.",
+ "dependencies": {
+ "component-emitter": "^1.2.0",
+ "cookiejar": "^2.1.0",
+ "debug": "^3.1.0",
+ "extend": "^3.0.0",
+ "form-data": "^2.3.1",
+ "formidable": "^1.2.0",
+ "methods": "^1.1.1",
+ "mime": "^1.4.1",
+ "qs": "^6.5.1",
+ "readable-stream": "^2.3.5"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/superagent/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/superagent/node_modules/form-data": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
+ "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/superagent/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-hyperlinks": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz",
+ "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
+ "node_modules/symlink-or-copy": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz",
+ "integrity": "sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==",
+ "dev": true
+ },
+ "node_modules/table": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.7.2.tgz",
+ "integrity": "sha512-UFZK67uvyNivLeQbVtkiUs8Uuuxv24aSL4/Vil2PJVtMgU8Lx0CYkP12uCGa3kjyQzOSgV1+z9Wkb82fCGsO0g==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^8.0.1",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ajv": {
+ "version": "8.6.3",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz",
+ "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/table/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/table/node_modules/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==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/table/node_modules/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==",
+ "dev": true
+ },
+ "node_modules/table/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/table/node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/table/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tar-stream/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/tarn": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz",
+ "integrity": "sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw==",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/terminal-link": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
+ "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-escapes": "^4.2.1",
+ "supports-hyperlinks": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/terminal-link/node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/terminal-link/node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+ "dev": true
+ },
+ "node_modules/throat": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==",
+ "dev": true
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "node_modules/through2": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz",
+ "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "3"
+ }
+ },
+ "node_modules/through2-filter": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
+ "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
+ "dev": true,
+ "dependencies": {
+ "through2": "~2.0.0",
+ "xtend": "~4.0.0"
+ }
+ },
+ "node_modules/through2-filter/node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/through2/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/tildify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
+ "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/titleize": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/titleize/-/titleize-2.1.0.tgz",
+ "integrity": "sha512-m+apkYlfiQTKLW+sI4vqUkwMEzfgEUEYSqljx1voUE3Wz/z1ZsxyzSxvH2X8uKVrOp7QkByWt0rA6+gvhCKy6g==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tlds": {
+ "version": "1.224.0",
+ "resolved": "https://registry.npmjs.org/tlds/-/tlds-1.224.0.tgz",
+ "integrity": "sha512-Jgdc8SEijbDFUsmCn6Wk/f7E6jBLFZOG3U1xK0amGSfEH55Xx97ItUS/d2NngsuApjn11UeWCWj8Um3VRhseZQ==",
+ "bin": {
+ "tlds": "bin.js"
+ }
+ },
+ "node_modules/tmpl": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+ "dev": true
+ },
+ "node_modules/to-absolute-glob": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
+ "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
+ "dev": true,
+ "dependencies": {
+ "is-absolute": "^1.0.0",
+ "is-negated-glob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-object-path/node_modules/kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "dependencies": {
+ "is-buffer": "^1.1.5"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-readable-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "dependencies": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/to-through": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
+ "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
+ "dev": true,
+ "dependencies": {
+ "through2": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/to-through/node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/token-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-1.0.0.tgz",
+ "integrity": "sha1-zCAOqyYT9BZtJ/+a/HylbUnfbrQ="
+ },
+ "node_modules/touch": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
+ "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
+ "dev": true,
+ "dependencies": {
+ "nopt": "~1.0.10"
+ },
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/tough-cookie": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
+ "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.1.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tough-cookie/node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tough-cookie/node_modules/universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
+ },
+ "node_modules/tslib": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
+ "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ },
+ "node_modules/type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "dependencies": {
+ "prelude-ls": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ },
+ "node_modules/typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
+ "dependencies": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
+ "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/ua-parser-js": {
+ "version": "0.7.30",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.30.tgz",
+ "integrity": "sha512-uXEtSresNUlXQ1QL4/3dQORcGv7+J2ookOG2ybA/ga9+HYEXueT2o+8dUJQkpedsyTyCJ6jCCirRcKtdtx1kbg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ua-parser-js"
+ },
+ {
+ "type": "paypal",
+ "url": "https://paypal.me/faisalman"
+ }
+ ],
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/uc.micro": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
+ "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has-bigints": "^1.0.1",
+ "has-symbols": "^1.0.2",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/unbzip2-stream": {
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
+ "dependencies": {
+ "buffer": "^5.2.1",
+ "through": "^2.3.8"
+ }
+ },
+ "node_modules/unbzip2-stream/node_modules/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
+ "node_modules/underscore": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz",
+ "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g=="
+ },
+ "node_modules/underscore.deep": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/underscore.deep/-/underscore.deep-0.5.1.tgz",
+ "integrity": "sha1-ByZx9I1oc1w0Ij/P72PmnlJ2zCs=",
+ "engines": {
+ "node": ">=0.10.x"
+ },
+ "peerDependencies": {
+ "underscore": "1.x"
+ }
+ },
+ "node_modules/underscore.string": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
+ "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "^1.0.3",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "dependencies": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/union-value/node_modules/set-value": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
+ "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/jonschlinkert",
+ "https://paypal.me/jonathanschlinkert",
+ "https://jonschlinkert.dev/sponsor"
+ ],
+ "dependencies": {
+ "is-plain-object": "^2.0.4",
+ "is-primitive": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=11.0"
+ }
+ },
+ "node_modules/unique-stream": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
+ "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
+ "dev": true,
+ "dependencies": {
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "through2-filter": "^3.0.0"
+ }
+ },
+ "node_modules/unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "dev": true,
+ "dependencies": {
+ "crypto-random-string": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+ "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "dependencies": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-value/node_modules/isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "dependencies": {
+ "isarray": "1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/unset-value/node_modules/has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/update-notifier": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz",
+ "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==",
+ "dev": true,
+ "dependencies": {
+ "boxen": "^5.0.0",
+ "chalk": "^4.1.0",
+ "configstore": "^5.0.1",
+ "has-yarn": "^2.1.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^2.0.0",
+ "is-installed-globally": "^0.4.0",
+ "is-npm": "^5.0.0",
+ "is-yarn-global": "^0.3.0",
+ "latest-version": "^5.1.0",
+ "pupa": "^2.1.1",
+ "semver": "^7.3.4",
+ "semver-diff": "^3.1.1",
+ "xdg-basedir": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/update-notifier?sponsor=1"
+ }
+ },
+ "node_modules/update-notifier/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/update-notifier/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/update-notifier/node_modules/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==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/update-notifier/node_modules/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==",
+ "dev": true
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/uri-js/node_modules/punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "deprecated": "Please see https://github.com/lydell/urix#deprecated",
+ "dev": true
+ },
+ "node_modules/url": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+ "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=",
+ "dependencies": {
+ "punycode": "1.3.2",
+ "querystring": "0.2.0"
+ }
+ },
+ "node_modules/url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+ "dev": true,
+ "dependencies": {
+ "prepend-http": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ },
+ "node_modules/util.promisify": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.1.1.tgz",
+ "integrity": "sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "for-each": "^0.3.3",
+ "has-symbols": "^1.0.1",
+ "object.getownpropertydescriptors": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/v8-compile-cache": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+ "dev": true
+ },
+ "node_modules/v8-to-istanbul": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
+ "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==",
+ "dev": true,
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "^2.0.1",
+ "convert-source-map": "^1.6.0",
+ "source-map": "^0.7.3"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/v8-to-istanbul/node_modules/source-map": {
+ "version": "0.7.3",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+ "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/valid-data-url": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-3.0.1.tgz",
+ "integrity": "sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dev": true,
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "node_modules/value-or-function": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
+ "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/verror/node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ },
+ "node_modules/vinyl": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
+ "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.1",
+ "clone-buffer": "^1.0.0",
+ "clone-stats": "^1.0.0",
+ "cloneable-readable": "^1.0.0",
+ "remove-trailing-separator": "^1.0.1",
+ "replace-ext": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-fs": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
+ "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
+ "dev": true,
+ "dependencies": {
+ "fs-mkdirp-stream": "^1.0.0",
+ "glob-stream": "^6.1.0",
+ "graceful-fs": "^4.0.0",
+ "is-valid-glob": "^1.0.0",
+ "lazystream": "^1.0.0",
+ "lead": "^1.0.0",
+ "object.assign": "^4.0.4",
+ "pumpify": "^1.3.5",
+ "readable-stream": "^2.3.3",
+ "remove-bom-buffer": "^3.0.0",
+ "remove-bom-stream": "^1.2.0",
+ "resolve-options": "^1.1.0",
+ "through2": "^2.0.0",
+ "to-through": "^2.0.0",
+ "value-or-function": "^3.0.0",
+ "vinyl": "^2.0.0",
+ "vinyl-sourcemap": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-fs/node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/vinyl-sourcemap": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
+ "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
+ "dev": true,
+ "dependencies": {
+ "append-buffer": "^1.0.2",
+ "convert-source-map": "^1.5.0",
+ "graceful-fs": "^4.1.6",
+ "normalize-path": "^2.1.1",
+ "now-and-later": "^2.0.0",
+ "remove-bom-buffer": "^3.0.0",
+ "vinyl": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-sourcemap/node_modules/normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "dependencies": {
+ "remove-trailing-separator": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/void-elements": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
+ "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vue-template-compiler": {
+ "version": "2.6.14",
+ "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz",
+ "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==",
+ "dev": true,
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.1.0"
+ }
+ },
+ "node_modules/w3c-hr-time": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
+ "dependencies": {
+ "browser-process-hrtime": "^1.0.0"
+ }
+ },
+ "node_modules/w3c-xmlserializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
+ "dependencies": {
+ "xml-name-validator": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/wait-on": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz",
+ "integrity": "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw==",
+ "dev": true,
+ "dependencies": {
+ "axios": "^0.21.1",
+ "joi": "^17.4.0",
+ "lodash": "^4.17.21",
+ "minimist": "^1.2.5",
+ "rxjs": "^7.1.0"
+ },
+ "bin": {
+ "wait-on": "bin/wait-on"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/wait-on/node_modules/rxjs": {
+ "version": "7.4.0",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz",
+ "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "~2.1.0"
+ }
+ },
+ "node_modules/wait-on/node_modules/tslib": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
+ "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
+ "dev": true
+ },
+ "node_modules/walk-sync": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz",
+ "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==",
+ "dev": true,
+ "dependencies": {
+ "@types/minimatch": "^3.0.3",
+ "ensure-posix-path": "^1.1.0",
+ "matcher-collection": "^2.0.0",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": "8.* || >= 10.*"
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "dev": true,
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
+ },
+ "node_modules/web-resource-inliner": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-5.0.0.tgz",
+ "integrity": "sha512-AIihwH+ZmdHfkJm7BjSXiEClVt4zUFqX4YlFAzjL13wLtDuUneSaFvDBTbdYRecs35SiU7iNKbMnN+++wVfb6A==",
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "escape-goat": "^3.0.0",
+ "htmlparser2": "^4.0.0",
+ "mime": "^2.4.6",
+ "node-fetch": "^2.6.0",
+ "valid-data-url": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/web-resource-inliner/node_modules/mime": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
+ "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
+ },
+ "node_modules/whatwg-encoding": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
+ "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
+ "dependencies": {
+ "iconv-lite": "0.4.24"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
+ "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "node_modules/widest-line": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+ "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/with": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/with/-/with-7.0.2.tgz",
+ "integrity": "sha512-RNGKj82nUPg3g5ygxkQl0R937xLyho1J24ItRCBTr/m1YnZkzJy1hUiHUJrc/VlsDQzsCnInEGSg3bci0Lmd4w==",
+ "dependencies": {
+ "@babel/parser": "^7.9.6",
+ "@babel/types": "^7.9.6",
+ "assert-never": "^1.2.1",
+ "babel-walk": "3.0.0-canary-5"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/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==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/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==",
+ "dev": true
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "node_modules/write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "dev": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "node_modules/ws": {
+ "version": "7.5.5",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
+ "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xdg-basedir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/xlsx-populate": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz",
+ "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==",
+ "dependencies": {
+ "cfb": "^1.1.3",
+ "jszip": "^3.2.2",
+ "lodash": "^4.17.15",
+ "sax": "^1.2.4"
+ }
+ },
+ "node_modules/xlsx-populate/node_modules/sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ },
+ "node_modules/xml-name-validator": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
+ "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ },
+ "node_modules/xml2js": {
+ "version": "0.4.19",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
+ "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~9.0.1"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "9.0.7",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
+ "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
+ "node_modules/xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "engines": {
+ "node": ">=0.4"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dependencies": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ }
+ },
"dependencies": {
"@babel/code-frame": {
"version": "7.15.8",
@@ -530,6 +16053,43 @@
}
}
},
+ "@faker-js/faker": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-6.3.1.tgz",
+ "integrity": "sha512-8YXBE2ZcU/pImVOHX7MWrSR/X5up7t6rPWZlk34RwZEcdr3ua6X+32pSd6XuOQRN+vbuvYNfA6iey8NbrjuMFQ==",
+ "dev": true
+ },
+ "@googlemaps/google-maps-services-js": {
+ "version": "3.3.14",
+ "resolved": "https://registry.npmjs.org/@googlemaps/google-maps-services-js/-/google-maps-services-js-3.3.14.tgz",
+ "integrity": "sha512-R7d/5anYSr0yeTBOjDuNmdAPLh18aajjmdrwIl933vpIis6DzOIclLDpHp7qe+v0V8GzbSzs8mPYJJTZX0Rv7Q==",
+ "requires": {
+ "@googlemaps/url-signature": "^1.0.4",
+ "agentkeepalive": "^4.1.0",
+ "axios": "^0.27.0",
+ "query-string": "^7.0.1",
+ "retry-axios": "^2.2.1"
+ },
+ "dependencies": {
+ "axios": {
+ "version": "0.27.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
+ "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
+ "requires": {
+ "follow-redirects": "^1.14.9",
+ "form-data": "^4.0.0"
+ }
+ }
+ }
+ },
+ "@googlemaps/url-signature": {
+ "version": "1.0.23",
+ "resolved": "https://registry.npmjs.org/@googlemaps/url-signature/-/url-signature-1.0.23.tgz",
+ "integrity": "sha512-gU3Cy3SlkWeFIsU/cyW9nmW6ZeL8zst+UTWybN723g4mihhpJgpUGiXl7nB8F3/LS5/vmAdAZg9THp9a8A/eRQ==",
+ "requires": {
+ "crypto-js": "^4.1.1"
+ }
+ },
"@hapi/boom": {
"version": "9.1.4",
"resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz",
@@ -1421,7 +16981,8 @@
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"acorn-walk": {
"version": "7.2.0",
@@ -1471,6 +17032,31 @@
}
}
},
+ "agentkeepalive": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
+ "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
+ "requires": {
+ "debug": "^4.1.0",
+ "depd": "^1.1.2",
+ "humanize-ms": "^1.2.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ }
+ }
+ },
"aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
@@ -1655,9 +17241,9 @@
"dev": true
},
"async": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
- "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
+ "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
},
"async-file": {
"version": "2.0.2",
@@ -2305,8 +17891,7 @@
},
"dependencies": {
"set-value": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
+ "version": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
"integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==",
"dev": true,
"requires": {
@@ -2361,9 +17946,9 @@
"dev": true
},
"caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA==",
+ "version": "1.0.30001339",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001339.tgz",
+ "integrity": "sha512-Es8PiVqCe+uXdms0Gu5xP5PF2bxLR7OBp3wUzUnuO7OHzhOfCyg3hdiGWVPVxhiuniOzng+hTc1u3fEQ0TlkSQ==",
"dev": true
},
"capture-exit": {
@@ -2544,8 +18129,7 @@
},
"dependencies": {
"glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"requires": {
@@ -2687,9 +18271,9 @@
"dev": true
},
"colorette": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
- "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw=="
+ "version": "2.0.16",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
+ "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
},
"colors": {
"version": "1.4.0",
@@ -2874,6 +18458,14 @@
"moment-timezone": "^0.5.31"
}
},
+ "cross-fetch": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
+ "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
+ "requires": {
+ "node-fetch": "2.6.7"
+ }
+ },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -3044,8 +18636,7 @@
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
- "dev": true
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
"decompress-response": {
"version": "3.3.0",
@@ -3173,9 +18764,9 @@
"dev": true
},
"devtools-protocol": {
- "version": "0.0.901419",
- "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz",
- "integrity": "sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ=="
+ "version": "0.0.960912",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.960912.tgz",
+ "integrity": "sha512-I3hWmV9rWHbdnUdmMKHF2NuYutIM2kXz2mdXW8ha7TbRlGTVs+PF+PsB5QWvpCek4Fy9B+msiispCfwlhG5Sqg=="
},
"dicer": {
"version": "0.2.5",
@@ -3659,8 +19250,7 @@
"dev": true
},
"glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"requires": {
@@ -3733,7 +19323,8 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-7.2.0.tgz",
"integrity": "sha512-rV4Qu0C3nfJKPOAhFujFxB7RMP+URFyQqqOZW9DMRD7ZDTFyjaIlETU3xzHELt++4ugC0+Jm084HQYkkJe+Ivg==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"eslint-scope": {
"version": "5.1.1",
@@ -4018,20 +19609,21 @@
}
},
"express-jwt": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-6.1.0.tgz",
- "integrity": "sha512-mmSR52Ps1FMeGwchroHzEJONWhsobd5KHVVKBffYiUEpZh9iK9wI9ZWkmzY5ROwWQtJLNGHV/VUMLh2M208s4Q==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-6.1.2.tgz",
+ "integrity": "sha512-l5dlf5lNM/1EODMsJGfHn1VnrhhsUYEetzrKFStJZLjFQXtR+HGdBiW+jUNZ+ISsFe+h7Wl/hQKjLrY2TX0Qkg==",
"requires": {
- "async": "^1.5.0",
+ "async": "^3.2.2",
"express-unless": "^1.0.0",
"jsonwebtoken": "^8.1.0",
- "lodash.set": "^4.0.0"
+ "lodash": "^4.17.21"
}
},
"express-jwt-authz": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/express-jwt-authz/-/express-jwt-authz-2.4.1.tgz",
- "integrity": "sha512-ruH86e2NvWicG9maStztyAyBJV0E8RsInXUm6Kuc/9pDtVJmJw3qigv1MEVs5bH+aksZuxocYZdz+N1V/9F+Dg=="
+ "integrity": "sha512-ruH86e2NvWicG9maStztyAyBJV0E8RsInXUm6Kuc/9pDtVJmJw3qigv1MEVs5bH+aksZuxocYZdz+N1V/9F+Dg==",
+ "requires": {}
},
"express-promise-router": {
"version": "4.1.0",
@@ -4078,15 +19670,6 @@
"requires": {
"is-plain-object": "^2.0.4"
}
- },
- "is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "requires": {
- "isobject": "^3.0.1"
- }
}
}
},
@@ -4186,12 +19769,6 @@
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
- "faker": {
- "version": "5.5.3",
- "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz",
- "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==",
- "dev": true
- },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4247,6 +19824,11 @@
"to-regex-range": "^5.0.1"
}
},
+ "filter-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
+ "integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
+ },
"finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -4297,9 +19879,9 @@
}
},
"follow-redirects": {
- "version": "1.14.7",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
- "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz",
+ "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ=="
},
"for-each": {
"version": "0.3.3",
@@ -4457,13 +20039,6 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
- "optional": true
- },
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
@@ -4616,22 +20191,12 @@
},
"dependencies": {
"glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "version": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"requires": {
"is-glob": "^4.0.3"
}
- },
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
}
}
},
@@ -5051,6 +20616,14 @@
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true
},
+ "humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+ "requires": {
+ "ms": "^2.0.0"
+ }
+ },
"i18n": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/i18n/-/i18n-0.13.3.tgz",
@@ -5485,7 +21058,8 @@
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
},
"is-extglob": {
"version": "2.1.1",
@@ -6411,7 +21985,8 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
"integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
- "dev": true
+ "dev": true,
+ "requires": {}
},
"jest-regex-util": {
"version": "26.0.0",
@@ -7287,11 +22862,11 @@
"dev": true
},
"knex": {
- "version": "0.95.11",
- "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.11.tgz",
- "integrity": "sha512-grDetD91O8VoQVCFqeWTgkzdq5406W6rggF/lK1hHuwzmjDs/0m9KxyncGdZbklTi7aUgHvw3+Cfy4x7FvpdaQ==",
+ "version": "0.95.15",
+ "resolved": "https://registry.npmjs.org/knex/-/knex-0.95.15.tgz",
+ "integrity": "sha512-Loq6WgHaWlmL2bfZGWPsy4l8xw4pOE+tmLGkPG0auBppxpI0UcK+GYCycJcqz9W54f2LiGewkCVLBm3Wq4ur/w==",
"requires": {
- "colorette": "1.2.1",
+ "colorette": "2.0.16",
"commander": "^7.1.0",
"debug": "4.3.2",
"escalade": "^3.1.1",
@@ -7633,12 +23208,6 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
- "colorette": {
- "version": "2.0.16",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
- "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
- "dev": true
- },
"log-update": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
@@ -7797,11 +23366,6 @@
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
},
- "lodash.set": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
- "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM="
- },
"lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -8083,9 +23647,9 @@
}
},
"minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
},
"mixin-deep": {
"version": "1.3.2",
@@ -8105,15 +23669,6 @@
"requires": {
"is-plain-object": "^2.0.4"
}
- },
- "is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "requires": {
- "isobject": "^3.0.1"
- }
}
}
},
@@ -8125,6 +23680,11 @@
"minimist": "^1.2.5"
}
},
+ "mkdirp-classic": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
+ },
"mktemp": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz",
@@ -8132,9 +23692,9 @@
"dev": true
},
"moment": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
- "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+ "version": "2.29.3",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
+ "integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
},
"moment-timezone": {
"version": "0.5.33",
@@ -8268,17 +23828,17 @@
}
},
"node-fetch": {
- "version": "2.6.5",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
- "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
"requires": {
"whatwg-url": "^5.0.0"
}
},
"node-forge": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz",
- "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w=="
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA=="
},
"node-int64": {
"version": "0.4.0",
@@ -8538,7 +24098,8 @@
"objection-soft-delete": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/objection-soft-delete/-/objection-soft-delete-1.0.7.tgz",
- "integrity": "sha512-YGGk48DdLiK2gkyXCY4ByItWad+UCHm2VzfsYg8AnD+zhVuCN7FJhjkT8XOwQvCGprqLYuFN7ij/ClLnghUKxA=="
+ "integrity": "sha512-YGGk48DdLiK2gkyXCY4ByItWad+UCHm2VzfsYg8AnD+zhVuCN7FJhjkT8XOwQvCGprqLYuFN7ij/ClLnghUKxA==",
+ "requires": {}
},
"on-finished": {
"version": "2.3.0",
@@ -8820,7 +24381,8 @@
"pg-pool": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.4.1.tgz",
- "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ=="
+ "integrity": "sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ==",
+ "requires": {}
},
"pg-protocol": {
"version": "1.5.0",
@@ -9014,9 +24576,9 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"progress": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz",
- "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg=="
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
},
"promise": {
"version": "7.3.1",
@@ -9258,28 +24820,28 @@
}
},
"puppeteer": {
- "version": "10.4.0",
- "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-10.4.0.tgz",
- "integrity": "sha512-2cP8mBoqnu5gzAVpbZ0fRaobBWZM8GEUF4I1F6WbgHrKV/rz7SX8PG2wMymZgD0wo0UBlg2FBPNxlF/xlqW6+w==",
+ "version": "13.3.1",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-13.3.1.tgz",
+ "integrity": "sha512-nYTR+LP1amGs5BALSoGLbw+QxQZS//7HsKKSrxaMAIic0AE3iIr10E7gcZEsP/4JcxBfgNyT3SPUyEOS6Wb0fQ==",
"requires": {
- "debug": "4.3.1",
- "devtools-protocol": "0.0.901419",
+ "cross-fetch": "3.1.5",
+ "debug": "4.3.3",
+ "devtools-protocol": "0.0.960912",
"extract-zip": "2.0.1",
"https-proxy-agent": "5.0.0",
- "node-fetch": "2.6.1",
"pkg-dir": "4.2.0",
- "progress": "2.0.1",
+ "progress": "2.0.3",
"proxy-from-env": "1.1.0",
"rimraf": "3.0.2",
- "tar-fs": "2.0.0",
- "unbzip2-stream": "1.3.3",
- "ws": "7.4.6"
+ "tar-fs": "2.1.1",
+ "unbzip2-stream": "1.4.3",
+ "ws": "8.5.0"
},
"dependencies": {
"debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+ "version": "4.3.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
+ "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
"requires": {
"ms": "2.1.2"
}
@@ -9289,15 +24851,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
- "node-fetch": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
- "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
- },
"ws": {
- "version": "7.4.6",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
- "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A=="
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
+ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "requires": {}
}
}
},
@@ -9306,6 +24864,17 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
},
+ "query-string": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.1.tgz",
+ "integrity": "sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==",
+ "requires": {
+ "decode-uri-component": "^0.2.0",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ }
+ },
"querystring": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
@@ -9771,6 +25340,12 @@
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
},
+ "retry-axios": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-2.6.0.tgz",
+ "integrity": "sha512-pOLi+Gdll3JekwuFjXO3fTq+L9lzMQGcSq7M5gIjExcl3Gu1hd4XXuf5o3+LuSBsaULQH7DiNbsqPd1chVpQGQ==",
+ "requires": {}
+ },
"rimraf": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -10352,7 +25927,8 @@
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "devOptional": true
},
"source-map-resolve": {
"version": "0.5.3",
@@ -10424,6 +26000,11 @@
"through": "2"
}
},
+ "split-on-first": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
+ },
"split-string": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -10579,6 +26160,19 @@
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
+ "strict-uri-encode": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+ "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
"string-argv": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
@@ -10635,14 +26229,6 @@
"define-properties": "^1.1.3"
}
},
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "~5.1.0"
- }
- },
"stringify-object": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
@@ -10839,14 +26425,14 @@
}
},
"tar-fs": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
- "integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
+ "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
"requires": {
"chownr": "^1.1.1",
- "mkdirp": "^0.5.1",
+ "mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
- "tar-stream": "^2.0.0"
+ "tar-stream": "^2.1.4"
}
},
"tar-stream": {
@@ -11209,9 +26795,9 @@
}
},
"unbzip2-stream": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz",
- "integrity": "sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg==",
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
+ "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
"requires": {
"buffer": "^5.2.1",
"through": "^2.3.8"
@@ -11248,7 +26834,8 @@
"underscore.deep": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/underscore.deep/-/underscore.deep-0.5.1.tgz",
- "integrity": "sha1-ByZx9I1oc1w0Ij/P72PmnlJ2zCs="
+ "integrity": "sha1-ByZx9I1oc1w0Ij/P72PmnlJ2zCs=",
+ "requires": {}
},
"underscore.string": {
"version": "3.3.5",
@@ -11272,17 +26859,8 @@
"set-value": "^2.0.1"
},
"dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
"set-value": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
+ "version": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
"integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==",
"dev": true,
"requires": {
@@ -11874,7 +27452,8 @@
"ws": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
- "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
+ "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
+ "requires": {}
},
"xdg-basedir": {
"version": "4.0.0",
diff --git a/packages/api/package.json b/packages/api/package.json
index 8927c55b03..304c7c4ed8 100644
--- a/packages/api/package.json
+++ b/packages/api/package.json
@@ -1,7 +1,7 @@
{
"name": "litefarm-api",
- "version": "3.1.1",
- "description": "backend for LiteFarm",
+ "version": "3.2.0",
+ "description": "LiteFarm API server",
"main": "./api/src/server.js",
"scripts": {
"test": "jest --runInBand",
@@ -14,7 +14,6 @@
"debug-email-template": "set NODE_ENV=development&& DEBUG=email-templates nodemon src/server.js",
"debug-i18n": "set NODE_ENV=development&& DEBUG=i18n:* nodemon src/server.js",
"production": "NODE_ENV=production node src/server.js",
- "preinstall": "npx npm-force-resolutions",
"integration": "NODE_ENV=integration node src/server.js",
"migrate:testing:db": "NODE_ENV=test knex migrate:latest --env=test",
"migrate:dev:db": "knex migrate:latest",
@@ -24,9 +23,6 @@
"migrate:testing:seed": "knex seed:run --env=test",
"migrate:rollback:testing:db": "NODE_ENV=test knex migrate:rollback --env=test",
"lint": "eslint src",
- "gitlab-server": "NODE_ENV=ci node src/server.js",
- "ci": "start-server-and-test gitlab-server 5000 test-end2end",
- "e2e": "start-server-and-test start 5000 test-end2end",
"i18n-scheduler": "npx i18next 'src/jobs/certification/**/*.js' -c 'src/jobs/locales/i18next-parser.config.js'",
"scheduler": "cp ../webapp/public/locales/en/crop.json src/jobs/locales/en && cp ../webapp/public/locales/es/crop.json src/jobs/locales/es && cp ../webapp/public/locales/pt/crop.json src/jobs/locales/pt && cp ../webapp/public/locales/fr/crop.json src/jobs/locales/fr && node src/jobs/index.js",
"fix-lint": "eslint src --fix",
@@ -40,15 +36,11 @@
},
"collectCoverageFrom": [
"src/**/*.{js,jsx,mjs}"
- ]
- },
- "author": "LiteFarm",
- "license": "ISC",
- "repository": {
- "type": "git",
- "url": "https://github.com/juice-tn/LiteFarm.git"
+ ],
+ "globalSetup": "./jest-global-setup.js"
},
"dependencies": {
+ "@googlemaps/google-maps-services-js": "^3.3.14",
"adm-zip": "^0.4.16",
"async-file": "^2.0.2",
"aws-sdk": "^2.931.0",
@@ -76,7 +68,7 @@
"json-2-csv": "^3.14.4",
"jsonwebtoken": "^8.5.1",
"jwks-rsa": "^1.12.1",
- "knex": "^0.95.11",
+ "knex": "^0.95.15",
"lodash": "^4.17.20",
"multer": "^1.4.2",
"node-schedule": "^1.3.2",
@@ -85,7 +77,7 @@
"objection-soft-delete": "^1.0.7",
"pg": "^8.5.1",
"pug": "^3.0.2",
- "puppeteer": "^10.1.0",
+ "puppeteer": "^13.3.1",
"request": "^2.87.0",
"request-promise": "^4.2.2",
"rimraf": "^3.0.2",
@@ -99,9 +91,9 @@
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.12.1",
"@babel/plugin-proposal-optional-chaining": "^7.13.8",
+ "@faker-js/faker": "^6.3.1",
"eslint": "^7.18.0",
"eslint-config-prettier": "^7.0.0",
- "faker": "^5.1.0",
"i18next-parser": "^5.3.0",
"jest": "^26.4.2",
"lint-staged": "^10.5.3",
@@ -109,14 +101,10 @@
"prettier": "2.2.1",
"start-server-and-test": "^1.11.7"
},
- "resolutions": {
- "set-value": "^4.1.0",
- "glob-parent": "^6.0.2"
- },
"lint-staged": {
- "*.{js}": [
+ "*.{js,css,md}": "prettier --write",
+ "*.js": [
"eslint --quiet --fix"
- ],
- "*.{js,css,md}": "prettier --write"
+ ]
}
-}
\ No newline at end of file
+}
diff --git a/packages/api/prod.Dockerfile b/packages/api/prod.Dockerfile
index 52b6cd56e0..35b98a7305 100644
--- a/packages/api/prod.Dockerfile
+++ b/packages/api/prod.Dockerfile
@@ -1,4 +1,4 @@
-FROM node:14.16.0
+FROM node:16.13.2
WORKDIR /usr/src/app
diff --git a/packages/api/researchAPI_README.md b/packages/api/researchAPI_README.md
deleted file mode 100644
index a9acde9947..0000000000
--- a/packages/api/researchAPI_README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Research API
-
-### Endpoint
-##### Integration
-`https://litefarm-api-integration.herokuapp.com/stats/farm`
-##### Production
-`https://litefarm-api-production.herokuapp.com/stats/farm`
-
-### List of queriy parameters
-All parameters are in boolean except farm_id and token
-Order does not matter
-
- - farm_id `required` `string`
- - token `required` `string`
- - all
- - users
- - fields
- - field_crops
- - shifts
- - logs
- - expenses
- - sales
- - people_fed
- - soil_om
- - labour_happiness
- - biodiversity
- - waterbalance
- - nitrogenbalance
-
- ### Examples
-
- - Get users data
- `https://app.litefarm.org/stats/farm?farm_id=xxxxxxxxxxxxx&token=xxxxxxxxxxxxx&users=true`
- - Get users and labour_happiness
- `https://app.litefarm.org/stats/farm?farm_id=xxxxxxxxxxxxx&token=xxxxxxxxxxxxx&users=true&labour_happiness=true`
diff --git a/packages/api/src/controllers/documentController.js b/packages/api/src/controllers/documentController.js
index 267e69d9a8..cccfb21940 100644
--- a/packages/api/src/controllers/documentController.js
+++ b/packages/api/src/controllers/documentController.js
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
const DocumentModel = require('../models/documentModel');
const { v4: uuidv4 } = require('uuid');
const {
@@ -13,8 +28,13 @@ const documentController = {
return async (req, res, next) => {
const { farm_id } = req.params;
try {
- const result = await DocumentModel.query().whereNotDeleted().withGraphFetched('[files]').where({ farm_id });
- return result?.length ? res.status(200).send(result) : res.status(404).send('No documents found');
+ const result = await DocumentModel.query()
+ .whereNotDeleted()
+ .withGraphFetched('[files]')
+ .where({ farm_id });
+ return result?.length
+ ? res.status(200).send(result)
+ : res.status(404).send('No documents found');
} catch (error) {
console.error(error);
return res.status(400).json({ error });
@@ -24,9 +44,10 @@ const documentController = {
createDocument() {
return async (req, res, next) => {
try {
- const result = await DocumentModel.transaction(async trx => {
- return await DocumentModel.query(trx).context({ user_id: req.user.user_id }).upsertGraph(
- req.body, { noUpdate: true, noDelete: true });
+ const result = await DocumentModel.transaction(async (trx) => {
+ return await DocumentModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph(req.body, { noUpdate: true, noDelete: true });
});
return res.status(201).send(result);
} catch (error) {
@@ -38,11 +59,14 @@ const documentController = {
};
},
- archiveDocument() {
+ patchDocumentArchive() {
return async (req, res, next) => {
const { document_id } = req.params;
try {
- const result = await DocumentModel.query().context(req.user).findById(document_id).patch({ valid_until: new Date('2000/1/1').toISOString() });
+ const result = await DocumentModel.query()
+ .context(req.user)
+ .findById(document_id)
+ .patch({ archived: req.body.archived });
return result ? res.sendStatus(200) : res.status(404).send('Document not found');
} catch (error) {
return res.status(400).json({ error });
@@ -54,16 +78,16 @@ const documentController = {
return async (req, res, next) => {
try {
const { document_id } = req.params;
- const result = await DocumentModel.transaction(async trx => {
- return await DocumentModel.query(trx).context({ user_id: req.user.user_id }).upsertGraph(
- {document_id: document_id, ...req.body}
- );
+ const result = await DocumentModel.transaction(async (trx) => {
+ return await DocumentModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph({ document_id, ...req.body });
});
return res.status(201).send(result);
} catch (err) {
console.log(err);
return res.status(400).json({
- error,
+ error: err,
});
}
};
@@ -77,12 +101,14 @@ const documentController = {
const fileName = `${farm_id}/document/${getRandomFileName(req.file)}`;
- const uploadOriginalDocumentPromise = s3.putObject({
- Body: req.file.buffer,
- Bucket: s3BucketName,
- Key: fileName,
- ACL: 'private',
- }).promise();
+ const uploadOriginalDocumentPromise = s3
+ .putObject({
+ Body: req.file.buffer,
+ Bucket: s3BucketName,
+ Key: fileName,
+ ACL: 'private',
+ })
+ .promise();
if (req.isMinimized) {
await uploadOriginalDocumentPromise;
@@ -104,17 +130,21 @@ const documentController = {
type: THUMBNAIL_FORMAT,
});
- const [thumbnail] = await Promise.all([imaginaryThumbnailPromise, uploadOriginalDocumentPromise]);
+ const [thumbnail] = await Promise.all([
+ imaginaryThumbnailPromise,
+ uploadOriginalDocumentPromise,
+ ]);
const thumbnailName = `${farm_id}/thumbnail/${uuidv4()}.${THUMBNAIL_FORMAT}`;
- await s3.putObject({
- Body: thumbnail.data,
- Bucket: getPrivateS3BucketName(),
- Key: thumbnailName,
- ACL: 'private',
- }).promise();
-
+ await s3
+ .putObject({
+ Body: thumbnail.data,
+ Bucket: getPrivateS3BucketName(),
+ Key: thumbnailName,
+ ACL: 'private',
+ })
+ .promise();
return res.status(201).json({
url: `${getPrivateS3Url()}/${fileName}`,
diff --git a/packages/api/src/controllers/farmController.js b/packages/api/src/controllers/farmController.js
index 3f595e628d..a8f1f77121 100644
--- a/packages/api/src/controllers/farmController.js
+++ b/packages/api/src/controllers/farmController.js
@@ -19,13 +19,14 @@ const userModel = require('../models/userModel');
const userFarmModel = require('../models/userFarmModel');
const { transaction, Model } = require('objection');
const knex = Model.knex();
+const { Client } = require('@googlemaps/google-maps-services-js');
+const client = new Client({});
const farmController = {
addFarm() {
return async (req, res) => {
const trx = await transaction.start(Model.knex());
try {
-
const { country } = req.body;
if (!country) {
await trx.rollback();
@@ -38,14 +39,16 @@ const farmController = {
return res.status(400).send('No unit info for given country');
}
+ const utc_offset = await this.getUTCOffsetFromGridPoints(req.body.grid_points);
+
const infoBody = {
farm_name: req.body.farm_name,
address: req.body.address,
grid_points: req.body.grid_points,
units,
country_id: id,
- }
- const user_id = req.user.user_id;
+ utc_offset,
+ };
const result = await baseController.postWithResponse(farmModel, infoBody, req, { trx });
// update user with new farm
const new_user = await farmController.getUser(req, trx);
@@ -82,7 +85,6 @@ const farmController = {
getFarmByID() {
return async (req, res) => {
try {
-
const id = req.params.farm_id;
const row = await baseController.getIndividual(farmModel, id);
if (!row.length) {
@@ -99,6 +101,23 @@ const farmController = {
};
},
+ async getFarmsByOffsetRange(req, res) {
+ try {
+ const [min, max] = [req.params.min, req.params.max];
+ const farms = await farmModel
+ .query()
+ .select('farm_id')
+ .where('utc_offset', '>=', min)
+ .where('utc_offset', '<=', max);
+
+ res.status(200).send(farms.map((farm) => farm['farm_id']));
+ } catch (error) {
+ res.status(400).json({
+ error,
+ });
+ }
+ },
+
deleteFarm() {
return async (req, res) => {
const trx = await transaction.start(Model.knex());
@@ -126,13 +145,16 @@ const farmController = {
if ((!!req.body.address || !!req.body.grid_points) && !mainPatch) {
throw new Error('Not allowed to modify address or gridPoints');
} else if (req.body.country) {
- const { id, ...units } = await this.getCountry(req.body.country)
+ const { id, ...units } = await this.getCountry(req.body.country);
+ const utc_offset = await this.getUTCOffsetFromGridPoints(req.body.grid_points);
req.body.units = units;
req.body.country_id = id;
+ req.body.utc_offset = utc_offset;
delete req.body.country;
}
- const user_id = req.user.user_id;
- const updated = await baseController.put(farmModel, req.params.farm_id, req.body, req, { trx });
+ const updated = await baseController.put(farmModel, req.params.farm_id, req.body, req, {
+ trx,
+ });
await trx.commit();
if (!updated.length) {
@@ -140,14 +162,13 @@ const farmController = {
} else {
res.status(200).send(updated);
}
-
} catch (error) {
await trx.rollback();
res.status(400).json({
error: error.message ? error.message : error,
});
}
- }
+ };
},
patchDefaultInitialLocation() {
@@ -155,7 +176,12 @@ const farmController = {
try {
const { default_initial_location_id } = req.body;
const user_id = req.user.user_id;
- const updated = await farmModel.query().context({ user_id }).findById(req.params.farm_id).patch({ default_initial_location_id }).returning('*');
+ const updated = await farmModel
+ .query()
+ .context({ user_id })
+ .findById(req.params.farm_id)
+ .patch({ default_initial_location_id })
+ .returning('*');
if (!updated) {
return res.sendStatus(404);
} else {
@@ -175,7 +201,12 @@ const farmController = {
try {
const { owner_operated } = req.body;
const user_id = req.user.user_id;
- const updated = await farmModel.query(trx).context({ user_id }).where({ farm_id: req.params.farm_id }).patch({ owner_operated }).returning('*');
+ const updated = await farmModel
+ .query(trx)
+ .context({ user_id })
+ .where({ farm_id: req.params.farm_id })
+ .patch({ owner_operated })
+ .returning('*');
await trx.commit();
if (!updated) {
res.sendStatus(404);
@@ -188,13 +219,12 @@ const farmController = {
error: e.message ? e.message : e,
});
}
- }
+ };
},
async getUser(req, trx) {
// check if a user is making this call
if (req.user) {
-
const uid = req.user.user_id;
return await userModel.query(trx).where(userModel.idColumn, uid).returning('*');
@@ -202,18 +232,64 @@ const farmController = {
},
async insertUserFarm(user, farm_id, trx) {
- return userFarmModel.query(trx).insert({
- user_id: user.user_id,
- farm_id,
- role_id: 1,
- status: 'Active',
- }).returning('*');
+ return userFarmModel
+ .query(trx)
+ .insert({
+ user_id: user.user_id,
+ farm_id,
+ role_id: 1,
+ status: 'Active',
+ })
+ .returning('*');
},
async getCountry(country) {
- const { iso, unit, id } = await knex('countries').select('*').where('country_name', country).first();
+ const { iso, unit, id } = await knex('countries')
+ .select('*')
+ .where('country_name', country)
+ .first();
return { currency: iso, measurement: unit.toLowerCase(), id };
},
-}
+
+ async getUTCOffsetFromGridPoints(gridPoints) {
+ try {
+ const timeZone = await client.timezone({
+ params: {
+ location: gridPoints,
+ timestamp: new Date(Date.now()),
+ key: process.env.GOOGLE_API_KEY,
+ },
+ });
+ return timeZone.data.rawOffset;
+ } catch (e) {
+ switch (e.response?.data?.status) {
+ case 'OVER_QUERY_LIMIT':
+ console.log('Hit query limit for timezones API: waiting for query limit to reset');
+ await new Promise((resolve) => setTimeout(resolve, 60000)); // Rate limit is on a per-minute basis
+ try {
+ const timeZone = await client.timezone({
+ params: {
+ location: gridPoints,
+ timestamp: new Date(Date.now()),
+ key: process.env.GOOGLE_API_KEY,
+ },
+ });
+ return timeZone.data.rawOffset;
+ } catch (e) {
+ console.log(e);
+ }
+ break;
+ case 'OVER_DAILY_LIMIT':
+ console.log(
+ 'Over the daily limit fot the timezones API. Please double check credentials are valid and try again tomorrow',
+ );
+ throw new Error('OVER_DAILY_LIMIT');
+ default:
+ console.log(`Unable to set a timezone for the farm`);
+ break;
+ }
+ }
+ },
+};
module.exports = farmController;
diff --git a/packages/api/src/controllers/insightController.js b/packages/api/src/controllers/insightController.js
index b854503873..c4d4a2c739 100644
--- a/packages/api/src/controllers/insightController.js
+++ b/packages/api/src/controllers/insightController.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (insightController.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,7 +13,6 @@
* GNU General Public License for more details, see .
*/
-
const { transaction, Model } = require('objection');
const waterBalanceModel = require('../models/waterBalanceModel');
const nitrogenScheduleModel = require('../models/nitrogenScheduleModel');
@@ -24,19 +23,22 @@ const waterBalanceScheduler = require('../jobs/waterBalance/waterBalance');
// TODO: put nitrogen scheduler here for when we want to put it back
const insightController = {
-
// this is for the People Fed module
getPeopleFedData() {
return async (req, res) => {
try {
const farmID = req.params.farm_id;
const saleData = await knex.raw(
- `SELECT DISTINCT cs.sale_id as id, cs.quantity_kg, c.percentrefuse, c.crop_common_name, c.energy, c.protein, c.lipid, c.vitc, c.vita_rae
+ `SELECT DISTINCT cs.sale_id as id, cs.quantity_kg, c.percentrefuse, c.crop_common_name, c.energy, c.protein,
+ c.lipid, c.vitc, c.vita_rae
FROM "cropSale" cs JOIN "sale" s ON cs.sale_id = s.sale_id
JOIN "crop" c ON cs.crop_id = c.crop_id
- WHERE s.farm_id = ? AND s.deleted = FALSE`, [farmID]);
+ WHERE s.farm_id = ? AND s.deleted = FALSE`,
+ [farmID],
+ );
const harvestData = await knex.raw(
- `SELECT DISTINCT hu.harvest_use_id as id, hu.quantity_kg, c.percentrefuse, c.crop_common_name, c.energy, c.protein, c.lipid, c.vitc, c.vita_rae
+ `SELECT DISTINCT hu.harvest_use_id as id, hu.quantity_kg, c.percentrefuse, c.crop_common_name, c.energy,
+ c.protein, c.lipid, c.vitc, c.vita_rae
FROM "harvestUse" hu
JOIN "task" al ON hu.task_id = al.task_id
JOIN "management_tasks" mt ON hu.task_id = mt.task_id
@@ -46,7 +48,9 @@ const insightController = {
JOIN "crop_variety" ON mp.crop_variety_id = crop_variety.crop_variety_id
JOIN "crop" c ON mp.crop_id = c.crop_id
WHERE location.farm_id = ? AND al.deleted = FALSE
- AND hu.harvest_use_type_id IN (2,5,6)`, [farmID]);
+ AND hu.harvest_use_type_id IN (2,5,6)`,
+ [farmID],
+ );
const data = saleData.rows.concat(harvestData.rows);
if (data) {
const people_fed_data = insightHelpers.getNutritionalData(data);
@@ -59,11 +63,13 @@ const insightController = {
} else {
res.status(200).send({
preview: 0,
- data: [{ label: 'Calories', val: 0, percentage: 0 },
+ data: [
+ { label: 'Calories', val: 0, percentage: 0 },
{ label: 'Protein', val: 0, percentage: 0 },
{ label: 'Fat', val: 0, percentage: 0 },
{ label: 'Vitamin C', val: 0, percentage: 0 },
- { label: 'Vitamin A', val: 0, percentage: 0 }],
+ { label: 'Vitamin A', val: 0, percentage: 0 },
+ ],
});
}
} catch (error) {
@@ -122,7 +128,9 @@ const insightController = {
AND r.location_id IS NULL
-- AND g.location_id IS NULL
GROUP BY l.location_id, l.name, area.grid_points
- ORDER BY l.name`, [farmID, farmID]);
+ ORDER BY l.name`,
+ [farmID, farmID],
+ );
const bufferZoneData = await knex.raw(
`SELECT DISTINCT
@@ -149,10 +157,12 @@ const insightController = {
WHERE l.farm_id = ?
AND l.deleted = false
GROUP BY l.location_id, l.name, line.line_points
- ORDER BY l.name`, [farmID, farmID]);
+ ORDER BY l.name`,
+ [farmID, farmID],
+ );
// buffer zones don't have grid_points, add line_points as grid_points to not break in helper function
- bufferZoneData.rows = bufferZoneData.rows.map(bufferZone => ({
+ bufferZoneData.rows = bufferZoneData.rows.map((bufferZone) => ({
...bufferZone,
grid_points: bufferZone.line_points,
}));
@@ -184,7 +194,27 @@ const insightController = {
AND t.task_type_id = tt.task_type_id
AND lt.location_id = l.location_id
AND l.farm_id = ?
- AND t.happiness is not null;`, [farmID]);
+ AND t.happiness is not null
+ UNION
+ SELECT t.task_id, t.happiness, t.duration, tt.task_translation_key
+ FROM "task" t, "plant_task" pt, "task_type" tt, "planting_management_plan" pmp, "location" l
+ WHERE t.task_id = pt.task_id
+ AND pt.planting_management_plan_id = pmp.planting_management_plan_id
+ AND t.task_type_id = tt.task_type_id
+ AND pmp.location_id = l.location_id
+ AND l.farm_id = ?
+ AND t.happiness is not null
+ UNION
+ SELECT t.task_id, t.happiness, t.duration, tt.task_translation_key
+ FROM "task" t, "transplant_task" tpt, "task_type" tt, "planting_management_plan" pmp, "location" l
+ WHERE t.task_id = tpt.task_id
+ AND tpt.planting_management_plan_id = pmp.planting_management_plan_id
+ AND t.task_type_id = tt.task_type_id
+ AND pmp.location_id = l.location_id
+ AND l.farm_id = ?
+ AND t.happiness is not null;`,
+ [farmID, farmID, farmID],
+ );
if (data.rows) {
const body = insightHelpers.getLabourHappiness(data.rows);
@@ -210,14 +240,18 @@ const insightController = {
JOIN "area" on figure.figure_id = area.figure_id
WHERE location.farm_id = ?
AND location.deleted = false
- GROUP BY area.grid_points`, [farmID]);
+ GROUP BY area.grid_points`,
+ [farmID],
+ );
const cropCount = await knex.raw(
`SELECT DISTINCT crop_variety.crop_variety_id
FROM "management_plan" mp
LEFT JOIN "crop_variety"
on mp.crop_variety_id = crop_variety.crop_variety_id
WHERE crop_variety.farm_id = ?
- and mp.start_date is not null`, [farmID]);
+ and mp.start_date is not null`,
+ [farmID],
+ );
if (dataPoints.rows && cropCount.rows) {
const count = cropCount.rows.length;
const body = await insightHelpers.getBiodiversityAPI(dataPoints.rows, count);
@@ -240,12 +274,20 @@ const insightController = {
const myLat = req.query.lat;
const myLong = req.query.long;
const startDate = req.query.startdate;
- const dataPoints = await insightController.queryCropSalesNearByStartDateAndFarmId(startDate, farmID);
+ const dataPoints = await insightController.queryCropSalesNearByStartDateAndFarmId(
+ startDate,
+ farmID,
+ );
if (dataPoints.rows) {
const filtered_datapoints = dataPoints.rows.filter((dataPoint) => {
const farm_location = dataPoint['grid_points'];
- const field_distance = insightHelpers.distance(farm_location['lat'], farm_location['lng'], parseFloat(myLat), parseFloat(myLong));
+ const field_distance = insightHelpers.distance(
+ farm_location['lat'],
+ farm_location['lng'],
+ parseFloat(myLat),
+ parseFloat(myLong),
+ );
return field_distance < distance;
});
const body = insightHelpers.formatPricesNearbyData(farmID, filtered_datapoints);
@@ -253,7 +295,6 @@ const insightController = {
} else {
res.status(200).send({});
}
-
} catch (error) {
console.log(error);
res.status(400).json({ error });
@@ -264,7 +305,8 @@ const insightController = {
async queryCropSalesNearByStartDateAndFarmId(startDate, farmID) {
return await knex.raw(
`
- SELECT to_char(date(s.sale_date), 'YYYY-MM') as year_month, c.crop_common_name, c.crop_translation_key, SUM(cvs.quantity) as sale_quant, SUM(cvs.sale_value) as sale_value, fa.farm_id, fa.grid_points
+ SELECT to_char(date(s.sale_date), 'YYYY-MM') as year_month, c.crop_common_name, c.crop_translation_key,
+ SUM(cvs.quantity) as sale_quant, SUM(cvs.sale_value) as sale_value, fa.farm_id, fa.grid_points
FROM "sale" s
JOIN "crop_variety_sale" cvs on cvs.sale_id = s.sale_id
JOIN "crop_variety" cv on cvs.crop_variety_id = cv.crop_variety_id
@@ -275,7 +317,9 @@ const insightController = {
FROM "crop_variety"
where crop_variety.farm_id = ?)
GROUP BY year_month, c.crop_common_name, c.crop_translation_key, fa.farm_id
- ORDER BY year_month, c.crop_common_name`, [startDate, farmID]);
+ ORDER BY year_month, c.crop_common_name`,
+ [startDate, farmID],
+ );
},
getWaterBalance() {
@@ -286,8 +330,13 @@ const insightController = {
const dataPoints = await knex.raw(
`SELECT c.crop_common_name, location.name, location.location_id, w.plant_available_water
FROM "management_plan" mp, "location", "waterBalance" w, "crop" c, "crop_variety"
- WHERE mp.location_id = location.location_id and location.farm_id = ? and c.crop_id = w.crop_id and w.location_id = location.location_id and
- mp.crop_variety_id = crop_variety.crop_variety_id and crop_variety.crop_id = w.crop_id and to_char(date(w.created_at), 'YYYY-MM-DD') = ?`, [farmID, prevDate]);
+ WHERE mp.location_id = location.location_id and location.farm_id = ?
+ AND c.crop_id = w.crop_id and w.location_id = location.location_id
+ AND mp.crop_variety_id = crop_variety.crop_variety_id
+ AND crop_variety.crop_id = w.crop_id
+ AND to_char(date(w.created_at), 'YYYY-MM-DD') = ?`,
+ [farmID, prevDate],
+ );
if (dataPoints.rows) {
const body = await insightHelpers.formatWaterBalanceData(dataPoints.rows);
res.status(200).send(body);
@@ -320,7 +369,9 @@ const insightController = {
const dataPoints = await knex.raw(
`SELECT *
FROM "waterBalanceSchedule" w
- WHERE w.farm_id = ?`, [farmID]);
+ WHERE w.farm_id = ?`,
+ [farmID],
+ );
if (dataPoints.rows.length > 0) {
const body = dataPoints.rows[0];
res.status(200).send(body);
@@ -341,8 +392,11 @@ const insightController = {
const dataPoints = await knex.raw(
`SELECT location.location_id, location.name, AVG(n.nitrogen_value) as nitrogen_value
FROM "location", "nitrogenBalance" n
- WHERE location.farm_id = ? and n.location_id = location.location_id and to_char(date(n.created_at), 'YYYY-MM-DD') >= ?
- GROUP BY location.location_id`, [farmID, prevDate]);
+ WHERE location.farm_id = ? and n.location_id = location.location_id
+ AND to_char(date(n.created_at), 'YYYY-MM-DD') >= ?
+ GROUP BY location.location_id`,
+ [farmID, prevDate],
+ );
if (dataPoints.rows.length > 0) {
const body = await insightHelpers.formatNitrogenBalanceData(dataPoints.rows);
res.status(200).send(body);
@@ -364,7 +418,8 @@ const insightController = {
`SELECT *
FROM "nitrogenSchedule" n
WHERE n.farm_id = ?
- ORDER BY n.scheduled_at DESC`, [farmID],
+ ORDER BY n.scheduled_at DESC`,
+ [farmID],
);
if (dataPoints.rows) {
const body = dataPoints.rows[0];
@@ -372,7 +427,6 @@ const insightController = {
} else {
res.status(404).json({ error: 'no data' });
}
-
} catch (error) {
res.status(400).json({ error });
}
@@ -385,7 +439,12 @@ const insightController = {
const body = req.body;
trx = await transaction.start(Model.knex());
try {
- const waterBalanceResult = await baseController.postWithResponse(waterBalanceModel, body, req, { trx });
+ const waterBalanceResult = await baseController.postWithResponse(
+ waterBalanceModel,
+ body,
+ req,
+ { trx },
+ );
await trx.commit();
res.status(201).send(waterBalanceResult);
} catch (error) {
@@ -401,7 +460,12 @@ const insightController = {
const body = req.body;
trx = await transaction.start(Model.knex());
try {
- const nitrogenScheduleResult = await baseController.postWithResponse(nitrogenScheduleModel, body, req, { trx });
+ const nitrogenScheduleResult = await baseController.postWithResponse(
+ nitrogenScheduleModel,
+ body,
+ req,
+ { trx },
+ );
await trx.commit();
res.status(201).send(nitrogenScheduleResult);
} catch (error) {
@@ -414,8 +478,14 @@ const insightController = {
delNitrogenSchedule() {
return async (req, res) => {
const trx = await transaction.start(Model.knex());
+ const { nitrogen_schedule_id } = req.params;
try {
- const isDeleted = await baseController.delete(nitrogenScheduleModel, req.params.nitrogen_schedule_id, req, { trx });
+ const isDeleted = await baseController.delete(
+ nitrogenScheduleModel,
+ nitrogen_schedule_id,
+ req,
+ { trx },
+ );
await trx.commit();
if (isDeleted) {
res.sendStatus(200);
@@ -432,5 +502,4 @@ const insightController = {
},
};
-
module.exports = insightController;
diff --git a/packages/api/src/controllers/insightHelpers.js b/packages/api/src/controllers/insightHelpers.js
index a45ce2916d..a8f2345b4f 100644
--- a/packages/api/src/controllers/insightHelpers.js
+++ b/packages/api/src/controllers/insightHelpers.js
@@ -21,41 +21,47 @@ const endPoints = require('../endPoints');
exports.averagePeopleFedMeals = (data) => {
let finalAverage = 0;
data.forEach((data) => {
- finalAverage += data['val']
+ finalAverage += data['val'];
});
return Math.round((finalAverage / data.length) * 100) / 100;
};
exports.getNutritionalData = (cropNutritionData) => {
-// @TODO, a simpler way to do this???
+ // @TODO, a simpler way to do this???
// generates the data for displaying a chart
// cal, prot, fats, vitc, vita
// returns an array with the values to easy-map
// expected intak for each nutrtion is referenced in the doc
const MEALS_PER_DAY = 3;
const data = {
- 'Calories': { label: 'Calories', val: 0, percentage: 0 },
- 'Protein': { label: 'Protein', val: 0, percentage: 0 },
- 'Fat': { label: 'Fat', val: 0, percentage: 0 },
+ Calories: { label: 'Calories', val: 0, percentage: 0 },
+ Protein: { label: 'Protein', val: 0, percentage: 0 },
+ Fat: { label: 'Fat', val: 0, percentage: 0 },
'Vitamin C': { label: 'Vitamin C', val: 0, percentage: 0 },
'Vitamin A': { label: 'Vitamin A', val: 0, percentage: 0 },
};
- const expectedDailyIntake = { 'Calories': 2500, 'Protein': 52, 'Fat': 75, 'Vitamin C': 90, 'Vitamin A': 900 };
+ const expectedDailyIntake = {
+ Calories: 2500,
+ Protein: 52,
+ Fat: 75,
+ 'Vitamin C': 90,
+ 'Vitamin A': 900,
+ };
cropNutritionData.map((item) => {
const percentRefuse = item.percentrefuse || 0;
- const percentLeft = 1 - (percentRefuse * 0.01);
- data['Calories']['val'] += (item.energy * 10) * item.quantity_kg * percentLeft; // kcal/lb
- data['Protein']['val'] += (item.protein * 10) * item.quantity_kg * percentLeft; // g/100g
- data['Fat']['val'] += (item.lipid * 10) * item.quantity_kg * percentLeft; // g/100g
- data['Vitamin C']['val'] += (item.vitc * 10) * item.quantity_kg * percentLeft; // mg/
- data['Vitamin A']['val'] += (item.vita_rae * 10) * item.quantity_kg * percentLeft;
+ const percentLeft = 1 - percentRefuse * 0.01;
+ data['Calories']['val'] += item.energy * 10 * item.quantity_kg * percentLeft; // kcal/lb
+ data['Protein']['val'] += item.protein * 10 * item.quantity_kg * percentLeft; // g/100g
+ data['Fat']['val'] += item.lipid * 10 * item.quantity_kg * percentLeft; // g/100g
+ data['Vitamin C']['val'] += item.vitc * 10 * item.quantity_kg * percentLeft; // mg/
+ data['Vitamin A']['val'] += item.vita_rae * 10 * item.quantity_kg * percentLeft;
});
// now normalize the data values
for (const key in data) {
- if (data.hasOwnProperty(key)) {
+ if (data.hasOwn(key)) {
data[key]['val'] = Math.round(data[key]['val'] / (expectedDailyIntake[key] / MEALS_PER_DAY));
}
}
@@ -63,7 +69,7 @@ exports.getNutritionalData = (cropNutritionData) => {
// now find the highest value for progress-bar to go off of
let maxVal = 0;
for (const key in data) {
- if (data.hasOwnProperty(key)) {
+ if (data.hasOwn(key)) {
maxVal = maxVal > data[key]['val'] ? maxVal : data[key]['val'];
}
}
@@ -71,7 +77,7 @@ exports.getNutritionalData = (cropNutritionData) => {
// now set the percentages for the progress-bar based off of the maxVal
for (const key in data) {
- if (data.hasOwnProperty(key)) {
+ if (data.hasOwn(key)) {
data[key]['percentage'] = Math.round((data[key]['val'] / maxVal) * 100);
}
}
@@ -79,11 +85,11 @@ exports.getNutritionalData = (cropNutritionData) => {
const returnArray = [];
for (const key in data) {
- if (data.hasOwnProperty(key)) {
- returnArray.push(data[key])
+ if (data.hasOwn(key)) {
+ returnArray.push(data[key]);
}
}
- return returnArray
+ return returnArray;
};
// helpers for Soil OM
@@ -100,18 +106,17 @@ exports.getSoilOM = async (data) => {
data.map((element) => {
if (!(element.location_id in returnData)) {
// The current field is not added to the returnData yet
- returnData[element.location_id] = initOMData(element)
+ returnData[element.location_id] = initOMData(element);
} else {
// If the current field has multiple soil data logs, put them
// into a list for calculating the average
- returnData[element.location_id]['activity_oms'].push(grabOM(element))
+ returnData[element.location_id]['activity_oms'].push(grabOM(element));
}
});
// assigning 'soil_om' to be the average of 'activity_oms'
// if there is no data, call the soilgrids api based on the first gridpoint
-
const soilGridPromises = Object.keys(returnData).map(async (key) => {
const summed = returnData[key]['activity_oms'].reduce((a, b) => a + b, 0);
if (summed === 0) {
@@ -129,17 +134,18 @@ exports.getSoilOM = async (data) => {
let runningAverage = 0;
for (const key in returnData) {
- runningAverage += returnData[key]['soil_om']
+ runningAverage += returnData[key]['soil_om'];
}
- returnValue['preview'] = Math.round((runningAverage / Object.keys(returnData).length) * 100) / 100;
+ returnValue['preview'] =
+ Math.round((runningAverage / Object.keys(returnData).length) * 100) / 100;
// max OM becomes 100% while everything else is based on it
let maxSoilOM = 0;
for (const key in returnData) {
- maxSoilOM = Math.max(returnData[key]['soil_om'], maxSoilOM)
+ maxSoilOM = Math.max(returnData[key]['soil_om'], maxSoilOM);
}
for (const key in returnData) {
- returnData[key]['percentage'] = (returnData[key]['soil_om'] / maxSoilOM) * 100
+ returnData[key]['percentage'] = (returnData[key]['soil_om'] / maxSoilOM) * 100;
}
// normalize to put in 'data' field of returnValue
@@ -158,14 +164,14 @@ const initOMData = (element) => {
OMData['percentage'] = 0;
OMData['activity_oms'] = [grabOM(element)];
- return OMData
+ return OMData;
};
// if om does not exist, grab organic_carbon, if organic_carbon does not exist, grab total_carbon
const grabOM = (element) => {
// parse the OM %
if (element.om !== 0) {
- return element.om
+ return element.om;
} else if (element.organic_carbon !== 0) {
return element.organic_carbon;
} else {
@@ -192,9 +198,8 @@ const callSoilGridAPI = async (data) => {
return Math.floor(soil_om);
})
.catch((err) => {
- return err
- })
-
+ return err;
+ });
};
/* Helpers for Labour Happiness */
@@ -211,11 +216,14 @@ exports.getLabourHappiness = (data) => {
// need to check if we should account for any task with happiness set, or any with duration set
data.map((element) => {
const currentValueMood = element['happiness'];
- const taskObject = { taskName: element['task_translation_key'], duration: element['duration'] ?? 0 };
+ const taskObject = {
+ taskName: element['task_translation_key'],
+ duration: element['duration'] ?? 0,
+ };
if (!(element['task_id'] in tasks)) {
tasks[element['task_id']] = { mood: currentValueMood, tasks: [taskObject] };
} else {
- tasks[element['task_id']]['tasks'].push(taskObject)
+ tasks[element['task_id']]['tasks'].push(taskObject);
}
});
@@ -225,15 +233,15 @@ exports.getLabourHappiness = (data) => {
const currentMood = tasks[key]['mood'];
const currentTasks = tasks[key]['tasks']; // an array
let currentDurationAverage = 0;
- currentTasks.map((element) => currentDurationAverage += element['duration']);
+ currentTasks.map((element) => (currentDurationAverage += element['duration']));
currentTasks.map((element) => {
- const weighted = currentDurationAverage ? (element['duration'] / currentDurationAverage) : 1;
+ const weighted = currentDurationAverage ? element['duration'] / currentDurationAverage : 1;
if (!(element['taskName'] in weightedTasks)) {
- weightedTasks[element['taskName']] = [{ mood: currentMood, weight: weighted }]
+ weightedTasks[element['taskName']] = [{ mood: currentMood, weight: weighted }];
} else {
- weightedTasks[element['taskName']].push({ mood: currentMood, weight: weighted })
+ weightedTasks[element['taskName']].push({ mood: currentMood, weight: weighted });
}
- })
+ });
}
// perform a "weighted mean" to get accurate data on ratings of tasks
@@ -258,7 +266,41 @@ exports.getLabourHappiness = (data) => {
average += element['mood'];
});
returnValue['preview'] = Math.round((average / returnValue['data'].length) * 100) / 100;
- return returnValue
+ return returnValue;
+};
+
+const findCentroid = (points) => {
+ let x = 0;
+ let y = 0;
+ points.forEach((p) => {
+ x += p.lng;
+ y += p.lat;
+ });
+ return { lng: x / points.length, lat: y / points.length };
+};
+
+const latlngCounterClockwiseLessThan = (a, b, center) => {
+ // compute the cross product of vectors (center -> a) x (center -> b)
+ // From right-hand rule this is +ve if a comes before b in ccw direction, -ve is a comes after b in ccw direction
+ const det =
+ (a.lng - center.lng) * (b.lat - center.lat) - (b.lng - center.lng) * (a.lat - center.lat);
+ if (det < 0) {
+ return 1;
+ } else if (det > 0) {
+ return -1;
+ }
+ // if we get here points are on the same line from the centre, so we want to return the point which is closest to the centre
+ const distanceA = Math.pow(a.lng - center.lng, 2) + Math.pow(a.lat - center.lat, 2);
+ const distanceB = Math.pow(b.lng - center.lng, 2) + Math.pow(b.lat - center.lat, 2);
+ return distanceA < distanceB ? 1 : -1;
+};
+
+const makePolygon = (points) => {
+ let polygonString = 'POLYGON((';
+ points.forEach((p) => {
+ polygonString = polygonString.concat(`${p.lng} ${p.lat},`);
+ });
+ return polygonString.concat(`${points[0].lng} ${points[0].lat}))`);
};
exports.getBiodiversityAPI = async (pointData, countData) => {
@@ -272,6 +314,7 @@ exports.getBiodiversityAPI = async (pointData, countData) => {
Insecta: 'Insects',
Plantae: 'Plants',
Amphibia: 'Amphibians',
+ Mammalia: 'Mammals',
};
const speciesCount = {
@@ -280,99 +323,92 @@ exports.getBiodiversityAPI = async (pointData, countData) => {
Plants: 0,
Amphibians: 0,
CropVarieties: 0,
+ Mammals: 0,
};
+ speciesCount['CropVarieties'] = parseInt(countData);
- const sortLats = new Array(pointData.length);
- const sortLngs = new Array(pointData.length);
- for (let i = 0; i < pointData.length; i++) {
- if (pointData[i]['grid_points'] != null) {
- pointData[i]['grid_points'].map((grid_point) => {
- if (Array.isArray(sortLats[i])) {
- sortLats[i].push(Math.round(grid_point['lat'] * 10000) / 10000);
- sortLngs[i].push(Math.round(grid_point['lng'] * 10000) / 10000);
- } else {
- sortLats[i] = [Math.round(grid_point['lat'] * 10000) / 10000];
- sortLngs[i] = [Math.round(grid_point['lng'] * 10000) / 10000]
- }
- })
- }
- }
- const fieldPoints = new Array(pointData.length);
+ const polygons = pointData.map((points) => {
+ const centroid = findCentroid(points.grid_points);
+ const compareLatLong = (a, b) => latlngCounterClockwiseLessThan(a, b, centroid);
+ return makePolygon(points.grid_points.sort(compareLatLong));
+ });
- for (let i = 0; i < pointData.length; i++) {
- fieldPoints[i] = [
- [Math.min(...sortLats[i]), Math.max(...sortLats[i])],
- [Math.min(...sortLngs[i]), Math.max(...sortLngs[i])],
- ]
- }
- speciesCount['CropVarieties'] = parseInt(countData);
+ const apiData = [];
const apiCalls = [];
-
- fieldPoints.forEach((fieldPoint) => {
- // TODO: figure out how to fetch past limit. ST-46
- const options = {
- uri: endPoints.gbifAPI,
- qs: {
- decimalLatitude: fieldPoint[0][0] + ',' + fieldPoint[0][1], //minLat maxLat
- decimalLongitude: fieldPoint[1][0] + ',' + fieldPoint[1][1], //minLong maxLong
- },
- };
- apiCalls.push(new Promise((resolve, reject) => {
- rp(options)
- .then((data) => {
- const jsonfied = JSON.parse(data);
- const results = jsonfied['results'];
- const infoFiltered = results.map((currentSpecies) => ({
- key: currentSpecies['key'],
- identificationID: currentSpecies['identificationID'],
- kingdom: currentSpecies['kingdom'],
- class: currentSpecies['class'],
- }));
- resolve(infoFiltered);
- })
- .catch((error) => {
- reject(error)
- })
- }));
+ console.time('First requests');
+ const counts = await Promise.all(
+ polygons.map(async (polygon) => {
+ const firstRequestOptions = {
+ uri: endPoints.gbifAPI,
+ qs: {
+ geometry: polygon,
+ // Max limit for api
+ limit: 300,
+ offset: 0,
+ // year: `${year - 5},${year}`,
+ },
+ };
+ const data = await rp(firstRequestOptions);
+ const { count, results } = JSON.parse(data);
+ apiData.push(...results);
+ return count;
+ }),
+ );
+ console.timeEnd('First requests');
+ console.time('generate');
+ counts.forEach((count, index) => {
+ for (let i = 300; i < count; i += 300) {
+ apiCalls.push(
+ new Promise((resolve, reject) => {
+ const a = i;
+ rp({
+ uri: endPoints.gbifAPI,
+ qs: {
+ geometry: polygons[index],
+ limit: 300,
+ offset: i,
+ },
+ })
+ .then((data) => {
+ const parsedData = JSON.parse(data);
+ apiData.push(...parsedData.results);
+ resolve();
+ })
+ .catch((error) => {
+ console.log(`Rejecting error on offset: ${a}`);
+ reject(error);
+ });
+ }),
+ );
+ }
});
- return await Promise.all(apiCalls)
- .then((apiResult) => {
- const mergedResults = mergeSpeciesObjects(apiResult);
- mergedResults.map((currentSpecies) => {
- if (currentSpecies['kingdom'] in dictionary) {
- speciesCount[dictionary[currentSpecies['kingdom']]]++;
- } else if (currentSpecies['class'] in dictionary) {
- speciesCount[dictionary[currentSpecies['class']]]++;
- }
- });
- let runningTotal = 0;
- let maxSpecies = 0;
- for (const key in speciesCount) {
- runningTotal += speciesCount[key];
- maxSpecies = Math.max(speciesCount[key], maxSpecies);
- resultData['data'].push({ name: key, count: speciesCount[key], percentage: 0 })
+ console.timeEnd('generate');
+ console.time('Api calls');
+ await Promise.allSettled(apiCalls);
+ console.timeEnd('Api calls');
+ console.time('Filter');
+ const filteredData = apiData.reduce((filtered, current) => {
+ if (!filtered.includes(current['speciesKey'])) {
+ filtered.push(current['speciesKey']);
+ if (current['kingdom'] in dictionary) {
+ speciesCount[dictionary[current['kingdom']]]++;
}
- resultData['data'].map((curr) => {
- curr['percentage'] = (curr['count'] / maxSpecies) * 100;
- });
- resultData['preview'] = runningTotal;
- return resultData
- })
- .catch((error) => {
- return error
+ if (current['class'] in dictionary) {
+ speciesCount[dictionary[current['class']]]++;
+ }
+ }
+ return filtered;
+ }, []);
+ console.timeEnd('Filter');
+ for (const species in speciesCount) {
+ resultData['data'].push({
+ name: species,
+ count: speciesCount[species],
+ percent: (speciesCount[species] / filteredData.length) * 100,
});
-};
-
-const mergeSpeciesObjects = (objects) => {
- if (objects.length === 0) {
- return [];
}
- let merged = objects[0];
- for (let i = 1; i < objects.length; i++) {
- const keys = new Set(merged.map(item => item.key));
- merged = [...merged, ...objects[i].filter(item => !keys.has(item.key))];
- }
- return merged;
+ resultData.preview = filteredData.length;
+ return resultData;
};
exports.formatPricesData = (data) => {
@@ -405,9 +441,9 @@ exports.formatPricesData = (data) => {
network_price: networkPriceForCrop.toFixed(2),
};
if (crop_name in organizeByMonthAndYear) {
- organizeByMonthAndYear[crop_name].push(cropData)
+ organizeByMonthAndYear[crop_name].push(cropData);
} else {
- organizeByMonthAndYear[crop_name] = [cropData]
+ organizeByMonthAndYear[crop_name] = [cropData];
}
});
runningTotal = (runningTotal * 100) / 100;
@@ -415,7 +451,7 @@ exports.formatPricesData = (data) => {
for (const key in organizeByMonthAndYear) {
returnData['data'].push({ [key]: organizeByMonthAndYear[key] });
}
- return returnData
+ return returnData;
};
exports.formatPricesNearbyData = (myFarmID, data) => {
@@ -430,32 +466,55 @@ exports.formatPricesNearbyData = (myFarmID, data) => {
// tally the running total as well as separate the data into different months
data.map((element) => {
if (!(element['crop_translation_key'] in organizeByNameThenByDate)) {
- organizeByNameThenByDate[element['crop_translation_key']] = {}
+ organizeByNameThenByDate[element['crop_translation_key']] = {};
}
if (!(element['year_month'] in organizeByNameThenByDate[element['crop_translation_key']])) {
organizeByNameThenByDate[element['crop_translation_key']][element['year_month']] = {
- 'crop_price_total': 0,
- 'sale_quant_total': 0,
- 'network_price': 0,
- }
+ crop_price_total: 0,
+ sale_quant_total: 0,
+ network_price: 0,
+ };
}
if (element['farm_id'] === myFarmID) {
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['crop_price_total'] += element['sale_value'];
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['sale_quant_total'] += element['sale_quant'];
-
- if (Array.isArray(organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'])) {
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'].push(element)
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'crop_price_total'
+ ] += element['sale_value'];
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'sale_quant_total'
+ ] += element['sale_quant'];
+
+ if (
+ Array.isArray(
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ],
+ )
+ ) {
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ].push(element);
} else {
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'] = [ element ];
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ] = [element];
}
- }
- else {
+ } else {
// first total up all network prices in an array and then grab the mean after
farmIDs.add(element['farm_id']);
- if (Array.isArray(organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'])) {
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'].push(element)
+ if (
+ Array.isArray(
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ],
+ )
+ ) {
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ].push(element);
} else {
- organizeByNameThenByDate[element['crop_translation_key']][element['year_month']]['network_price'] = [ element ]
+ organizeByNameThenByDate[element['crop_translation_key']][element['year_month']][
+ 'network_price'
+ ] = [element];
}
}
});
@@ -468,16 +527,19 @@ exports.formatPricesNearbyData = (myFarmID, data) => {
runningNetworkQuantity += sale['sale_quant'];
runningNetworkValue += sale['sale_value'];
});
- const networkPrice = runningNetworkValue / runningNetworkQuantity;
+ const networkPrice = runningNetworkValue / runningNetworkQuantity;
const cropData = {
crop_date: date,
- crop_price: roundToTwoDecimal(organizeByNameThenByDate[crop_name][date]['crop_price_total']/(organizeByNameThenByDate[crop_name][date]['sale_quant_total'] || 1)),
+ crop_price: roundToTwoDecimal(
+ organizeByNameThenByDate[crop_name][date]['crop_price_total'] /
+ (organizeByNameThenByDate[crop_name][date]['sale_quant_total'] || 1),
+ ),
network_price: roundToTwoDecimal(networkPrice),
};
if (crop_name in organizeByMonthAndYear) {
- organizeByMonthAndYear[crop_name].push(cropData)
+ organizeByMonthAndYear[crop_name].push(cropData);
} else {
- organizeByMonthAndYear[crop_name] = [cropData]
+ organizeByMonthAndYear[crop_name] = [cropData];
}
}
}
@@ -488,16 +550,16 @@ exports.formatPricesNearbyData = (myFarmID, data) => {
organizeByMonthAndYear[crop].forEach((crop) => {
if (crop['crop_price'] !== 0) {
runningSum += crop['crop_price'] / crop['network_price'];
- runningLength += 1
+ runningLength += 1;
}
- })
+ });
}
returnData['preview'] = Math.ceil((runningSum / runningLength) * 100);
returnData['amountOfFarms'] = farmIDs.size || 0;
for (const key in organizeByMonthAndYear) {
returnData['data'].push({ [key]: organizeByMonthAndYear[key] });
}
- return returnData
+ return returnData;
};
exports.formatWaterBalanceData = async (dataPoints) => {
@@ -513,7 +575,10 @@ exports.formatWaterBalanceData = async (dataPoints) => {
let runningTotal = 0;
dataPoints.forEach((crop) => {
const fieldKeyName = crop['field_id'] + ' ' + crop['field_name'];
- const cropObject = { crop: crop['crop_common_name'], plantAvailableWater: crop['plant_available_water'] };
+ const cropObject = {
+ crop: crop['crop_common_name'],
+ plantAvailableWater: crop['plant_available_water'],
+ };
runningTotal += crop['plant_available_water'];
if (Array.isArray(cropsByField[fieldKeyName])) {
cropsByField[fieldKeyName].push(cropObject);
@@ -522,11 +587,11 @@ exports.formatWaterBalanceData = async (dataPoints) => {
}
});
for (const key in cropsByField) {
- returnData['data'].push({ [key]: cropsByField[key] })
+ returnData['data'].push({ [key]: cropsByField[key] });
}
returnData['preview'] = Math.round((runningTotal / amountOfCrops) * 100) / 100;
- return returnData
+ return returnData;
};
exports.formatNitrogenBalanceData = async (dataPoints) => {
@@ -538,17 +603,17 @@ exports.formatNitrogenBalanceData = async (dataPoints) => {
if (dataPoints.length === 0) return returnData;
dataPoints.forEach((row) => {
runningTotal += row['nitrogen_value'];
- returnData['data'].push({ [row['field_id'] + ' ' + row['field_name']]: Math.round(row['nitrogen_value'] * 100) / 100 })
+ returnData['data'].push({
+ [row['field_id'] + ' ' + row['field_name']]: Math.round(row['nitrogen_value'] * 100) / 100,
+ });
});
- returnData['preview'] = Math.round(runningTotal / dataPoints.length * 100) / 100;
- return returnData
+ returnData['preview'] = Math.round((runningTotal / dataPoints.length) * 100) / 100;
+ return returnData;
};
-
exports.formatPreviousDate = (date, mode) => {
const d = new Date(date);
- let
- year = d.getFullYear(),
+ let year = d.getFullYear(),
month = '' + (d.getMonth() + 1),
day = '' + d.getDate();
@@ -575,31 +640,33 @@ exports.formatPreviousDate = (date, mode) => {
//::: :::
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-exports.distance = (lat1, lon1, lat2, lon2, unit='KM') => {
- if ((lat1 === lat2) && (lon1 === lon2)) {
+exports.distance = (lat1, lon1, lat2, lon2, unit = 'KM') => {
+ if (lat1 === lat2 && lon1 === lon2) {
return 0;
} else {
- const radlat1 = Math.PI * lat1 / 180;
- const radlat2 = Math.PI * lat2 / 180;
+ const radlat1 = (Math.PI * lat1) / 180;
+ const radlat2 = (Math.PI * lat2) / 180;
const theta = lon1 - lon2;
- const radtheta = Math.PI * theta / 180;
- let dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
+ const radtheta = (Math.PI * theta) / 180;
+ let dist =
+ Math.sin(radlat1) * Math.sin(radlat2) +
+ Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {
dist = 1;
}
dist = Math.acos(dist);
- dist = dist * 180 / Math.PI;
+ dist = (dist * 180) / Math.PI;
dist = dist * 60 * 1.1515;
if (unit === 'KM') {
- dist = dist * 1.609344
+ dist = dist * 1.609344;
}
if (unit === 'MILE') {
- dist = dist * 0.8684
+ dist = dist * 0.8684;
}
return dist;
}
};
const roundToTwoDecimal = (number) => {
- return number * 100 / 100
+ return (number * 100) / 100;
};
diff --git a/packages/api/src/controllers/loginController.js b/packages/api/src/controllers/loginController.js
index 693a776ea1..2004a547bf 100644
--- a/packages/api/src/controllers/loginController.js
+++ b/packages/api/src/controllers/loginController.js
@@ -13,16 +13,15 @@
* GNU General Public License for more details, see .
*/
-const baseController = require('../controllers/baseController');
const userModel = require('../models/userModel');
const passwordModel = require('../models/passwordModel');
const userFarmModel = require('../models/userFarmModel');
const showedSpotlightModel = require('../models/showedSpotlightModel');
const bcrypt = require('bcryptjs');
-const userController = require('./userController');
-const { sendEmailTemplate, emails, sendEmail } = require('../templates/sendEmailTemplate');
+const { emails, sendEmail } = require('../templates/sendEmailTemplate');
const parser = require('ua-parser-js');
const userLogModel = require('../models/userLogModel');
+const emailModel = require('../models/emailTokenModel');
const { createToken } = require('../util/jwt');
@@ -46,7 +45,11 @@ const loginController = {
try {
const userData = await userModel.query().select('*').where('email', email).first();
- const pwData = await passwordModel.query().select('*').where('user_id', userData.user_id).first();
+ const pwData = await passwordModel
+ .query()
+ .select('*')
+ .where('user_id', userData.user_id)
+ .first();
const isMatch = await bcrypt.compare(password, pwData.password_hash);
userID = userData.user_id;
if (!isMatch) {
@@ -66,7 +69,7 @@ const loginController = {
reason_for_failure: 'password_mismatch',
});
return res.sendStatus(401);
- };
+ }
const id_token = await createToken('access', { user_id: userData.user_id });
return res.status(200).send({
@@ -108,23 +111,26 @@ const loginController = {
const isUserNew = !user;
if (isUserNew) {
const newUser = { user_id, email, first_name, last_name, language_preference };
- await userModel.transaction(async trx => {
+ await userModel.transaction(async (trx) => {
await userModel.query(trx).insert(newUser);
await showedSpotlightModel.query(trx).insert({ user_id });
});
}
const isPasswordNeeded = !ssoUser && passwordUser;
- const id_token = isPasswordNeeded
- ? ''
- : await createToken('access', { user_id });
+ const id_token = isPasswordNeeded ? '' : await createToken('access', { user_id });
return res.status(201).send({
id_token,
user: {
user_id: isPasswordNeeded ? passwordUser.user_id : user_id,
email,
first_name: isPasswordNeeded ? passwordUser.first_name : first_name,
- language_preference: ssoUser?.language_preference ?? passwordUser?.language_preference ?? language_preference,
- full_name: isPasswordNeeded ? `${passwordUser.first_name} ${passwordUser.last_name}` : `${first_name} ${last_name}`
+ language_preference:
+ ssoUser?.language_preference ??
+ passwordUser?.language_preference ??
+ language_preference,
+ full_name: isPasswordNeeded
+ ? `${passwordUser.first_name} ${passwordUser.last_name}`
+ : `${first_name} ${last_name}`,
},
isSignUp: isUserNew,
});
@@ -140,8 +146,12 @@ const loginController = {
return async (req, res) => {
const { email } = req.params;
try {
- const data = await userModel.query()
- .select('user_id', 'first_name', 'email', 'language_preference', 'status_id').from('users').where('users.email', email).first();
+ const data = await userModel
+ .query()
+ .select('user_id', 'first_name', 'email', 'language_preference', 'status_id')
+ .from('users')
+ .where('users.email', email)
+ .first();
if (!data) {
res.status(200).send({
first_name: null,
@@ -212,28 +222,40 @@ const loginController = {
};
async function sendMissingInvitations(user) {
- const userFarms = await userFarmModel.query().select('users.*', 'farm.farm_name', 'farm.farm_id')
+ const userFarms = await userFarmModel
+ .query()
+ .select('users.*', 'farm.farm_name', 'farm.farm_id')
.join('farm', 'userFarm.farm_id', 'farm.farm_id')
.join('users', 'users.user_id', 'userFarm.user_id')
- .where('users.user_id', user.user_id).andWhere('userFarm.status', 'Invited');
+ .where('users.user_id', user.user_id)
+ .andWhere('userFarm.status', 'Invited');
if (userFarms) {
- await Promise.all(userFarms.map((userFarm) => {
- return userController.createTokenSendEmail(user, userFarm, userFarm.farm_name);
- }));
+ await Promise.all(
+ userFarms.map((userFarm) => {
+ return emailModel.createTokenSendEmail(user, userFarm, userFarm.farm_name);
+ }),
+ );
}
}
async function sendPasswordReset(data) {
const created_at = new Date();
- const wasEmailSent = await passwordModel.query()
- .select('*').where({ user_id: data.user_id }).first();
- const password = wasEmailSent ? wasEmailSent : await passwordModel.query()
- .insert({
- user_id: data.user_id,
- reset_token_version: 1,
- password_hash: `${Math.random()}`,
- created_at: created_at.toISOString(),
- }).returning('*');
+ const wasEmailSent = await passwordModel
+ .query()
+ .select('*')
+ .where({ user_id: data.user_id })
+ .first();
+ const password = wasEmailSent
+ ? wasEmailSent
+ : await passwordModel
+ .query()
+ .insert({
+ user_id: data.user_id,
+ reset_token_version: 1,
+ password_hash: `${Math.random()}`,
+ created_at: created_at.toISOString(),
+ })
+ .returning('*');
const tokenPayload = {
...data,
reset_token_version: 0,
diff --git a/packages/api/src/controllers/managementPlanController.js b/packages/api/src/controllers/managementPlanController.js
index aaefc872b0..d4b5b6ee42 100644
--- a/packages/api/src/controllers/managementPlanController.js
+++ b/packages/api/src/controllers/managementPlanController.js
@@ -37,17 +37,16 @@ const managementPlanController = {
req.body, { noUpdate: true, noDelete: true, noInsert: ['location', 'crop_variety'] });
const tasks = [];
- const getTask = (planned_time, task_type_id, task = {}) => {
+ const getTask = (due_date, task_type_id, task = {}) => {
return {
- due_date: planned_time,
- planned_time,
+ due_date,
task_type_id,
owner_user_id: req.user.user_id,
...task,
};
};
if (!req.body.crop_management_plan.already_in_ground) {
- const planned_time = req.body.crop_management_plan.plant_date || req.body.crop_management_plan.seed_date;
+ const due_date = req.body.crop_management_plan.plant_date || req.body.crop_management_plan.seed_date;
const { planting_management_plan_id } = management_plan.crop_management_plan.planting_management_plans.find(
planting_management_plan => planting_management_plan.planting_task_type === 'PLANT_TASK',
);
@@ -56,12 +55,12 @@ const managementPlanController = {
'farm_id': null,
'task_translation_key': 'PLANT_TASK',
}).first();
- const plantTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(planned_time, plantTaskType.task_type_id, { plant_task: { planting_management_plan_id } }));
+ const plantTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(due_date, plantTaskType.task_type_id, { plant_task: { planting_management_plan_id } }));
tasks.push(plantTask);
}
if (req.body.crop_management_plan.needs_transplant) {
- const planned_time = req.body.crop_management_plan.transplant_date;
+ const due_date = req.body.crop_management_plan.transplant_date;
const { planting_management_plan_id } = management_plan.crop_management_plan.planting_management_plans.find(
planting_management_plan => planting_management_plan.planting_task_type === 'TRANSPLANT_TASK',
);
@@ -73,7 +72,7 @@ const managementPlanController = {
'farm_id': null,
'task_translation_key': 'TRANSPLANT_TASK',
}).first();
- const transplantTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(planned_time, transplantTaskType.task_type_id, {
+ const transplantTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(due_date, transplantTaskType.task_type_id, {
transplant_task: {
planting_management_plan_id,
prev_planting_management_plan_id,
@@ -93,22 +92,22 @@ const managementPlanController = {
managementPlans: [{ planting_management_plan_id }],
};
if (!req.body.crop_management_plan.for_cover) {
- const planned_time = req.body.crop_management_plan.harvest_date;
+ const due_date = req.body.crop_management_plan.harvest_date;
const harvestTaskType = await taskTypeModel.query(trx).where({
'farm_id': null,
'task_translation_key': 'HARVEST_TASK',
}).first();
- const harvestTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(planned_time, harvestTaskType.task_type_id, { harvest_task: { harvest_everything: true }, ...taskManagementPlansAndLocations }), {
+ const harvestTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(due_date, harvestTaskType.task_type_id, { harvest_task: { harvest_everything: true }, ...taskManagementPlansAndLocations }), {
relate: ['locations', 'managementPlans'],
});
tasks.push(harvestTask);
} else {
- const planned_time = req.body.crop_management_plan.termination_date;
+ const due_date = req.body.crop_management_plan.termination_date;
const fieldWorkTaskType = await taskTypeModel.query(trx).where({
'farm_id': null,
'task_translation_key': 'FIELD_WORK_TASK',
}).first();
- const fieldWorkTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(planned_time, fieldWorkTaskType.task_type_id, { field_work_task: { type: 'TERMINATION' }, ...taskManagementPlansAndLocations }), {
+ const fieldWorkTask = await taskModel.query(trx).context(req.user).upsertGraph(getTask(due_date, fieldWorkTaskType.task_type_id, { field_work_task: { type: 'TERMINATION' }, ...taskManagementPlansAndLocations }), {
relate: ['locations', 'managementPlans'],
});
tasks.push(fieldWorkTask);
@@ -180,20 +179,20 @@ const managementPlanController = {
.then(tasks => managementTasksModel.query()
.join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'management_tasks.planting_management_plan_id')
.join('task', 'task.task_id', 'management_tasks.task_id')
- .whereNull('task.completed_time')
+ .whereNull('task.complete_date')
.whereIn('management_tasks.task_id', tasks.map(({ task_id }) => task_id))
.groupBy('management_tasks.task_id').count('planting_management_plan.management_plan_id').select('management_tasks.task_id'));
const transplantTasks = await transplantTaskModel.query().select('*')
.join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'transplant_task.planting_management_plan_id')
.join('task', 'task.task_id', 'transplant_task.task_id')
- .whereNull('task.completed_time')
+ .whereNull('task.complete_date')
.where('planting_management_plan.management_plan_id', management_plan_id);
const plantTasks = await plantTaskModel.query().select('*')
.join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'plant_task.planting_management_plan_id')
.join('task', 'task.task_id', 'plant_task.task_id')
- .whereNull('task.completed_time')
+ .whereNull('task.complete_date')
.where('planting_management_plan.management_plan_id', management_plan_id);
const taskIdsRelatedToOneManagementPlan = [...tasksWithManagementPlanCount.filter(({ count }) => count === '1'), ...transplantTasks, ...plantTasks]
@@ -201,7 +200,7 @@ const managementPlanController = {
const abandonedTasks = await taskModel.query(trx).context(req.user)
.whereIn('task_id', taskIdsRelatedToOneManagementPlan)
.patch({
- abandoned_time: req.body.abandon_date,
+ abandon_date: req.body.abandon_date,
abandonment_reason: 'OTHER',
other_abandonment_reason: 'Crop management plan abandoned',
});
diff --git a/packages/api/src/controllers/notificationUserController.js b/packages/api/src/controllers/notificationUserController.js
new file mode 100644
index 0000000000..d45a02c070
--- /dev/null
+++ b/packages/api/src/controllers/notificationUserController.js
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const NotificationUser = require('../models/notificationUserModel');
+
+/**
+ * Controls requests related to the user's notifications.
+ */
+module.exports = {
+ /**
+ * Establishes a subscription for the user's notifications.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ */
+ subscribeToAlerts(req, res) {
+ const { user_id, farm_id, subscriber_id } = req.query;
+
+ // Maintain subscriptions Map(key = user_id, value = Map(key = subscriber_id, value = Map(key = timestamp, value = res))).
+ // subscriber_id distinguishes the same user in different browsers.
+ const subscriptions = NotificationUser.subscriptions;
+
+ let userSubs = subscriptions.get(user_id);
+ if (!userSubs) {
+ userSubs = new Map();
+ subscriptions.set(user_id, userSubs);
+ }
+
+ let subscriberSubs = userSubs.get(subscriber_id);
+ if (!subscriberSubs) {
+ subscriberSubs = new Map();
+ userSubs.set(subscriber_id, subscriberSubs);
+ }
+
+ if (subscriberSubs.size >= 5) {
+ // Subscriptions are limited to 5 per browser.
+ // 204 No Content communicates (non)result while avoiding error status.
+ // Cannot send text because connection is event stream.
+ return res.sendStatus(204);
+ }
+
+ // Use server-sent events.
+ res.writeHead(200, {
+ 'Content-Type': 'text/event-stream',
+ 'Content-Encoding': 'identity',
+ Connection: 'keep-alive',
+ 'Cache-Control': 'no-cache',
+ 'X-Accel-Buffering': 'no',
+ });
+ res.write('\n');
+
+ const opened = new Date().toISOString();
+
+ // Register a function to send alerts to sessions for the user, farm combination.
+ const sendAlert = (delta = 1) => {
+ res.write(`data: ${JSON.stringify({ delta })}\n\n`);
+ };
+
+ // Periodically send a "heartbeat" to prevent browser from closing idle connection.
+ // Chrome appears to close connections that are idle for 1 minute.
+ // Note: there is client code to reconnect after idle timeout or other disconnect.
+ // But that causes scary error in browser console, plus brief outage in connectivity.
+ const intervalId = setInterval(() => {
+ sendAlert(0);
+ }, 1000 * 45);
+
+ // Register a function to end the long-term HTTP response that handles server-sent events.
+ const endHttpRes = () => {
+ res.end();
+ };
+
+ // Record the subscription.
+ subscriberSubs.set(opened, { farm_id, sendAlert, endHttpRes });
+ subscriptions.set('count', (subscriptions.get('count') || 0) + 1);
+ console.log(
+ `Opening subscription: user ${user_id} as subscriber ${subscriber_id} at ${opened}`,
+ );
+ console.log(
+ ` ${subscriptions.size - 1} users have ${subscriptions.get('count')} active subscriptions.`,
+ );
+ // console.log('subscriptions', subscriptions)
+
+ // Cleans up subscription tracking when HTTP request closes.
+ req.on('close', () => {
+ clearInterval(intervalId);
+ const userSubs = subscriptions.get(user_id);
+ if (!userSubs) {
+ console.log(`Cannot close non-existent subscription: user ${user_id}`);
+ return;
+ }
+
+ const subscriberSubs = userSubs.get(subscriber_id);
+ if (!subscriberSubs) {
+ console.log(
+ `Cannot close non-existent subscription: subscriber ${subscriber_id} as subscriber ${subscriber_id}`,
+ );
+ return;
+ }
+
+ const sub = subscriberSubs.get(opened);
+ if (!sub) {
+ console.log(
+ `Cannot close non-existent subscription: user ${user_id} as subscriber ${subscriber_id} opened at ${opened}`,
+ );
+ return;
+ }
+
+ // End the HTTP response.
+ sub.endHttpRes();
+
+ // Remove the subscription tracking.
+ subscriberSubs.delete(opened);
+ if (subscriberSubs.size === 0) userSubs.delete(subscriber_id);
+ if (userSubs.size === 0) subscriptions.delete(user_id);
+ subscriptions.set('count', subscriptions.get('count') - 1);
+ console.log(
+ `Closed subscription: user ${user_id} as subscriber ${subscriber_id} opened at ${opened}`,
+ );
+ console.log(
+ ` ${subscriptions.size - 1} users have ${subscriptions.get(
+ 'count',
+ )} active subscriptions.`,
+ );
+ });
+ },
+
+ /**
+ * Responds with the user's notifications regarding their current farm.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ * @async
+ */
+ async getNotifications(req, res) {
+ try {
+ const notifications = await NotificationUser.getNotificationsForFarmUser(
+ req.headers.farm_id,
+ req.user.user_id,
+ );
+ res.status(200).send(notifications);
+ } catch (error) {
+ console.log(error);
+ res.status(400).json({ error });
+ }
+ },
+
+ /**
+ * Handles requests to update user notifications.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ * @async
+ */
+ async patchNotifications(req, res) {
+ const payload = { ...req.body };
+ delete payload.notification_ids;
+ try {
+ await NotificationUser.update(req.user.user_id, req.body.notification_ids, payload);
+ res.sendStatus(200);
+ } catch (error) {
+ console.log(error);
+ res.status(400).json({ error });
+ }
+ },
+
+ /**
+ * Handles requests to clear notification alert indicators.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ * @async
+ */
+ async clearAlerts(req, res) {
+ try {
+ await NotificationUser.clearAlerts(
+ req.user.user_id,
+ req.headers.farm_id,
+ req.body.notification_ids,
+ );
+ res.sendStatus(200);
+ } catch (error) {
+ console.log(error);
+ res.status(400).json({ error });
+ }
+ },
+};
diff --git a/packages/api/src/controllers/organicCertifierSurveyController.js b/packages/api/src/controllers/organicCertifierSurveyController.js
index 46289c50aa..9a4f4c6dab 100644
--- a/packages/api/src/controllers/organicCertifierSurveyController.js
+++ b/packages/api/src/controllers/organicCertifierSurveyController.js
@@ -23,7 +23,7 @@ const locationModel = require('../models/locationModel');
const documentModel = require('../models/documentModel');
const Queue = require('bull');
-const { raw, Model } = require('objection');
+const { Model } = require('objection');
const { v4: uuidv4 } = require('uuid');
const knex = Model.knex();
const redisConf = {
@@ -186,6 +186,7 @@ const organicCertifierSurveyController = {
.whereBetween('valid_until', [from_date, to_date])
.orWhere({ no_expiration: true });
})
+ .where({ archived: false })
.andWhere({ farm_id });
const user_id = req.user.user_id;
const files = documents
@@ -258,7 +259,7 @@ const organicCertifierSurveyController = {
JOIN crop c ON cp.crop_id = c.crop_id
JOIN crop_management_plan cpm ON cpm.management_plan_id = mp.management_plan_id
JOIN farm f ON cp.farm_id = f.farm_id
- WHERE mp.management_plan_id = any(:managementPlanIds)
+ WHERE mp.management_plan_id = any (:managementPlanIds)
AND cp.organic IS NOT NULL
AND cp.farm_id = :farm_id
`,
@@ -273,9 +274,9 @@ const organicCertifierSurveyController = {
p.supplier,
sat.product_quantity,
CASE
- WHEN t.completed_time is null
+ WHEN t.complete_date is null
THEN t.due_date
- ELSE t.completed_time
+ ELSE t.complete_date
END as date_used,
t.task_id,
p.on_permitted_substances_list
@@ -284,22 +285,20 @@ const organicCertifierSurveyController = {
JOIN product p ON p.product_id = sat.product_id
JOIN location_tasks tl ON t.task_id = tl.task_id
JOIN location l ON tl.location_id = l.location_id
- JOIN (
- SELECT location_id
- FROM field
- WHERE organic_status != 'Non-Organic'
- UNION
- SELECT location_id
- FROM greenhouse
- WHERE organic_status != 'Non-Organic'
- UNION
- SELECT location_id
- FROM garden
- WHERE organic_status != 'Non-Organic'
- ) lu ON lu.location_id = l.location_id
- WHERE ((completed_time::date <= :to_date::date AND completed_time::date >= :from_date::date) OR
+ JOIN (SELECT location_id
+ FROM field
+ WHERE organic_status != 'Non-Organic'
+ UNION
+ SELECT location_id
+ FROM greenhouse
+ WHERE organic_status != 'Non-Organic'
+ UNION
+ SELECT location_id
+ FROM garden
+ WHERE organic_status != 'Non-Organic') lu ON lu.location_id = l.location_id
+ WHERE ((complete_date::date <= :to_date::date AND complete_date::date >= :from_date::date) OR
(due_date::date <= :to_date::date AND due_date::date >= :from_date::date))
- AND abandoned_time IS NULL
+ AND abandon_date IS NULL
AND p.farm_id = :farm_id
`,
{ to_date, from_date, farm_id },
@@ -334,18 +333,18 @@ const organicCertifierSurveyController = {
p.supplier,
ct.product_quantity,
CASE
- WHEN t.completed_time is null
+ WHEN t.complete_date is null
THEN t.due_date
- ELSE t.completed_time
+ ELSE t.complete_date
END as date_used,
t.task_id,
p.on_permitted_substances_list
FROM task t
JOIN cleaning_task ct ON ct.task_id = t.task_id
JOIN product p ON p.product_id = ct.product_id
- WHERE ((completed_time::date <= :to_date::date AND completed_time::date >= :from_date::date) OR
+ WHERE ((complete_date::date <= :to_date::date AND complete_date::date >= :from_date::date) OR
(due_date::date <= :to_date::date AND due_date::date >= :from_date::date))
- AND abandoned_time IS NULL
+ AND abandon_date IS NULL
AND p.farm_id = :farm_id
`,
{ to_date, from_date, farm_id },
@@ -405,12 +404,13 @@ const organicCertifierSurveyController = {
}
/**
* https://lucid.app/lucidchart/482f5f34-1ff7-4166-a1c4-7c23560fe7b5/edit?invitationId=inv_f1389038-4f0a-4b67-a826-adc754bfeb9f
+ * hasBeenTransplanted = plantingManagementPlans.filter()
*/
- const hasBeenTransplanted = plantingManagementPlans
+ plantingManagementPlans
.filter((plantingManagementPlan) => {
- if (plantingManagementPlan?.transplant_task?.task?.abandoned_time) return false;
+ if (plantingManagementPlan?.transplant_task?.task?.abandon_date) return false;
const transplantTaskDate =
- plantingManagementPlan?.transplant_task?.task?.completed_time ||
+ plantingManagementPlan?.transplant_task?.task?.complete_date ||
plantingManagementPlan.transplant_task?.task?.due_date;
if (!transplantTaskDate) return true;
return transplantTaskDate <= endOfEndDate;
@@ -421,12 +421,12 @@ const organicCertifierSurveyController = {
if (!task2.transplant_task) return -1;
const {
transplant_task: {
- task: { completed_time: firstCompleteTime, due_date: firstDueDate },
+ task: { complete_date: firstCompleteTime, due_date: firstDueDate },
},
} = task1;
const {
transplant_task: {
- task: { completed_time: secondCompleteTime, due_date: secondDueDate },
+ task: { complete_date: secondCompleteTime, due_date: secondDueDate },
},
} = task2;
return (
@@ -439,7 +439,7 @@ const organicCertifierSurveyController = {
managementPlan.crop_variety.crop.crop_translation_key,
);
const transplantTaskDate =
- plantingManagementPlan?.transplant_task?.task?.completed_time ||
+ plantingManagementPlan?.transplant_task?.task?.complete_date ||
plantingManagementPlan.transplant_task?.task?.due_date;
return transplantTaskDate && transplantTaskDate < startOfFromDate;
});
@@ -551,11 +551,11 @@ const organicCertifierSurveyController = {
if (planting_management_plan.transplant_task)
tasks.push(planting_management_plan.transplant_task.task);
- const nonAbandonedTasks = tasks.filter((task) => !task.abandoned_time);
+ const nonAbandonedTasks = tasks.filter((task) => !task.abandon_date);
let hasTasksBeforeReportingPeriod;
let hasTasksAfterReportingPeriod;
for (const task of nonAbandonedTasks) {
- const taskDate = task?.completed_time || task.due_date;
+ const taskDate = task?.complete_date || task.due_date;
if (taskDate >= startOfFromDate && taskDate <= endOfEndDate) return true;
if (taskDate < startOfFromDate) hasTasksBeforeReportingPeriod = true;
if (taskDate > endOfEndDate) hasTasksAfterReportingPeriod = true;
@@ -635,10 +635,10 @@ const organicCertifierSurveyController = {
SELECT DISTINCT p.name,
p.supplier,
pct.product_quantity,
- t.completed_time::date as date_used, CASE
- WHEN t.completed_time is null
- THEN t.due_date
- ELSE t.completed_time
+ t.complete_date::date as date_used, CASE
+ WHEN t.complete_date is null
+ THEN t.due_date
+ ELSE t.complete_date
END as date_used,
p.on_permitted_substances_list,
t.task_id
@@ -647,20 +647,18 @@ const organicCertifierSurveyController = {
JOIN product p ON p.product_id = pct.product_id
JOIN location_tasks tl ON t.task_id = tl.task_id
JOIN location l ON tl.location_id = l.location_id
- JOIN (
- SELECT location_id
- FROM field
- WHERE organic_status != 'Non-Organic'
- UNION
- SELECT location_id
- FROM greenhouse
- WHERE organic_status != 'Non-Organic'
- UNION
- SELECT location_id
- FROM garden
- WHERE organic_status != 'Non-Organic'
- ) lu ON lu.location_id = l.location_id
- WHERE ((completed_time::date <= :to_date::date AND completed_time::date >= :from_date::date) OR
+ JOIN (SELECT location_id
+ FROM field
+ WHERE organic_status != 'Non-Organic'
+ UNION
+ SELECT location_id
+ FROM greenhouse
+ WHERE organic_status != 'Non-Organic'
+ UNION
+ SELECT location_id
+ FROM garden
+ WHERE organic_status != 'Non-Organic') lu ON lu.location_id = l.location_id
+ WHERE ((complete_date::date <= :to_date::date AND complete_date::date >= :from_date::date) OR
(due_date::date <= :to_date::date AND due_date::date >= :from_date::date))
AND p.farm_id = :farm_id`,
{ to_date, from_date, farm_id },
@@ -674,9 +672,9 @@ const organicCertifierSurveyController = {
p.supplier,
pct.product_quantity,
CASE
- WHEN t.completed_time is null
+ WHEN t.complete_date is null
THEN t.due_date
- ELSE t.completed_time
+ ELSE t.complete_date
END as date_used,
p.on_permitted_substances_list,
t.task_id
@@ -685,38 +683,36 @@ const organicCertifierSurveyController = {
JOIN product p ON p.product_id = pct.product_id
JOIN location_tasks tl ON t.task_id = tl.task_id
JOIN location l ON tl.location_id = l.location_id
- JOIN (
- SELECT location_id
- FROM buffer_zone
- UNION
- SELECT location_id
- FROM water_valve
- UNION
- SELECT location_id
- FROM watercourse
- UNION
- SELECT location_id
- FROM barn
- UNION
- SELECT location_id
- FROM ceremonial_area
- UNION
- SELECT location_id
- FROM fence
- UNION
- SELECT location_id
- FROM gate
- UNION
- SELECT location_id
- FROM natural_area
- UNION
- SELECT location_id
- FROM surface_water
- UNION
- SELECT location_id
- FROM residence
- ) lu ON lu.location_id = l.location_id
- WHERE ((completed_time::date <= :to_date::date AND completed_time::date >= :from_date::date) OR
+ JOIN (SELECT location_id
+ FROM buffer_zone
+ UNION
+ SELECT location_id
+ FROM water_valve
+ UNION
+ SELECT location_id
+ FROM watercourse
+ UNION
+ SELECT location_id
+ FROM barn
+ UNION
+ SELECT location_id
+ FROM ceremonial_area
+ UNION
+ SELECT location_id
+ FROM fence
+ UNION
+ SELECT location_id
+ FROM gate
+ UNION
+ SELECT location_id
+ FROM natural_area
+ UNION
+ SELECT location_id
+ FROM surface_water
+ UNION
+ SELECT location_id
+ FROM residence) lu ON lu.location_id = l.location_id
+ WHERE ((complete_date::date <= :to_date::date AND complete_date::date >= :from_date::date) OR
(due_date::date <= :to_date::date AND due_date::date >= :from_date::date))
AND p.farm_id = :farm_id`,
{ to_date, from_date, farm_id },
diff --git a/packages/api/src/controllers/showedSpotlightController.js b/packages/api/src/controllers/showedSpotlightController.js
index 32f910b33b..6056dfd966 100644
--- a/packages/api/src/controllers/showedSpotlightController.js
+++ b/packages/api/src/controllers/showedSpotlightController.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (showedSpotlightController.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,22 +21,26 @@ const showedSpotlightController = {
return async (req, res) => {
try {
const { user_id } = req.user;
- const data = await showedSpotlightModel.query().select(
- 'map',
- 'draw_area',
- 'draw_line',
- 'drop_point',
- 'adjust_area',
- 'adjust_line',
- 'navigation',
- 'introduce_map',
- 'crop_catalog',
- 'crop_variety_detail',
- 'documents',
- 'compliance_docs_and_certification',
- 'transplant',
- 'management_plan_creation',
- ).findById(user_id);
+ const data = await showedSpotlightModel
+ .query()
+ .select(
+ 'map',
+ 'draw_area',
+ 'draw_line',
+ 'drop_point',
+ 'adjust_area',
+ 'adjust_line',
+ 'navigation',
+ 'notification',
+ 'introduce_map',
+ 'crop_catalog',
+ 'crop_variety_detail',
+ 'documents',
+ 'compliance_docs_and_certification',
+ 'transplant',
+ 'management_plan_creation',
+ )
+ .findById(user_id);
res.status(200).send(data);
} catch (error) {
//handle more exceptions
@@ -50,7 +54,12 @@ const showedSpotlightController = {
return async (req, res) => {
const { user_id } = req.user;
try {
- const isPatched = await baseController.updateIndividualById(showedSpotlightModel, user_id, req.body, req);
+ const isPatched = await baseController.updateIndividualById(
+ showedSpotlightModel,
+ user_id,
+ req.body,
+ req,
+ );
if (isPatched) {
return res.sendStatus(200);
} else {
diff --git a/packages/api/src/controllers/taskController.js b/packages/api/src/controllers/taskController.js
index 0b0f0a20d2..375fd6b2e6 100644
--- a/packages/api/src/controllers/taskController.js
+++ b/packages/api/src/controllers/taskController.js
@@ -1,118 +1,236 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
const TaskModel = require('../models/taskModel');
const userFarmModel = require('../models/userFarmModel');
const managementPlanModel = require('../models/managementPlanModel');
const managementTasksModel = require('../models/managementTasksModel');
const transplantTaskModel = require('../models/transplantTaskModel');
const plantTaskModel = require('../models/plantTaskModel');
-const plantingManagementPlanModel = require('../models/plantingManagementPlanModel');
const HarvestUse = require('../models/harvestUseModel');
+const NotificationUser = require('../models/notificationUserModel');
+const User = require('../models/userModel');
const { typesOfTask } = require('./../middleware/validation/task');
const adminRoles = [1, 2, 5];
+const isDateInPast = (date) => {
+ const today = new Date();
+ const newDate = new Date(date);
+ if (newDate.setUTCHours(0, 0, 0, 0) < today.setUTCHours(0, 0, 0, 0)) {
+ return true;
+ }
+ return false;
+};
const taskController = {
+ async assignTask(req, res) {
+ try {
+ const { task_id } = req.params;
+ const { farm_id } = req.headers;
+ const { user_id } = req.user;
+ const { assignee_user_id: newAssigneeUserId } = req.body;
+ const { assignee_user_id: oldAssigneeUserId, task_translation_key } = req.checkTaskStatus;
+
+ // Avoid 1) making an empty update, and 2) sending a redundant notification.
+ if (oldAssigneeUserId === newAssigneeUserId) return res.sendStatus(200);
+
+ const result = await TaskModel.assignTask(task_id, newAssigneeUserId, req.user);
+
+ if (!result) return res.status(404).send('Task not found');
+
+ await sendTaskReassignedNotifications(
+ task_id,
+ newAssigneeUserId,
+ oldAssigneeUserId,
+ task_translation_key,
+ farm_id,
+ user_id,
+ );
+
+ return res.sendStatus(200);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).json({ error });
+ }
+ },
- assignTask() {
- return async (req, res, next) => {
- try {
- const { task_id } = req.params;
- const { user_id } = req.headers;
- const { assignee_user_id } = req.body;
- if (!adminRoles.includes(req.role) && user_id !== assignee_user_id && assignee_user_id !== null) {
- return res.status(403).send('Not authorized to assign other people for this task');
- }
+ async assignAllTasksOnDate(req, res) {
+ try {
+ const { farm_id } = req.headers;
+ const { user_id } = req.user;
+ const { assignee_user_id: newAssigneeUserId, date } = req.body;
+ const {
+ assignee_user_id: oldAssigneeUserId,
+ task_translation_key: currentTaskTranslationKey,
+ } = req.checkTaskStatus;
+ const { task_id: current_task_id } = req.params;
+ const tasks = await getTasksForFarm(farm_id);
+ const taskIds = tasks.map(({ task_id }) => task_id);
+ let updatedTask;
+
+ // if the current task was not previously unassigned or assigned to the same user,
+ // assign the current task to newAssigneeUserId
+ if (oldAssigneeUserId !== null && oldAssigneeUserId !== newAssigneeUserId) {
+ updatedTask = await TaskModel.assignTask(current_task_id, newAssigneeUserId, req.user);
+
+ if (!updatedTask) return res.status(404).send('Task not found');
+
+ await sendTaskReassignedNotifications(
+ current_task_id,
+ newAssigneeUserId,
+ oldAssigneeUserId,
+ currentTaskTranslationKey,
+ farm_id,
+ user_id,
+ );
+ }
- const checkTaskStatus = await TaskModel.query().select('completed_time', 'abandoned_time').where({ task_id }).first();
- if (checkTaskStatus.completed_time || checkTaskStatus.abandoned_time) {
- return res.status(406).send('Task has already been completed or abandoned');
- }
- const result = await TaskModel.query().context(req.user).findById(task_id).patch({
- assignee_user_id,
- });
- return result ? res.sendStatus(200) : res.status(404).send('Task not found');
- } catch (error) {
- console.log(error);
- return res.status(400).json({ error });
+ // assign all other unassigned tasks due on this day to newAssigneeUserId
+ const available_tasks = await TaskModel.getAvailableTasksOnDate(taskIds, date, req.user);
+ const availableTaskIds = available_tasks.map(({ task_id }) => task_id);
+ const result = await TaskModel.assignTasks(availableTaskIds, newAssigneeUserId, req.user);
+ if (result) {
+ await Promise.all(
+ available_tasks.map(async (task) => {
+ await sendTaskNotification(
+ newAssigneeUserId,
+ null,
+ task.task_id,
+ TaskNotificationTypes.TASK_ASSIGNED,
+ task.task_translation_key,
+ farm_id,
+ );
+ }),
+ );
+ return res
+ .status(200)
+ .send(updatedTask ? [...available_tasks, updatedTask] : available_tasks);
}
- };
+ return res.status(404).send('Tasks not found');
+ } catch (error) {
+ return res.status(400).json({ error });
+ }
},
- assignAllTasksOnDate() {
- return async (req, res, next) => {
- try {
- const { user_id, farm_id } = req.headers;
- const { assignee_user_id, date } = req.body;
- if (!adminRoles.includes(req.role) && user_id !== assignee_user_id && assignee_user_id !== null) {
- return res.status(403).send('Not authorized to assign other people for this task');
- }
- const tasks = await getTasksForFarm(farm_id);
- const taskIds = tasks.map(({ task_id }) => task_id);
- let available_tasks = await TaskModel.query().context(req.user)
- .select('task_id')
- .where((builder) => {
- builder.where('due_date', date);
- builder.whereIn('task_id', taskIds);
- if (assignee_user_id !== null) {
- builder.where('assignee_user_id', null);
- }
- builder.where('completed_time', null);
- builder.where('abandoned_time', null);
- });
- available_tasks = available_tasks.map(({ task_id }) => task_id);
- const result = await TaskModel.query().context(req.user).patch({
- assignee_user_id,
- }).whereIn('task_id', available_tasks);
- return result ? res.status(200).send(available_tasks) : res.status(404).send('Tasks not found');
- } catch (error) {
- return res.status(400).json({ error });
+ async patchTaskDate(req, res) {
+ try {
+ const { task_id } = req.params;
+ const { due_date } = req.body;
+
+ //Ensure the task due date is not in the past
+ const isPast = await isDateInPast(due_date);
+ if (isPast) {
+ return res.status(400).send('Task due date must be today or in the future');
}
- };
+
+ //Ensure only adminRoles can modify task due date
+ if (!adminRoles.includes(req.role)) {
+ return res.status(403).send('Not authorized to change due date');
+ }
+
+ const result = await TaskModel.query()
+ .context(req.user)
+ .findById(task_id)
+ .patch({ due_date });
+ return result ? res.sendStatus(200) : res.status(404).send('Task not found');
+ } catch (error) {
+ console.log(error);
+ return res.status(400).json({ error });
+ }
},
- abandonTask() {
- return async (req, res, next) => {
- try {
- const { task_id } = req.params;
- const { user_id, farm_id } = req.headers;
- const { abandonment_reason, other_abandonment_reason, abandonment_notes, happiness, duration } = req.body;
-
- const { owner_user_id, assignee_user_id, wage_at_moment, override_hourly_wage } = await TaskModel.query()
- .select('owner_user_id', 'assignee_user_id', 'wage_at_moment', 'override_hourly_wage')
- .where({ task_id }).first();
- const isUserTaskOwner = user_id === owner_user_id;
- const isUserTaskAssignee = user_id === assignee_user_id;
- const hasAssignee = assignee_user_id !== null;
- // TODO: move to middleware
- // cannot abandon task if user is worker and not assignee and not creator
- if (!adminRoles.includes(req.role) && !isUserTaskOwner && !isUserTaskAssignee) {
- return res.status(403).send('A worker who is not assignee or owner of task cannot abandon it');
- }
- // cannot abandon an unassigned task with rating or duration
- if (!hasAssignee && (happiness || duration)) {
- return res.status(406).send('An unassigned task should not be rated or have time clocked');
- }
+ async abandonTask(req, res) {
+ try {
+ const { task_id } = req.params;
+ const { user_id, farm_id } = req.headers;
+ const {
+ abandonment_reason,
+ other_abandonment_reason,
+ abandonment_notes,
+ happiness,
+ duration,
+ abandon_date,
+ } = req.body;
+
+ const checkTaskStatus = await TaskModel.getTaskStatus(task_id);
+ if (checkTaskStatus.complete_date || checkTaskStatus.abandon_date) {
+ return res.status(400).send('Task has already been completed or abandoned');
+ }
- let wage = { amount: 0 };
- if (assignee_user_id) {
- const assigneeUserFarm = await userFarmModel.query().where({ user_id: assignee_user_id, farm_id }).first();
- wage = assigneeUserFarm.wage;
- }
+ const {
+ owner_user_id,
+ assignee_user_id,
+ wage_at_moment,
+ override_hourly_wage,
+ } = await TaskModel.query()
+ .select('owner_user_id', 'assignee_user_id', 'wage_at_moment', 'override_hourly_wage')
+ .where({ task_id })
+ .first();
+ const isUserTaskOwner = user_id === owner_user_id;
+ const isUserTaskAssignee = user_id === assignee_user_id;
+ const hasAssignee = assignee_user_id !== null;
+ // TODO: move to middleware
+ // cannot abandon task if user is worker and not assignee and not creator
+ if (!adminRoles.includes(req.role) && !isUserTaskOwner && !isUserTaskAssignee) {
+ return res
+ .status(403)
+ .send('A worker who is not assignee or owner of task cannot abandon it');
+ }
+ // cannot abandon an unassigned task with rating or duration
+ if (!hasAssignee && (happiness || duration)) {
+ return res.status(400).send('An unassigned task should not be rated or have time clocked');
+ }
+
+ let wage = { amount: 0 };
+ if (assignee_user_id) {
+ const assigneeUserFarm = await userFarmModel
+ .query()
+ .where({ user_id: assignee_user_id, farm_id })
+ .first();
+ wage = assigneeUserFarm.wage;
+ }
- const result = await TaskModel.query().context(req.user).findById(task_id).patch({
- abandoned_time: new Date(Date.now()),
+ const result = await TaskModel.query()
+ .context(req.user)
+ .findById(task_id)
+ .patch({
+ abandon_date,
abandonment_reason,
other_abandonment_reason,
abandonment_notes,
happiness,
duration,
wage_at_moment: override_hourly_wage ? wage_at_moment : wage.amount,
- }).returning('*');
- return result ? res.status(200).send(result) : res.status(404).send('Task not found');
- } catch (error) {
- console.log(error);
- return res.status(400).json({ error });
- }
- };
+ })
+ .returning('*');
+ if (!result) return res.status(404).send('Task not found');
+
+ await sendTaskNotification(
+ assignee_user_id,
+ user_id,
+ task_id,
+ TaskNotificationTypes.TASK_ABANDONED,
+ checkTaskStatus.task_translation_key,
+ farm_id,
+ );
+
+ return res.status(200).send(result);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).json({ error });
+ }
},
createTask(typeOfTask) {
@@ -124,22 +242,37 @@ const taskController = {
// after the validation middleware.
const data = req.body;
const { user_id } = req.user;
- data.planned_time = data.due_date;
data.owner_user_id = user_id;
- const result = await TaskModel.transaction(async trx => {
- const { task_id } = await TaskModel.query(trx).context({ user_id: req.user.user_id })
- .upsertGraph(req.body, {
+ const result = await TaskModel.transaction(async (trx) => {
+ const { task_id } = await TaskModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph(data, {
noUpdate: true,
noDelete: true,
noInsert: nonModifiable,
relate: ['locations', 'managementPlans'],
});
- const [task] = await TaskModel.query(trx).withGraphFetched(`
- [locations, managementPlans, taskType, soil_amendment_task, irrigation_task,scouting_task,
+ const [task] = await TaskModel.query(trx)
+ .withGraphFetched(
+ `
+ [locations, managementPlans, taskType, soil_amendment_task, irrigation_task,scouting_task,
field_work_task, cleaning_task, pest_control_task, soil_task, harvest_task, plant_task]
- `).where({ task_id });
+ `,
+ )
+ .where({ task_id });
return removeNullTypes(task);
});
+ if (result.assignee_user_id) {
+ const { assignee_user_id, task_id, taskType } = result;
+ await sendTaskNotification(
+ assignee_user_id,
+ null,
+ task_id,
+ TaskNotificationTypes.TASK_ASSIGNED,
+ taskType.task_translation_key,
+ req.headers.farm_id,
+ );
+ }
return res.status(201).send(result);
} catch (error) {
console.log(error);
@@ -148,82 +281,82 @@ const taskController = {
};
},
- createHarvestTasks() {
- const nonModifiable = getNonModifiable('harvest_task');
-
- return async (req, res, next) => {
- try {
- const harvest_tasks = req.body;
- const { farm_id } = req.headers;
- const { user_id } = req.user;
- //TODO: use cases of planned_time and due_date
-
- const result = await TaskModel.transaction(async trx => {
- const result = [];
- for (const harvest_task of harvest_tasks) {
- harvest_task.planned_time = harvest_task.due_date;
- harvest_task.owner_user_id = user_id;
- if (harvest_task.assignee_user_id && !harvest_task.wage_at_moment) {
- const { wage } = await userFarmModel.query().where({
+ async createHarvestTasks(req, res) {
+ try {
+ const nonModifiable = getNonModifiable('harvest_task');
+ const harvest_tasks = req.body;
+ const { farm_id } = req.headers;
+ const { user_id } = req.user;
+
+ const result = await TaskModel.transaction(async (trx) => {
+ const result = [];
+ for (const harvest_task of harvest_tasks) {
+ harvest_task.owner_user_id = user_id;
+ if (harvest_task.assignee_user_id && !harvest_task.wage_at_moment) {
+ const { wage } = await userFarmModel
+ .query()
+ .where({
user_id: harvest_task.assignee_user_id,
farm_id,
- }).first();
- harvest_task.wage_at_moment = wage.amount;
- }
-
- const task = await TaskModel.query(trx).context({ user_id: req.user.user_id })
- .upsertGraph(harvest_task, {
- noUpdate: true,
- noDelete: true,
- noInsert: nonModifiable,
- relate: ['locations', 'managementPlans'],
- });
- result.push(removeNullTypes(task));
+ })
+ .first();
+ harvest_task.wage_at_moment = wage.amount;
}
- return result;
- });
- return res.status(201).send(result);
- } catch (error) {
- console.log(error);
- return res.status(400).json({ error });
- }
- };
- },
- createTransplantTask() {
- const nonModifiable = getNonModifiable('transplant_task');
-
- return async (req, res, next) => {
- try {
- const transplant_task = req.body;
- const { farm_id } = req.headers;
- const { user_id } = req.user;
- //TODO: use cases of planned_time and due_date
-
- const result = await TaskModel.transaction(async trx => {
- transplant_task.planned_time = transplant_task.due_date;
- transplant_task.owner_user_id = user_id;
- if (transplant_task.assignee_user_id && !transplant_task.wage_at_moment) {
- const { wage } = await userFarmModel.query().where({
- user_id: transplant_task.assignee_user_id,
- farm_id,
- }).first();
- transplant_task.wage_at_moment = wage.amount;
- }
- //TODO: noInsert on planting_management_plan planting methods LF-1864
- return await TaskModel.query(trx).context({ user_id: req.user.user_id })
- .upsertGraph(transplant_task, {
+ const task = await TaskModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph(harvest_task, {
noUpdate: true,
noDelete: true,
noInsert: nonModifiable,
+ relate: ['locations', 'managementPlans'],
});
- });
- return res.status(201).send(result);
- } catch (error) {
- console.log(error);
- return res.status(400).json({ error });
- }
- };
+ // N.B. Notification not needed; these tasks are never assigned at creation.
+ result.push(removeNullTypes(task));
+ }
+ return result;
+ });
+ return res.status(201).send(result);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).json({ error });
+ }
+ },
+
+ async createTransplantTask(req, res) {
+ try {
+ const nonModifiable = getNonModifiable('transplant_task');
+ const transplant_task = req.body;
+ const { farm_id } = req.headers;
+ const { user_id } = req.user;
+
+ const result = await TaskModel.transaction(async (trx) => {
+ transplant_task.owner_user_id = user_id;
+ if (transplant_task.assignee_user_id && !transplant_task.wage_at_moment) {
+ const { wage } = await userFarmModel
+ .query()
+ .where({
+ user_id: transplant_task.assignee_user_id,
+ farm_id,
+ })
+ .first();
+ transplant_task.wage_at_moment = wage.amount;
+ }
+ //TODO: noInsert on planting_management_plan planting methods LF-1864
+ return await TaskModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph(transplant_task, {
+ noUpdate: true,
+ noDelete: true,
+ noInsert: nonModifiable,
+ });
+ });
+ // N.B. Notification not needed; these tasks are never assigned at creation.
+ return res.status(201).send(result);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).json({ error });
+ }
},
completeTask(typeOfTask) {
@@ -231,31 +364,52 @@ const taskController = {
return async (req, res, next) => {
try {
const data = req.body;
- const { user_id, farm_id } = req.headers;
+ const { farm_id } = req.headers;
+ const { user_id } = req.user;
const { task_id } = req.params;
- const { assignee_user_id, wage_at_moment, override_hourly_wage } = await TaskModel.query()
- .context(req.user)
- .findById(task_id);
- if (assignee_user_id !== user_id) {
- return res.status(403).send('Not authorized to complete other people\'s task');
+ const {
+ assignee_user_id,
+ assignee_role_id,
+ wage_at_moment,
+ override_hourly_wage,
+ } = await TaskModel.getTaskAssignee(task_id);
+ const { role_id } = await userFarmModel.getUserRoleId(user_id);
+ if (!canCompleteTask(assignee_user_id, assignee_role_id, user_id, role_id)) {
+ return res.status(403).send("Not authorized to complete other people's task");
}
- const { wage } = await userFarmModel.query().where({ user_id: assignee_user_id, farm_id }).first();
- const wagePatchData = override_hourly_wage ?
- { wage_at_moment } :
- { wage_at_moment: wage.amount };
- const result = await TaskModel.transaction(async trx => {
- const task = await TaskModel.query(trx).context({ user_id: req.user.user_id })
- .upsertGraph({ task_id: parseInt(task_id), ...data, ...wagePatchData }, {
- noUpdate: nonModifiable,
- noDelete: true,
- noInsert: true,
- });
+ const { wage } = await userFarmModel
+ .query()
+ .where({ user_id: assignee_user_id, farm_id })
+ .first();
+ const wagePatchData = override_hourly_wage
+ ? { wage_at_moment }
+ : { wage_at_moment: wage.amount };
+ const result = await TaskModel.transaction(async (trx) => {
+ const task = await TaskModel.query(trx)
+ .context({ user_id: req.user.user_id })
+ .upsertGraph(
+ { task_id: parseInt(task_id), ...data, ...wagePatchData },
+ {
+ noUpdate: nonModifiable,
+ noDelete: true,
+ noInsert: true,
+ },
+ );
await patchManagementPlanStartDate(trx, req, typeOfTask);
return task;
});
if (result) {
+ const taskType = await TaskModel.getTaskType(task_id);
+ await sendTaskNotification(
+ assignee_user_id,
+ user_id,
+ task_id,
+ TaskNotificationTypes.TASK_COMPLETED_BY_OTHER_USER,
+ taskType.task_translation_key,
+ farm_id,
+ );
return res.status(200).send(result);
} else {
return res.status(404).send('Task not found');
@@ -267,102 +421,120 @@ const taskController = {
};
},
-
- completeHarvestTask() {
- const nonModifiable = getNonModifiable('harvest_task');
- return async (req, res, next) => {
- try {
- const data = req.body;
- const { user_id } = req.headers;
- const task_id = parseInt(req.params.task_id);
- const { assignee_user_id } = await TaskModel.query().context(req.user).findById(task_id);
- if (assignee_user_id !== user_id) {
- return res.status(403).send('Not authorized to complete other people\'s task');
- }
- const harvest_uses = data.harvest_uses.map(harvest_use => ({ ...harvest_use, task_id }));
- const task = data.task;
-
-
- const result = await TaskModel.transaction(async trx => {
- const result = {};
- const updated_task = await TaskModel.query(trx).context({ user_id: req.user.user_id })
- .upsertGraph({ task_id: parseInt(task_id), ...task }, {
+ /**
+ * Records the completion of a harvest task, and information about the harvest's usage.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ */
+ async completeHarvestTask(req, res) {
+ try {
+ const nonModifiable = getNonModifiable('harvest_task');
+ const { user_id } = req.user;
+ const { farm_id } = req.headers;
+ const task_id = parseInt(req.params.task_id);
+ const { assignee_user_id, assignee_role_id } = await TaskModel.getTaskAssignee(task_id);
+ const { role_id } = await userFarmModel.getUserRoleId(user_id);
+ if (!canCompleteTask(assignee_user_id, assignee_role_id, user_id, role_id)) {
+ return res.status(403).send("Not authorized to complete other people's task");
+ }
+ const result = await TaskModel.transaction(async (trx) => {
+ const updated_task = await TaskModel.query(trx)
+ .context({ user_id })
+ .upsertGraph(
+ { task_id, ...req.body.task },
+ {
noUpdate: nonModifiable,
noDelete: true,
noInsert: true,
- });
- result.task = removeNullTypes(updated_task);
- const updated_harvest_uses = await HarvestUse.query(trx).context({ user_id: req.user.user_id })
- .insert(harvest_uses);
- result.harvest_uses = updated_harvest_uses;
- await patchManagementPlanStartDate(trx, req, 'harvest_task', req.body.task);
-
- return result;
- });
-
- if (Object.keys(result).length > 0) {
- return res.status(200).send(result);
- } else {
- return res.status(404).send('Task not found');
- }
- } catch (error) {
- console.log(error);
- return res.status(400).send({ error });
+ },
+ );
+ const result = removeNullTypes(updated_task);
+ delete result.harvest_task; // Not needed by front end.
+
+ // Write harvest uses to database.
+ const harvest_uses = req.body.harvest_uses.map((harvest_use) => ({
+ ...harvest_use,
+ task_id,
+ }));
+ await HarvestUse.query(trx).context({ user_id }).insert(harvest_uses);
+
+ await patchManagementPlanStartDate(trx, req, 'harvest_task', req.body.task);
+
+ return result;
+ });
+
+ if (Object.keys(result).length > 0) {
+ const { task_translation_key } = await TaskModel.getTaskType(task_id);
+ await sendTaskNotification(
+ assignee_user_id,
+ user_id,
+ task_id,
+ TaskNotificationTypes.TASK_COMPLETED_BY_OTHER_USER,
+ task_translation_key,
+ farm_id,
+ );
+ return res.status(200).send(result);
+ } else {
+ return res.status(404).send('Task not found');
}
- };
+ } catch (error) {
+ console.log(error);
+ return res.status(400).send({ error });
+ }
},
- getTasksByFarmId() {
- return async (req, res, next) => {
- const { farm_id } = req.params;
- try {
- const tasks = await getTasksForFarm(farm_id);
- const taskIds = tasks.map(({ task_id }) => task_id);
- const graphTasks = await TaskModel.query().whereNotDeleted().withGraphFetched(`
- [locations, managementPlans, soil_amendment_task, field_work_task, cleaning_task, pest_control_task, harvest_task.[harvest_use], plant_task, transplant_task]
- `).whereIn('task_id', taskIds);
- const filteredTasks = graphTasks.map(removeNullTypes);
- if (graphTasks) {
- res.status(200).send(filteredTasks);
- }
- } catch (error) {
- console.log(error);
- return res.status(400).send({ error });
-
+ async getTasksByFarmId(req, res) {
+ const { farm_id } = req.params;
+ try {
+ const tasks = await getTasksForFarm(farm_id);
+ const taskIds = tasks.map(({ task_id }) => task_id);
+ const graphTasks = await TaskModel.query()
+ .whereNotDeleted()
+ .withGraphFetched(
+ `[locations, managementPlans, soil_amendment_task, field_work_task, cleaning_task, pest_control_task,
+ harvest_task.[harvest_use], plant_task, transplant_task]
+ `,
+ )
+ .whereIn('task_id', taskIds);
+ const filteredTasks = graphTasks.map(removeNullTypes);
+ if (graphTasks) {
+ res.status(200).send(filteredTasks);
}
- };
+ } catch (error) {
+ console.log(error);
+ return res.status(400).send({ error });
+ }
},
- //TODO: evaluate getHarvestUsesByFarmId use cases
- getHarvestUsesByFarmId() {
- return async (req, res, next) => {
- const { farm_id } = req.params;
- try {
- const harvest_uses = await HarvestUse.query().select()
- .join('task', 'harvest_use.task_id', 'task.task_id')
- .join('location_tasks', 'location_tasks.task_id', 'task.task_id')
- .join('location', 'location.location_id', 'location_tasks.location_id')
- .where('location.farm_id', farm_id);
- if (harvest_uses) {
- return res.status(200).send(harvest_uses);
- }
- } catch (error) {
- console.log(error);
- return res.status(400).send({ error });
+ async getHarvestUsesByFarmId(req, res) {
+ const { farm_id } = req.params;
+ try {
+ const harvest_uses = await HarvestUse.query()
+ .select()
+ .join('task', 'harvest_use.task_id', 'task.task_id')
+ .join('location_tasks', 'location_tasks.task_id', 'task.task_id')
+ .join('location', 'location.location_id', 'location_tasks.location_id')
+ .where('location.farm_id', farm_id);
+ if (harvest_uses) {
+ return res.status(200).send(harvest_uses);
}
- };
+ } catch (error) {
+ console.log(error);
+ return res.status(400).send({ error });
+ }
},
-
};
//TODO: tests where location and management_plan inserts should fail
function getNonModifiable(asset) {
- const nonModifiableAssets = typesOfTask.filter(a => a !== asset);
- return ['createdByUser', 'updatedByUser', 'location', 'management_plan'].concat(nonModifiableAssets);
+ const nonModifiableAssets = typesOfTask.filter((a) => a !== asset);
+ return ['createdByUser', 'updatedByUser', 'location', 'management_plan'].concat(
+ nonModifiableAssets,
+ );
}
-function removeNullTypes(task, i, arr) {
+function removeNullTypes(task) {
const filtered = Object.keys(task)
.filter((k) => typesOfTask.includes(k))
.reduce((reducer, k) => ({ ...reducer, [k]: task[k] === null ? undefined : task[k] }), {});
@@ -372,48 +544,97 @@ function removeNullTypes(task, i, arr) {
//TODO: optimize after plant_task and transplant_task refactor
async function getTasksForFarm(farm_id) {
const [managementTasks, locationTasks, plantTasks, transplantTasks] = await Promise.all([
- TaskModel.query().select('task.task_id').whereNotDeleted()
+ TaskModel.query()
+ .select('task.task_id')
+ .whereNotDeleted()
.distinct('task.task_id')
.join('management_tasks', 'management_tasks.task_id', 'task.task_id')
- .join('planting_management_plan', 'management_tasks.planting_management_plan_id', 'planting_management_plan.planting_management_plan_id')
- .join('management_plan', 'planting_management_plan.management_plan_id', 'management_plan.management_plan_id')
+ .join(
+ 'planting_management_plan',
+ 'management_tasks.planting_management_plan_id',
+ 'planting_management_plan.planting_management_plan_id',
+ )
+ .join(
+ 'management_plan',
+ 'planting_management_plan.management_plan_id',
+ 'management_plan.management_plan_id',
+ )
.join('crop_variety', 'crop_variety.crop_variety_id', 'management_plan.crop_variety_id')
.where('crop_variety.farm_id', farm_id),
- TaskModel.query().select('task.task_id').whereNotDeleted()
+ TaskModel.query()
+ .select('task.task_id')
+ .whereNotDeleted()
.distinct('task.task_id')
.join('location_tasks', 'location_tasks.task_id', 'task.task_id')
.join('location', 'location.location_id', 'location_tasks.location_id')
.where('location.farm_id', farm_id),
- plantTaskModel.query().select('plant_task.task_id')
- .join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'plant_task.planting_management_plan_id')
- .join('management_plan', 'management_plan.management_plan_id', 'planting_management_plan. management_plan_id')
+ plantTaskModel
+ .query()
+ .select('plant_task.task_id')
+ .join(
+ 'planting_management_plan',
+ 'planting_management_plan.planting_management_plan_id',
+ 'plant_task.planting_management_plan_id',
+ )
+ .join(
+ 'management_plan',
+ 'management_plan.management_plan_id',
+ 'planting_management_plan. management_plan_id',
+ )
.join('crop_variety', 'crop_variety.crop_variety_id', 'management_plan.crop_variety_id')
.where('crop_variety.farm_id', farm_id),
- transplantTaskModel.query().select('transplant_task.task_id')
- .join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'transplant_task.planting_management_plan_id')
- .join('management_plan', 'management_plan.management_plan_id', 'planting_management_plan. management_plan_id')
+ transplantTaskModel
+ .query()
+ .select('transplant_task.task_id')
+ .join(
+ 'planting_management_plan',
+ 'planting_management_plan.planting_management_plan_id',
+ 'transplant_task.planting_management_plan_id',
+ )
+ .join(
+ 'management_plan',
+ 'management_plan.management_plan_id',
+ 'planting_management_plan. management_plan_id',
+ )
.join('crop_variety', 'crop_variety.crop_variety_id', 'management_plan.crop_variety_id')
.where('crop_variety.farm_id', farm_id),
-
]);
return [...managementTasks, ...locationTasks, ...plantTasks, ...transplantTasks];
}
async function getManagementPlans(task_id, typeOfTask) {
switch (typeOfTask) {
- case 'plant_task':
- return plantTaskModel.query()
- .join('planting_management_plan', 'plant_task.planting_management_plan_id', 'planting_management_plan.planting_management_plan_id')
- .where({ task_id }).select('*');
-
- case 'transplant_task':
- return transplantTaskModel.query()
- .join('planting_management_plan', 'transplant_task.planting_management_plan_id', 'planting_management_plan.planting_management_plan_id')
- .where({ task_id }).select('*');
- default:
- return managementTasksModel.query().select('planting_management_plan.management_plan_id')
- .join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'management_tasks.planting_management_plan_id')
- .where('task_id', task_id);
+ case 'plant_task':
+ return plantTaskModel
+ .query()
+ .join(
+ 'planting_management_plan',
+ 'plant_task.planting_management_plan_id',
+ 'planting_management_plan.planting_management_plan_id',
+ )
+ .where({ task_id })
+ .select('*');
+
+ case 'transplant_task':
+ return transplantTaskModel
+ .query()
+ .join(
+ 'planting_management_plan',
+ 'transplant_task.planting_management_plan_id',
+ 'planting_management_plan.planting_management_plan_id',
+ )
+ .where({ task_id })
+ .select('*');
+ default:
+ return managementTasksModel
+ .query()
+ .select('planting_management_plan.management_plan_id')
+ .join(
+ 'planting_management_plan',
+ 'planting_management_plan.planting_management_plan_id',
+ 'management_tasks.planting_management_plan_id',
+ )
+ .where('task_id', task_id);
}
}
@@ -422,10 +643,113 @@ async function patchManagementPlanStartDate(trx, req, typeOfTask, task = req.bod
const management_plans = await getManagementPlans(task_id, typeOfTask);
const management_plan_ids = management_plans.map(({ management_plan_id }) => management_plan_id);
if (management_plan_ids.length > 0) {
- await managementPlanModel.query(trx).context(req.user).patch({ start_date: task.completed_time })
+ await managementPlanModel
+ .query(trx)
+ .context(req.user)
+ .patch({ start_date: task.complete_date })
.whereIn('management_plan_id', management_plan_ids)
- .where('start_date', null).returning('*');
+ .where('start_date', null)
+ .returning('*');
}
}
+const TaskNotificationTypes = {
+ TASK_ASSIGNED: 'TASK_ASSIGNED',
+ TASK_ABANDONED: 'TASK_ABANDONED',
+ TASK_REASSIGNED: 'TASK_REASSIGNED',
+ TASK_COMPLETED_BY_OTHER_USER: 'TASK_COMPLETED_BY_OTHER_USER',
+};
+
+const TaskNotificationUserTypes = {
+ TASK_ASSIGNED: 'assignee',
+ TASK_ABANDONED: 'abandoner',
+ TASK_REASSIGNED: 'assigner',
+ TASK_COMPLETED_BY_OTHER_USER: 'assigner',
+};
+
+async function sendTaskNotification(
+ receiverId,
+ senderId,
+ taskId,
+ notifyTranslationKey,
+ taskTranslationKey,
+ farmId,
+) {
+ if (!receiverId) return;
+
+ const userName = await User.getNameFromUserId(senderId ? senderId : receiverId);
+ await NotificationUser.notify(
+ {
+ title: {
+ translation_key: `NOTIFICATION.${TaskNotificationTypes[notifyTranslationKey]}.TITLE`,
+ },
+ body: { translation_key: `NOTIFICATION.${TaskNotificationTypes[notifyTranslationKey]}.BODY` },
+ variables: [
+ { name: 'taskType', value: `task:${taskTranslationKey}`, translate: true },
+ {
+ name: TaskNotificationUserTypes[notifyTranslationKey],
+ value: userName,
+ translate: false,
+ },
+ ],
+ ref: { entity: { type: 'task', id: taskId } },
+ context: { task_translation_key: taskTranslationKey },
+ farm_id: farmId,
+ },
+ [receiverId],
+ );
+}
+
+/**
+ * Sends notifications to the new assignee and old assignee of a task that was reassigned
+ * @param taskId {uuid} - uuid of the task
+ * @param newAssigneeUserId {uuid} - uuid of the user who is being assigned the task
+ * @param oldAssigneeUserId {uuid} - uuid of the user was previously assigned the task
+ * @param taskTranslationKey {String} - a key for translating languages
+ * @param farmId {uuid} - uuid of the farm
+ * @param assignerUserId - {uuid} uuid of the user who assigned the task
+ */
+async function sendTaskReassignedNotifications(
+ taskId,
+ newAssigneeUserId,
+ oldAssigneeUserId,
+ taskTranslationKey,
+ farmId,
+ assignerUserId,
+) {
+ await Promise.all([
+ sendTaskNotification(
+ newAssigneeUserId,
+ null,
+ taskId,
+ TaskNotificationTypes.TASK_ASSIGNED,
+ taskTranslationKey,
+ farmId,
+ ),
+ sendTaskNotification(
+ oldAssigneeUserId,
+ assignerUserId,
+ taskId,
+ TaskNotificationTypes.TASK_REASSIGNED,
+ taskTranslationKey,
+ farmId,
+ ),
+ ]);
+}
+
+/**
+ * Checks if the current user can complete the task.
+ * @param assigneeUserId {uuid} - uuid of the task assignee
+ * @param assigneeRoleId {number} - role id of assignee
+ * @param userId {uuid} - uuid of the user completing the task
+ * @param userRoleId {number} - role of the user completing the task
+ * @returns {boolean}
+ */
+function canCompleteTask(assigneeUserId, assigneeRoleId, userId, userRoleId) {
+ const isAdmin = adminRoles.includes(userRoleId);
+ // 4 is worker without account aka pseudo user
+ return assigneeUserId === userId || (assigneeRoleId === 4 && isAdmin);
+}
+
module.exports = taskController;
+module.exports.getTasksForFarm = getTasksForFarm;
diff --git a/packages/api/src/controllers/timeNotificationController.js b/packages/api/src/controllers/timeNotificationController.js
new file mode 100644
index 0000000000..1ffd0bd080
--- /dev/null
+++ b/packages/api/src/controllers/timeNotificationController.js
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const UserFarmModel = require('../models/userFarmModel');
+const TaskModel = require('../models/taskModel');
+const NotificationUser = require('../models/notificationUserModel');
+const { getTasksForFarm } = require('./taskController');
+
+const timeNotificationController = {
+ /**
+ * Notifies farm management of unassigned tasks due this week.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ * @async
+ */
+ async postWeeklyUnassignedTasks(req, res) {
+ const { farm_id } = req.params;
+ const { isDayLaterThanUtc } = req.body;
+
+ try {
+ // All unassigned tasks at the farm associated with farm_id due this week that are
+ // not completed or abandoned
+ const tasksFromFarm = await getTasksForFarm(farm_id);
+ const taskIds = tasksFromFarm.map(({ task_id }) => task_id);
+
+ const unassignedTasks = await TaskModel.getUnassignedTasksDueThisWeekFromIds(
+ taskIds,
+ isDayLaterThanUtc,
+ );
+ const farmManagementObjs = await UserFarmModel.getFarmManagementByFarmId(farm_id);
+
+ const farmManagement = farmManagementObjs.map(
+ (farmManagementObj) => farmManagementObj.user_id,
+ );
+
+ if (unassignedTasks.length > 0 && farmManagement.length > 0) {
+ await sendWeeklyUnassignedTaskNotifications(farm_id, farmManagement, isDayLaterThanUtc);
+ }
+
+ const status = unassignedTasks.length > 0 && farmManagement.length > 0 ? 201 : 200;
+ return res
+ .status(status)
+ .send(`${status === 201 ? farmManagement.length : 0} notifications sent.`);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).send({ error });
+ }
+ },
+
+ /**
+ * Notifies all users of a specified farm of tasks due today
+ * @param {Request} req request
+ * @param {Response} res response
+ * @async
+ */
+ async postDailyDueTodayTasks(req, res) {
+ const { farm_id } = req.params;
+ const { isDayLaterThanUtc } = req.body;
+ try {
+ let notificationsSent = 0;
+ const activeUsers = await UserFarmModel.getActiveUsersFromFarmId(farm_id);
+ const tasksFromFarm = await getTasksForFarm(farm_id);
+ const taskIdsFromFarm = tasksFromFarm.map(({ task_id }) => task_id);
+
+ for (const { user_id } of activeUsers) {
+ const hasTasksDueToday = await TaskModel.hasTasksDueTodayForUserFromFarm(
+ user_id,
+ taskIdsFromFarm,
+ isDayLaterThanUtc,
+ );
+
+ if (hasTasksDueToday) {
+ await sendDailyDueTodayTaskNotification(farm_id, user_id);
+ notificationsSent++;
+ }
+ }
+ return res
+ .status(notificationsSent ? 201 : 200)
+ .send(`${notificationsSent} notifications sent.`);
+ } catch (error) {
+ console.log(error);
+ return res.status(400).send({ error });
+ }
+ },
+};
+
+/**
+ * Notifies farm management of unassigned tasks due this week.
+ * @param {String} farmId - id of the farm the farm managers belong to
+ * @param {Array} farmManagement - user_ids of FM/FO/EO that need to be notified
+ * @param {String} firstTaskTranslationKey - task translation key of the first unassigned task
+ * @async
+ */
+async function sendWeeklyUnassignedTaskNotifications(farmId, farmManagement, isDayLaterThanUtc) {
+ const today = new Date();
+ if (isDayLaterThanUtc) today.setDate(today.getDate() + 1);
+ const todayStr = today.toISOString().split('T')[0];
+ await NotificationUser.notify(
+ {
+ title: { translation_key: 'NOTIFICATION.WEEKLY_UNASSIGNED_TASKS.TITLE' },
+ body: { translation_key: 'NOTIFICATION.WEEKLY_UNASSIGNED_TASKS.BODY' },
+ variables: [],
+ ref: { url: '/tasks' },
+ context: {
+ task_translation_key: 'FIELD_WORK_TASK',
+ notification_type: 'WEEKLY_UNASSIGNED_TASKS',
+ notification_date: todayStr,
+ },
+ farm_id: farmId,
+ },
+ farmManagement,
+ );
+}
+
+/**
+ * Sends notification to a user of tasks due today
+ * @param {String} farmId
+ * @param {String} userId
+ * @async
+ */
+async function sendDailyDueTodayTaskNotification(farmId, userId, isDayLaterThanUtc) {
+ const today = new Date();
+ if (isDayLaterThanUtc) today.setDate(today.getDate() + 1);
+ const todayStr = today.toISOString().split('T')[0];
+ await NotificationUser.notify(
+ {
+ title: { translation_key: 'NOTIFICATION.DAILY_TASKS_DUE_TODAY.TITLE' },
+ body: { translation_key: 'NOTIFICATION.DAILY_TASKS_DUE_TODAY.BODY' },
+ variables: [],
+ ref: { url: '/tasks' },
+ context: {
+ task_translation_key: 'FIELD_WORK_TASK',
+ notification_type: 'DAILY_TASKS_DUE_TODAY',
+ notification_date: todayStr,
+ },
+ farm_id: farmId,
+ },
+ [userId],
+ );
+}
+
+module.exports = timeNotificationController;
diff --git a/packages/api/src/controllers/userController.js b/packages/api/src/controllers/userController.js
index e15036a9f0..93eae55d76 100644
--- a/packages/api/src/controllers/userController.js
+++ b/packages/api/src/controllers/userController.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (userController.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,101 +23,224 @@ const farmModel = require('../models/farmModel');
const { transaction, Model } = require('objection');
const bcrypt = require('bcryptjs');
const { createToken } = require('../util/jwt');
-const { sendEmailTemplate, emails, sendEmail } = require('../templates/sendEmailTemplate');
+const { emails, sendEmail } = require('../templates/sendEmailTemplate');
const showedSpotlightModel = require('../models/showedSpotlightModel');
-
const userController = {
- addUser() {
- return async (req, res) => {
- const { email, first_name, last_name, password, gender, birth_year, language_preference } = req.body;
- const userData = {
- email,
- first_name,
- last_name,
- gender,
- birth_year,
- language_preference,
- };
+ async addUser(req, res) {
+ const {
+ email,
+ first_name,
+ last_name,
+ password,
+ gender,
+ birth_year,
+ language_preference,
+ } = req.body;
+ const userData = {
+ email,
+ first_name,
+ last_name,
+ gender,
+ birth_year,
+ language_preference,
+ };
+ const trx = await transaction.start(Model.knex());
+ try {
+ // hash password
+ const salt = await bcrypt.genSalt(10);
+ const password_hash = await bcrypt.hash(password, salt);
- const trx = await transaction.start(Model.knex());
- try {
- // hash password
- const salt = await bcrypt.genSalt(10);
- const password_hash = await bcrypt.hash(password, salt);
+ // persist user data
+ const userResult = await baseController.post(userModel, userData, req, { trx });
- // persist user data
- const userResult = await baseController.post(userModel, userData, req, { trx });
+ const { user_id } = userResult;
- const { user_id } = userResult;
+ const pwData = {
+ user_id,
+ password_hash,
+ };
+ await baseController.post(passwordModel, pwData, req, { trx });
+ await baseController.post(showedSpotlightModel, { user_id }, req, { trx });
+ await trx.commit();
+
+ // generate token, set to last a week
+ const id_token = await createToken('access', { user_id: userResult.user_id });
- const pwData = {
- user_id,
- password_hash,
+ // send welcome email
+ try {
+ const template_path = emails.WELCOME;
+ const replacements = {
+ first_name: userResult.first_name,
+ locale: language_preference,
};
- const pwResult = await baseController.post(passwordModel, pwData, req, { trx });
- const ssResult = await baseController.post(showedSpotlightModel, { user_id }, req, { trx });
- await trx.commit();
+ const sender = 'system@litefarm.org';
+ if (userResult.email && template_path) {
+ await sendEmail(template_path, replacements, userResult.email, { sender });
+ }
+ } catch (e) {
+ console.log('Failed to send email: ', e);
+ }
- // generate token, set to last a week
- const id_token = await createToken('access', { user_id: userResult.user_id });
+ // send token and user data (sans password hash)
+ return res.status(201).send({
+ id_token,
+ user: userResult,
+ });
+ } catch (error) {
+ // handle more exceptions
+ await trx.rollback();
+ return res.status(400).json({
+ error,
+ });
+ }
+ },
- // send welcome email
- try {
- const template_path = emails.WELCOME;
- const replacements = {
- first_name: userResult.first_name,
- locale: language_preference,
- };
- const sender = 'system@litefarm.org';
- if (userResult.email && template_path) {
- sendEmail(template_path, replacements, userResult.email, { sender });
- }
- } catch (e) {
- console.log('Failed to send email: ', e);
+ async addInvitedUser(req, res) {
+ const {
+ last_name,
+ email: reqEmail,
+ farm_id,
+ role_id,
+ wage,
+ gender,
+ birth_year,
+ phone_number,
+ language,
+ } = req.body;
+ let { first_name } = req.body;
+ const { type: wageType, amount: wageAmount } = wage || {};
+ wage.amount = wageAmount ? wageAmount : 0;
+ const email = reqEmail && reqEmail.toLowerCase();
+ /* Start of input validation */
+ const requiredProps = {
+ email,
+ first_name,
+ farm_id,
+ role_id,
+ };
+
+ if (Object.keys(requiredProps).some((key) => !requiredProps[key])) {
+ const errorMessageTitle = 'Missing Properties: ';
+ const errorMessage = Object.keys(requiredProps).reduce((missingPropMsg, key) => {
+ if (!requiredProps[key]) {
+ const concatMsg = [missingPropMsg, key];
+ return missingPropMsg === errorMessageTitle
+ ? concatMsg.join('') // to avoid prepending first item in list with comma
+ : concatMsg.join(', ');
}
+ return missingPropMsg;
+ }, errorMessageTitle);
+ return res.status(400).send(errorMessage);
+ }
- // send token and user data (sans password hash)
- return res.status(201).send({
- id_token,
- user: userResult,
- });
- } catch (error) {
- // handle more exceptions
- await trx.rollback();
- return res.status(400).json({
- error,
- });
- }
- };
- },
+ const validEmailRegex = RegExp(/^$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
+ if (!validEmailRegex.test(email)) {
+ return res.status(400).send('Invalid email');
+ }
+
+ const validWageRegex = RegExp(/^$|^[0-9]\d*(?:\.\d{1,2})?$/i);
+ if (wage && wageAmount && !validWageRegex.test(wageAmount)) {
+ return res.status(400).send('Invalid wage amount');
+ }
- addInvitedUser() {
- return async (req, res) => {
- const {
- last_name,
- email: reqEmail,
+ if (wage && wageType && wageType.toLowerCase() !== 'hourly') {
+ return res.status(400).send('Current app version only allows hourly wage');
+ }
+
+ console.log('Checking if user is created');
+ const isUserAlreadyCreated = await userModel.getUserByEmail(email);
+ const created_user_id = isUserAlreadyCreated ? isUserAlreadyCreated.user_id : null;
+ console.log('Checking if user is on farm');
+ const userExistOnThisFarm = await userFarmModel.checkIfUserExistsOnFarm(
+ created_user_id,
+ farm_id,
+ );
+
+ if (userExistOnThisFarm) {
+ res.status(400).send({ error: 'User already exists on this farm' });
+ return;
+ }
+ const { farm_name } = await farmModel.query().where('farm_id', farm_id).first();
+ const trx = await transaction.start(Model.knex());
+ try {
+ let user;
+ if (!isUserAlreadyCreated) {
+ user = await baseController.post(
+ userModel,
+ {
+ email,
+ first_name,
+ last_name,
+ status_id: 2,
+ gender,
+ birth_year,
+ phone_number,
+ },
+ req,
+ { trx },
+ );
+ } else {
+ user = isUserAlreadyCreated;
+ first_name = user.first_name;
+ }
+ const { user_id } = user;
+ await userFarmModel.query(trx).insert({
+ user_id,
farm_id,
+ status: 'Invited',
+ consent_version: '1.0',
role_id,
wage,
- gender,
- birth_year,
- phone_number,
- } = req.body;
- let { first_name } = req.body;
+ has_consent: false,
+ step_one: true,
+ step_two: true,
+ step_three: false,
+ step_four: true,
+ step_five: true,
+ });
+ const userFarm = await userFarmModel.getUserFarmByEmail(email, farm_id, trx);
+ await trx.commit();
+ res.status(201).send({ ...user, ...userFarm });
+ try {
+ const { language_preference } = isUserAlreadyCreated ?? { language_preference: language };
+ await emailTokenModel.createTokenSendEmail(
+ {
+ email,
+ first_name,
+ last_name,
+ gender,
+ birth_year,
+ language_preference,
+ },
+ userFarm,
+ farm_name,
+ );
+ } catch (e) {
+ console.error('Failed to send email', e);
+ }
+ } catch (error) {
+ await trx.rollback();
+ return res.status(400).send(error);
+ }
+ },
+
+ async addPseudoUser(req, res) {
+ const trx = await transaction.start(Model.knex());
+ try {
+ const { user_id, farm_id, first_name, wage, email } = req.body;
const { type: wageType, amount: wageAmount } = wage || {};
- wage.amount = wageAmount ? wageAmount : 0;
- const email = reqEmail && reqEmail.toLowerCase();
+
/* Start of input validation */
const requiredProps = {
- email,
- first_name,
+ user_id,
farm_id,
- role_id,
+ first_name,
+ email,
};
- if (Object.keys(requiredProps).some(key => !requiredProps[key])) {
+ if (Object.keys(requiredProps).some((key) => !requiredProps[key])) {
const errorMessageTitle = 'Missing Properties: ';
const errorMessage = Object.keys(requiredProps).reduce((missingPropMsg, key) => {
if (!requiredProps[key]) {
@@ -128,421 +251,292 @@ const userController = {
}
return missingPropMsg;
}, errorMessageTitle);
+ await trx.rollback();
return res.status(400).send(errorMessage);
}
- const validEmailRegex = RegExp(/^$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
- if (!validEmailRegex.test(email)) {
- return res.status(400).send('Invalid email');
+ if (email !== `${user_id}@pseudo.com`) {
+ await trx.rollback();
+ return res.status(400).send('Invalid pseudo user email');
}
const validWageRegex = RegExp(/^$|^[0-9]\d*(?:\.\d{1,2})?$/i);
if (wage && wageAmount && !validWageRegex.test(wageAmount)) {
+ await trx.rollback();
return res.status(400).send('Invalid wage amount');
}
if (wage && wageType && wageType.toLowerCase() !== 'hourly') {
- return res.status(400).send('Current app version only allows hourly wage');
- }
-
- const isUserAlreadyCreated = await userModel.query().where('email', email).first();
- const created_user_id = isUserAlreadyCreated ? isUserAlreadyCreated.user_id : null;
- const userExistOnThisFarm = await userFarmModel.query()
- .where('user_id', created_user_id).andWhere('farm_id', farm_id).first();
-
- if (userExistOnThisFarm) {
- res.status(400).send({ error: 'User already exists on this farm' });
- return;
- }
- const { farm_name } = await farmModel.query().where('farm_id', farm_id).first();
- const trx = await transaction.start(Model.knex());
- try {
- let user;
- if (!isUserAlreadyCreated) {
- user = await baseController.post(userModel, {
- email,
- first_name,
- last_name,
- status_id: 2,
- gender,
- birth_year,
- phone_number,
- }, req, { trx });
- } else {
- user = isUserAlreadyCreated;
- first_name = user.first_name;
- }
- const { user_id } = user;
- await userFarmModel.query(trx).insert({
- user_id,
- farm_id,
- status: 'Invited',
- consent_version: '1.0',
- role_id,
- wage,
- has_consent: false,
- step_one: true,
- step_two: true,
- step_three: false,
- step_four: true,
- step_five: true,
- });
- const userFarm = await userFarmModel.query(trx)
- .join('users', 'userFarm.user_id', '=', 'users.user_id')
- .join('farm', 'farm.farm_id', '=', 'userFarm.farm_id')
- .join('role', 'userFarm.role_id', '=', 'role.role_id')
- .where({ 'users.email': email, 'userFarm.farm_id': farm_id }).first()
- .select('*');
- await trx.commit();
- res.status(201).send({ ...user, ...userFarm });
- try {
- const { language_preference } = await userModel.query().findById(req.user.user_id);
-
- await this.createTokenSendEmail({
- email,
- first_name,
- last_name,
- gender,
- birth_year,
- language_preference,
- }, userFarm, farm_name);
- } catch (e) {
- console.error('Failed to send email', e);
- }
- } catch (error) {
await trx.rollback();
- return res.status(400).send(error);
+ return res.status(400).send('Current app version only allows hourly wage');
}
- };
+ /* End of input validation */
+ await baseController.post(userModel, req.body, req, { trx });
+ await userFarmModel.query(trx).insert({
+ user_id,
+ farm_id,
+ status: 'Active',
+ consent_version: '1.0',
+ role_id: 4,
+ wage,
+ step_one: true,
+ step_two: true,
+ step_three: true,
+ step_four: true,
+ step_five: true,
+ });
+ const userFarm = await userFarmModel
+ .query(trx)
+ .join('users', 'userFarm.user_id', '=', 'users.user_id')
+ .join('farm', 'farm.farm_id', '=', 'userFarm.farm_id')
+ .join('role', 'userFarm.role_id', '=', 'role.role_id')
+ .where({ 'users.email': email, 'userFarm.farm_id': farm_id })
+ .first()
+ .select('*');
+ await trx.commit();
+ res.status(201).send(userFarm);
+ } catch (error) {
+ // handle more exceptions
+ await trx.rollback();
+ res.status(400).json({
+ error,
+ });
+ }
},
- async createTokenSendEmail(user, userFarm, farm_name) {
- let token;
- const emailSent = await emailTokenModel.query().where({
- user_id: userFarm.user_id,
- farm_id: userFarm.farm_id,
- }).first();
- if (!emailSent || emailSent.times_sent < 3) {
- const timesSent = emailSent && emailSent.times_sent ? ++emailSent.times_sent : 1;
- if (timesSent === 1) {
- const emailToken = await emailTokenModel.query().insert({
- user_id: userFarm.user_id,
- farm_id: userFarm.farm_id,
- times_sent: timesSent,
- }).returning('*');
- token = await createToken('invite', { ...user, ...userFarm, invitation_id: emailToken.invitation_id });
+ async getUserByID(req, res) {
+ try {
+ const id = req.params.user_id;
+
+ const data = await userModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .findById(id)
+ .select(
+ 'first_name',
+ 'last_name',
+ 'profile_picture',
+ 'email',
+ 'phone_number',
+ 'user_id',
+ 'gender',
+ 'birth_year',
+ );
+
+ if (!data) {
+ res.sendStatus(404);
} else {
- const [emailToken] = await emailTokenModel.query().patch({ times_sent: timesSent }).where({
- user_id: user.user_id,
- farm_id: userFarm.farm_id,
- }).returning('*');
- token = await createToken('invite', { ...user, ...userFarm, invitation_id: emailToken.invitation_id });
+ res.status(200).send(data);
}
- await this.sendTokenEmail(farm_name, user, token);
+ } catch (error) {
+ //handle more exceptions
+ console.log(error);
+ res.status(400).send(error);
}
},
- async sendTokenEmail(farm, user, token) {
- const sender = 'system@litefarm.org';
- const template_path = emails.INVITATION;
- sendEmail(template_path, { first_name: user.first_name, farm, locale: user.language_preference, farm_name: farm },
- user.email, { sender, buttonLink: `/callback/?invite_token=${token}` });
- },
-
- addPseudoUser() {
- // Add pseudo user endpoint
- return async (req, res) => {
- const trx = await transaction.start(Model.knex());
- try {
- const { user_id, farm_id, first_name, last_name, wage, email } = req.body;
- const { type: wageType, amount: wageAmount } = wage || {};
-
- /* Start of input validation */
- const requiredProps = {
- user_id,
- farm_id,
- first_name,
- email,
- };
-
- if (Object.keys(requiredProps).some((key) => !requiredProps[key])) {
- const errorMessageTitle = 'Missing Properties: ';
- const errorMessage = Object.keys(requiredProps).reduce((missingPropMsg, key) => {
- if (!requiredProps[key]) {
- const concatMsg = [missingPropMsg, key];
- return missingPropMsg === errorMessageTitle
- ? concatMsg.join('') // to avoid prepending first item in list with comma
- : concatMsg.join(', ');
- }
- return missingPropMsg;
- }, errorMessageTitle);
- await trx.rollback();
- return res.status(400).send(errorMessage);
- }
-
- if (email !== `${user_id}@pseudo.com`) {
- await trx.rollback();
- return res.status(400).send('Invalid pseudo user email');
- }
-
- const validWageRegex = RegExp(/^$|^[0-9]\d*(?:\.\d{1,2})?$/i);
- if (wage && wageAmount && !validWageRegex.test(wageAmount)) {
- await trx.rollback();
- return res.status(400).send('Invalid wage amount');
- }
-
- if (wage && wageType && wageType.toLowerCase() !== 'hourly') {
- await trx.rollback();
- return res.status(400).send('Current app version only allows hourly wage');
- }
- /* End of input validation */
-
- const user = await baseController.post(userModel, req.body, req, { trx });
- await userFarmModel.query(trx).insert({
- user_id,
- farm_id,
- status: 'Active',
- consent_version: '1.0',
- role_id: 4,
- wage,
- step_one: true,
- step_two: true,
- step_three: true,
- step_four: true,
- step_five: true,
- });
- const userFarm = await userFarmModel.query(trx)
- .join('users', 'userFarm.user_id', '=', 'users.user_id')
- .join('farm', 'farm.farm_id', '=', 'userFarm.farm_id')
- .join('role', 'userFarm.role_id', '=', 'role.role_id')
- .where({ 'users.email': email, 'userFarm.farm_id': farm_id }).first()
- .select('*');
- await trx.commit();
- res.status(201).send(userFarm);
- } catch (error) {
- // handle more exceptions
- await trx.rollback();
- res.status(400).json({
- error,
- });
- }
- };
- },
-
- getUserByID() {
- return async (req, res) => {
- try {
- const id = req.params.user_id;
-
- const data = await userModel.query().context({ user_id: req.user.user_id }).findById(id)
- .select('first_name', 'last_name', 'profile_picture', 'email', 'phone_number', 'user_id', 'gender', 'birth_year');
-
- if (!data) {
- res.sendStatus(404);
- } else {
- res.status(200).send(data);
- }
- } catch (error) {
- //handle more exceptions
- console.log(error);
- res.status(400).send(error);
- }
- };
- },
-
-
- deactivateUser() {
- return async (req, res) => {
- const user_id = req.params.id;
- const template_path = emails.ACCESS_REVOKE;
- const trx = await transaction.start(Model.knex());
- try {
- const rows = await userFarmModel
- .query()
- .select('*')
- .where('userFarm.user_id', user_id)
- .leftJoin('role', 'userFarm.role_id', 'role.role_id')
- .leftJoin('users', 'userFarm.user_id', 'users.user_id')
- .leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
- const replacements = {
- first_name: rows[0].first_name,
- farm: rows[0].farm_name,
- locale: rows[0].language_preference,
- farm_name: rows[0].farm_name,
- };
- const sender = 'help@litefarm.org';
- const isUserFarmPatched = await userFarmModel.query(trx).where('user_id', user_id).patch({
- status: 'Inactive',
- });
- await trx.commit();
- if (isUserFarmPatched) {
- res.sendStatus(200);
- //send email informing user their access revoked (unless user is no account worker - no email)
- try {
- if (rows[0].email) {
- sendEmail(
- template_path,
- replacements,
- rows[0].email,
- { sender },
- );
- }
- } catch (e) {
- console.log(e);
+ async deactivateUser(req, res) {
+ const user_id = req.params.id;
+ const template_path = emails.ACCESS_REVOKE;
+ const trx = await transaction.start(Model.knex());
+ try {
+ const rows = await userFarmModel
+ .query()
+ .select('*')
+ .where('userFarm.user_id', user_id)
+ .leftJoin('role', 'userFarm.role_id', 'role.role_id')
+ .leftJoin('users', 'userFarm.user_id', 'users.user_id')
+ .leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
+ const replacements = {
+ first_name: rows[0].first_name,
+ farm: rows[0].farm_name,
+ locale: rows[0].language_preference,
+ farm_name: rows[0].farm_name,
+ };
+ const sender = 'help@litefarm.org';
+ const isUserFarmPatched = await userFarmModel.query(trx).where('user_id', user_id).patch({
+ status: 'Inactive',
+ });
+ await trx.commit();
+ if (isUserFarmPatched) {
+ res.sendStatus(200);
+ //send email informing user their access revoked (unless user is no account worker - no email)
+ try {
+ if (rows[0].email) {
+ await sendEmail(template_path, replacements, rows[0].email, { sender });
}
- } else {
- res.sendStatus(404);
+ } catch (e) {
+ console.log(e);
}
- } catch (error) {
- await trx.rollback();
- res.status(400).json({
- error,
- });
+ } else {
+ res.sendStatus(404);
}
- };
+ } catch (error) {
+ await trx.rollback();
+ res.status(400).json({
+ error,
+ });
+ }
},
- updateConsent() {
- return async (req, res) => {
- const trx = await transaction.start(Model.knex());
- const user_id = req.params.id;
- try {
- const updated = await userModel.query(trx).where('user_id', user_id).patch({
- has_consent: true,
- });
- await trx.commit();
- if (!updated) {
- res.status(409).send('Update failed');
- } else {
- res.sendStatus(200);
- }
- } catch (error) {
- await trx.rollback();
- res.status(400).send(error);
+ async updateConsent(req, res) {
+ const trx = await transaction.start(Model.knex());
+ const user_id = req.params.id;
+ try {
+ const updated = await userModel.query(trx).where('user_id', user_id).patch({
+ has_consent: true,
+ });
+ await trx.commit();
+ if (!updated) {
+ res.status(409).send('Update failed');
+ } else {
+ res.sendStatus(200);
}
- };
+ } catch (error) {
+ await trx.rollback();
+ res.status(400).send(error);
+ }
},
- updateUser() {
- return async (req, res) => {
- const trx = await transaction.start(Model.knex());
- try {
- delete req.body.status_id;
- const updated = await baseController.put(userModel, req.params.user_id, req.body, req, { trx });
- await trx.commit();
- if (!updated.length) {
- res.sendStatus(404);
- } else {
- res.status(200).send(updated);
- }
- } catch (error) {
- await trx.rollback();
- res.status(400).json({
- error,
- });
+ async updateUser(req, res) {
+ const trx = await transaction.start(Model.knex());
+ try {
+ delete req.body.status_id;
+ const updated = await baseController.put(userModel, req.params.user_id, req.body, req, {
+ trx,
+ });
+ await trx.commit();
+ if (!updated.length) {
+ res.sendStatus(404);
+ } else {
+ res.status(200).send(updated);
}
- };
+ } catch (error) {
+ await trx.rollback();
+ res.status(400).json({
+ error,
+ });
+ }
},
- acceptInvitationAndPostPassword() {
- return async (req, res) => {
- let result;
- try {
- const { password, first_name, last_name, gender, birth_year, language_preference } = req.body;
- const { user_id, farm_id, email } = req.user;
- const salt = await bcrypt.genSalt(10);
- const password_hash = await bcrypt.hash(password, salt);
- await userModel.transaction(async trx => {
- await passwordModel.query(trx).insert({ user_id, password_hash });
- await userModel.query(trx).findById(user_id).patch({
- first_name,
- last_name,
- gender,
- birth_year,
- language_preference,
- status_id: 1,
- });
- const { role_id } = await userFarmModel.query(trx).where({
+ async acceptInvitationAndPostPassword(req, res) {
+ let result;
+ try {
+ const { password, first_name, last_name, gender, birth_year, language_preference } = req.body;
+ const { user_id, farm_id } = req.user;
+ const salt = await bcrypt.genSalt(10);
+ const password_hash = await bcrypt.hash(password, salt);
+ await userModel.transaction(async (trx) => {
+ await passwordModel.query(trx).insert({ user_id, password_hash });
+ await userModel.query(trx).findById(user_id).patch({
+ first_name,
+ last_name,
+ gender,
+ birth_year,
+ language_preference,
+ status_id: 1,
+ });
+ await userFarmModel
+ .query(trx)
+ .where({
user_id,
farm_id,
- }).patch({ status: 'Active' }).returning('*').first();
- await showedSpotlightModel.query(trx).insert({ user_id });
- });
-
- result = await userFarmModel.query().withGraphFetched('[role, farm, user]').findById([user_id, farm_id]);
- result = { ...result.user, ...result, ...result.role, ...result.farm };
- delete result.farm;
- delete result.user;
- delete result.role;
- const id_token = await createToken('access', { user_id });
- return res.status(201).send({
- id_token,
- user: result,
- });
- } catch (error) {
- console.log(error);
- res.status(400).json({
- error,
- });
- }
- };
+ })
+ .patch({ status: 'Active' })
+ .returning('*')
+ .first();
+ await showedSpotlightModel.query(trx).insert({ user_id });
+ });
+
+ result = await userFarmModel
+ .query()
+ .withGraphFetched('[role, farm, user]')
+ .findById([user_id, farm_id]);
+ result = { ...result.user, ...result, ...result.role, ...result.farm };
+ delete result.farm;
+ delete result.user;
+ delete result.role;
+ const id_token = await createToken('access', { user_id });
+ return res.status(201).send({
+ id_token,
+ user: result,
+ });
+ } catch (error) {
+ console.log(error);
+ res.status(400).json({
+ error,
+ });
+ }
},
- acceptInvitationWithGoogleAccount() {
- return async (req, res) => {
- let result;
- const { sub, user_id, farm_id, email } = req.user;
- const { first_name, last_name, gender, birth_year, language_preference } = req.body;
- try {
- await userModel.transaction(async trx => {
- const user = await userModel.query(trx).context({
+ async acceptInvitationWithGoogleAccount(req, res) {
+ let result;
+ const { sub, user_id, farm_id, email } = req.user;
+ const { first_name, last_name, gender, birth_year, language_preference } = req.body;
+ try {
+ await userModel.transaction(async (trx) => {
+ const user = await userModel
+ .query(trx)
+ .context({
showHidden: true,
shouldUpdateEmail: true,
- }).findById(user_id).patch({ email: user_id }).returning('*');
- delete user.profile_picture;
- delete user.user_address;
- user.phone_number = user.phone_number ? user.phone_number : undefined;
- await userModel.query(trx).insert({
- ...user,
- user_id: sub,
- status_id: 1,
- email,
- first_name,
- last_name,
- gender,
- birth_year,
- language_preference,
- });
- await userFarmModel.query(trx).where({
+ })
+ .findById(user_id)
+ .patch({ email: user_id })
+ .returning('*');
+ delete user.profile_picture;
+ delete user.user_address;
+ user.phone_number = user.phone_number ? user.phone_number : undefined;
+ await userModel.query(trx).insert({
+ ...user,
+ user_id: sub,
+ status_id: 1,
+ email,
+ first_name,
+ last_name,
+ gender,
+ birth_year,
+ language_preference,
+ });
+ await userFarmModel
+ .query(trx)
+ .where({
user_id,
farm_id,
- }).patch({ status: 'Active' });
- const userFarms = await userFarmModel.query(trx).where({ user_id });
- await userFarmModel.query(trx).insert(userFarms.map(userFarm => ({ ...userFarm, user_id: sub })));
- await shiftModel.query(trx).context({ user_id: sub }).where({ user_id }).patch({ user_id: sub });
- await emailTokenModel.query(trx).where({ user_id }).patch({ user_id: sub });
- await showedSpotlightModel.query(trx).insert({ user_id: sub });
- await userFarmModel.query(trx).where({ user_id }).delete();
- await userModel.query(trx).findById(user_id).delete();
- });
- result = await userFarmModel.query().withGraphFetched('[role, farm, user]').findById([
- sub, farm_id,
- ]);
- result = { ...result.user, ...result, ...result.role, ...result.farm };
- delete result.farm;
- delete result.user;
- delete result.role;
- const id_token = await createToken('access', { user_id: sub });
- return res.status(200).send({
- id_token,
- user: result,
- });
- } catch (error) {
- return res.status(400).json({
- error,
- });
- }
- };
+ })
+ .patch({ status: 'Active' });
+ const userFarms = await userFarmModel.query(trx).where({ user_id });
+ await userFarmModel
+ .query(trx)
+ .insert(userFarms.map((userFarm) => ({ ...userFarm, user_id: sub })));
+ await shiftModel
+ .query(trx)
+ .context({ user_id: sub })
+ .where({ user_id })
+ .patch({ user_id: sub });
+ await emailTokenModel.query(trx).where({ user_id }).patch({ user_id: sub });
+ await showedSpotlightModel.query(trx).insert({ user_id: sub });
+ await userFarmModel.query(trx).where({ user_id }).delete();
+ await userModel.query(trx).findById(user_id).delete();
+ });
+ result = await userFarmModel
+ .query()
+ .withGraphFetched('[role, farm, user]')
+ .findById([sub, farm_id]);
+ result = { ...result.user, ...result, ...result.role, ...result.farm };
+ delete result.farm;
+ delete result.user;
+ delete result.role;
+ const id_token = await createToken('access', { user_id: sub });
+ return res.status(200).send({
+ id_token,
+ user: result,
+ });
+ } catch (error) {
+ return res.status(400).json({
+ error,
+ });
+ }
},
};
diff --git a/packages/api/src/controllers/userFarmController.js b/packages/api/src/controllers/userFarmController.js
index 0109c1adee..0d4063de73 100644
--- a/packages/api/src/controllers/userFarmController.js
+++ b/packages/api/src/controllers/userFarmController.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (userFarmController.js) is part of LiteFarm.
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,37 +13,34 @@
* GNU General Public License for more details, see .
*/
-const baseController = require('../controllers/baseController');
-const userController = require('../controllers/userController');
const userFarmModel = require('../models/userFarmModel');
const userModel = require('../models/userModel');
const userLogModel = require('../models/userLogModel');
-const farmModel = require('../models/farmModel');
const passwordModel = require('../models/passwordModel');
-const emailTokenModel = require('../models/emailTokenModel');
const roleModel = require('../models/roleModel');
const shiftModel = require('../models/shiftModel');
-const userFarmStatusEnum = require('../common/enums/userFarmStatus');
+const emailModel = require('../models/emailTokenModel');
const { transaction, Model } = require('objection');
-const { sendEmailTemplate, emails, sendEmail } = require('../templates/sendEmailTemplate');
-const { v4: uuidv4 } = require('uuid');
+const { emails, sendEmail } = require('../templates/sendEmailTemplate');
const { createToken } = require('../util/jwt');
-
const validStatusChanges = {
- 'Active': ['Inactive'],
- 'Inactive': ['Invited', 'Active'],
- 'Invited': ['Inactive'],
+ Active: ['Inactive'],
+ Inactive: ['Invited', 'Active'],
+ Invited: ['Inactive'],
};
const userFarmController = {
-
getUserFarmByUserID() {
return async (req, res) => {
try {
const user_id = req.params.user_id;
- const rows = await userFarmModel.query().context({ user_id: req.user.user_id })
- .select('*').where('userFarm.user_id', user_id).andWhereNot('farm.deleted', 'true')
+ const rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select('*')
+ .where('userFarm.user_id', user_id)
+ .andWhereNot('farm.deleted', 'true')
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
@@ -66,32 +63,43 @@ const userFarmController = {
try {
const farm_id = req.params.farm_id;
const user_id = req.headers.user_id;
- const [userFarm] = await userFarmModel.query().select('role_id').where('farm_id', farm_id).andWhere('user_id', user_id);
+ const [userFarm] = await userFarmModel
+ .query()
+ .select('role_id')
+ .where('farm_id', farm_id)
+ .andWhere('user_id', user_id);
let rows;
if (userFarm.role_id === 3) {
- rows = await userFarmModel.query().context({ user_id: req.user.user_id }).select(
- 'users.first_name',
- 'users.last_name',
- 'users.profile_picture',
- 'users.phone_number',
- 'users.email',
- 'userFarm.role_id',
- 'role.role',
- 'userFarm.status',
- 'userFarm.farm_id',
- 'userFarm.user_id',
- ).where('userFarm.farm_id', farm_id)
+ rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select(
+ 'users.first_name',
+ 'users.last_name',
+ 'users.profile_picture',
+ 'users.phone_number',
+ 'users.email',
+ 'userFarm.role_id',
+ 'role.role',
+ 'userFarm.status',
+ 'userFarm.farm_id',
+ 'userFarm.user_id',
+ )
+ .where('userFarm.farm_id', farm_id)
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id');
} else {
- rows = await userFarmModel.query().context({ user_id: req.user.user_id }).select('*').where('userFarm.farm_id', farm_id)
+ rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select('*')
+ .where('userFarm.farm_id', farm_id)
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
}
res.status(200).send(rows);
} catch (error) {
- //handle more exceptions
res.status(400).send(error);
}
};
@@ -102,30 +110,42 @@ const userFarmController = {
try {
const farm_id = req.params.farm_id;
const user_id = req.headers.user_id;
- const [userFarm] = await userFarmModel.query().select('role_id').where('farm_id', farm_id).andWhere('user_id', user_id);
+ const [userFarm] = await userFarmModel
+ .query()
+ .select('role_id')
+ .where('farm_id', farm_id)
+ .andWhere('user_id', user_id);
let rows;
if (userFarm.role_id === 3) {
- rows = await userFarmModel.query().context({ user_id: req.user.user_id }).select(
- 'users.first_name',
- 'users.last_name',
- 'users.profile_picture',
- 'users.phone_number',
- 'users.email',
- 'userFarm.role_id',
- 'role.role',
- 'userFarm.status',
- ).where('userFarm.farm_id', farm_id).andWhere('userFarm.status', 'Active')
+ rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select(
+ 'users.first_name',
+ 'users.last_name',
+ 'users.profile_picture',
+ 'users.phone_number',
+ 'users.email',
+ 'userFarm.role_id',
+ 'role.role',
+ 'userFarm.status',
+ )
+ .where('userFarm.farm_id', farm_id)
+ .andWhere('userFarm.status', 'Active')
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id');
} else {
- rows = await userFarmModel.query().select('*').where('userFarm.farm_id', farm_id).andWhere('userFarm.status', 'Active')
+ rows = await userFarmModel
+ .query()
+ .select('*')
+ .where('userFarm.farm_id', farm_id)
+ .andWhere('userFarm.status', 'Active')
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
}
res.status(200).send(rows);
} catch (error) {
- //handle more exceptions
res.status(400).send(error);
}
};
@@ -136,32 +156,45 @@ const userFarmController = {
try {
const user_id = req.params.user_id;
const farm_id = req.params.farm_id;
- const [userFarm] = await userFarmModel.query().select('role_id').where('farm_id', farm_id).andWhere('user_id', user_id);
+ const [userFarm] = await userFarmModel
+ .query()
+ .select('role_id')
+ .where('farm_id', farm_id)
+ .andWhere('user_id', user_id);
let rows;
if (userFarm.role_id === 3) {
- rows = await userFarmModel.query().context({ user_id: req.user.user_id }).select(
- 'users.first_name',
- 'users.last_name',
- 'users.profile_picture',
- 'users.phone_number',
- 'users.email',
- 'userFarm.role_id',
- 'role.role',
- 'userFarm.status',
- 'userFarm.farm_id',
- 'userFarm.user_id',
- ).where('userFarm.user_id', user_id).andWhere('userFarm.farm_id', farm_id)
+ rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select(
+ 'users.first_name',
+ 'users.last_name',
+ 'users.profile_picture',
+ 'users.phone_number',
+ 'users.email',
+ 'userFarm.role_id',
+ 'role.role',
+ 'userFarm.status',
+ 'userFarm.farm_id',
+ 'userFarm.user_id',
+ )
+ .where('userFarm.user_id', user_id)
+ .andWhere('userFarm.farm_id', farm_id)
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id');
} else {
- rows = await userFarmModel.query().context({ user_id: req.user.user_id }).select('*').where('userFarm.user_id', user_id).andWhere('userFarm.farm_id', farm_id)
+ rows = await userFarmModel
+ .query()
+ .context({ user_id: req.user.user_id })
+ .select('*')
+ .where('userFarm.user_id', user_id)
+ .andWhere('userFarm.farm_id', farm_id)
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id');
}
return res.status(200).send(rows);
} catch (error) {
- //handle more exceptions
res.status(400).send(error);
}
};
@@ -172,14 +205,21 @@ const userFarmController = {
try {
const { user_id, farm_id } = req.params;
const { has_consent, consent_version } = req.body;
- const userFarm = await userFarmModel.query().select('*').where({
- 'userFarm.user_id': user_id,
- 'userFarm.farm_id': farm_id,
- })
+ const userFarm = await userFarmModel
+ .query()
+ .select('*')
+ .where({
+ 'userFarm.user_id': user_id,
+ 'userFarm.farm_id': farm_id,
+ })
.leftJoin('role', 'userFarm.role_id', 'role.role_id')
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
- .leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id').first();
- await userFarmModel.query().where({ user_id, farm_id }).patch({ has_consent, consent_version });
+ .leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id')
+ .first();
+ await userFarmModel
+ .query()
+ .where({ user_id, farm_id })
+ .patch({ has_consent, consent_version });
res.sendStatus(200);
const { step_two_end, step_three_end, step_five_end } = userFarm;
const isWelcomeEmailSent = !!step_two_end && !!step_three_end && !step_five_end;
@@ -227,8 +267,10 @@ const userFarmController = {
const step_five_end = req.body.step_five_end;
try {
-
- const isPatched = await userFarmModel.query(trx).where('user_id', user_id).andWhere('farm_id', farm_id)
+ const isPatched = await userFarmModel
+ .query(trx)
+ .where('user_id', user_id)
+ .andWhere('farm_id', farm_id)
.patch({
step_one,
step_one_end,
@@ -269,21 +311,25 @@ const userFarmController = {
if (!role) {
return res.status(400).send('role_id not found');
} else if (role_id === 4) {
- return res.status(400).send('Can\'t change user\'s role to pseudo user');
+ return res.status(400).send("Can't change user's role to pseudo user");
}
// if admin is updating themselves to worker, check if they're the last admin of farm
if (role_id === 3) {
- const admins = await userFarmModel.query().where({
- role_id: 1,
- farm_id,
- }).orWhere({
- role_id: 2,
- farm_id,
- }).orWhere({
- role_id: 5,
- farm_id,
- });
+ const admins = await userFarmModel
+ .query()
+ .where({
+ role_id: 1,
+ farm_id,
+ })
+ .orWhere({
+ role_id: 2,
+ farm_id,
+ })
+ .orWhere({
+ role_id: 5,
+ farm_id,
+ });
if (admins.length === 1)
return res.status(404).send('Cannot update last admin of farm to worker');
}
@@ -294,7 +340,6 @@ const userFarmController = {
};
const isPatched = await userFarmModel.query().where({ farm_id, user_id }).patch(updateData);
return isPatched ? res.sendStatus(200) : res.status(404).send('User not found');
-
} catch (error) {
console.log(error);
return res.status(400).send(error);
@@ -310,11 +355,18 @@ const userFarmController = {
const { status } = req.body;
let template_path;
- let subject;
try {
- const targetUser = await userFarmModel.query().select('users.first_name', 'users.last_name',
- 'farm.farm_name', 'userFarm.status', 'users.email', 'users.language_preference')
+ const targetUser = await userFarmModel
+ .query()
+ .select(
+ 'users.first_name',
+ 'users.last_name',
+ 'farm.farm_name',
+ 'userFarm.status',
+ 'users.email',
+ 'users.language_preference',
+ )
.where({ 'userFarm.user_id': user_id, 'userFarm.farm_id': farm_id })
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id')
@@ -341,14 +393,16 @@ const userFarmController = {
} else if (currentStatus === 'Inactive') {
template_path = emails.ACCESS_RESTORE;
}
- const isPatched = await userFarmModel.query().where('farm_id', farm_id).andWhere('user_id', user_id)
+ const isPatched = await userFarmModel
+ .query()
+ .where('farm_id', farm_id)
+ .andWhere('user_id', user_id)
.patch({
status,
});
if (isPatched) {
res.sendStatus(200);
try {
- console.log('template_path:', template_path);
if (targetUser.email && template_path) {
sendEmail(template_path, replacements, targetUser.email, { sender });
}
@@ -373,17 +427,27 @@ const userFarmController = {
const { user_id, farm_id } = req.user;
const { language_preference } = req.body;
if (!/^\d+$/.test(user_id)) {
- const user = await userModel.query().findById(user_id).patch({ language_preference }).returning('*');
+ const user = await userModel
+ .query()
+ .findById(user_id)
+ .patch({ language_preference })
+ .returning('*');
const passwordRow = await passwordModel.query().findById(user_id);
if (!passwordRow || user.status_id === 2) {
return res.status(404).send('User does not exist');
}
}
- await userFarmModel.query().where({
- user_id,
- farm_id,
- }).patch({ status: 'Active' });
- result = await userFarmModel.query().withGraphFetched('[role, farm, user]').findById([user_id, farm_id]);
+ await userFarmModel
+ .query()
+ .where({
+ user_id,
+ farm_id,
+ })
+ .patch({ status: 'Active' });
+ result = await userFarmModel
+ .query()
+ .withGraphFetched('[role, farm, user]')
+ .findById([user_id, farm_id]);
result = { ...result.user, ...result, ...result.role, ...result.farm };
delete result.farm;
delete result.user;
@@ -409,7 +473,10 @@ const userFarmController = {
const { wage } = req.body;
try {
- const isPatched = await userFarmModel.query(trx).where('farm_id', farm_id).andWhere('user_id', user_id)
+ const isPatched = await userFarmModel
+ .query(trx)
+ .where('farm_id', farm_id)
+ .andWhere('user_id', user_id)
.patch({
wage,
});
@@ -435,13 +502,13 @@ const userFarmController = {
const { user_id, farm_id } = req.params;
const { email } = req.body;
const roleIdAndWage = {};
- roleIdAndWage.role_id = (!req.body.role_id || req.body.role_id === 4) ? 3 : req.body.role_id;
+ roleIdAndWage.role_id = !req.body.role_id || req.body.role_id === 4 ? 3 : req.body.role_id;
if (req.body.wage) {
roleIdAndWage.wage = req.body.wage;
}
let userFarm;
try {
- await userFarmModel.transaction(async trx => {
+ await userFarmModel.transaction(async (trx) => {
userFarm = await userFarmModel.query(trx).findById([user_id, farm_id]);
if (userFarm.role_id !== 4) {
// TODO: move validation
@@ -449,16 +516,25 @@ const userFarmController = {
}
const user = await userModel.query(trx).where({ email }).first();
const isExistingAccount = !!user;
- const isUserAMemberOfFarm = isExistingAccount ? !!await userFarmModel.query(trx).findById([user.user_id, farm_id]) : false;
+ const isUserAMemberOfFarm = isExistingAccount
+ ? !!(await userFarmModel.query(trx).findById([user.user_id, farm_id]))
+ : false;
if (isUserAMemberOfFarm) {
const { user_id: newUserId } = user;
- await userFarmModel.query(trx).findById([user.user_id, farm_id]).patch({
- status: 'Invited',
- step_three: false,
- has_consent: false,
- ...roleIdAndWage,
- });
- await shiftModel.query(trx).context({ user_id: newUserId }).where({ user_id }).patch({ user_id: newUserId });
+ await userFarmModel
+ .query(trx)
+ .findById([user.user_id, farm_id])
+ .patch({
+ status: 'Invited',
+ step_three: false,
+ has_consent: false,
+ ...roleIdAndWage,
+ });
+ await shiftModel
+ .query(trx)
+ .context({ user_id: newUserId })
+ .where({ user_id })
+ .patch({ user_id: newUserId });
await userFarmModel.query(trx).where({ user_id }).delete();
await userLogModel.query(trx).where({ user_id }).delete();
await userModel.query(trx).findById(user_id).delete();
@@ -472,30 +548,44 @@ const userFarmController = {
has_consent: false,
...roleIdAndWage,
});
- await shiftModel.query(trx).context({ user_id: newUserId }).where({ user_id }).patch({ user_id: newUserId });
+ await shiftModel
+ .query(trx)
+ .context({ user_id: newUserId })
+ .where({ user_id })
+ .patch({ user_id: newUserId });
await userFarmModel.query(trx).where({ user_id }).delete();
await userLogModel.query(trx).where({ user_id }).delete();
await userModel.query(trx).findById(user_id).delete();
return;
} else {
- await userModel.query(trx).context({ shouldUpdateEmail: true }).findById(user_id).patch({
- email,
- status_id: 2,
- }).returning('*');
- await userFarmModel.query(trx).findById([user_id, farm_id]).patch({
- status: 'Invited',
- step_three: false,
- has_consent: false,
- ...roleIdAndWage,
- });
+ await userModel
+ .query(trx)
+ .context({ shouldUpdateEmail: true })
+ .findById(user_id)
+ .patch({
+ email,
+ status_id: 2,
+ })
+ .returning('*');
+ await userFarmModel
+ .query(trx)
+ .findById([user_id, farm_id])
+ .patch({
+ status: 'Invited',
+ step_three: false,
+ has_consent: false,
+ ...roleIdAndWage,
+ });
return;
}
});
- userFarm = await userFarmModel.query()
+ userFarm = await userFarmModel
+ .query()
.join('users', 'userFarm.user_id', '=', 'users.user_id')
.join('farm', 'farm.farm_id', '=', 'userFarm.farm_id')
.join('role', 'userFarm.role_id', '=', 'role.role_id')
- .where({ 'users.email': email, 'userFarm.farm_id': farm_id }).first()
+ .where({ 'users.email': email, 'userFarm.farm_id': farm_id })
+ .first()
.select('*');
res.status(201).send(userFarm);
} catch (e) {
@@ -503,7 +593,7 @@ const userFarmController = {
}
try {
const { farm_name } = userFarm;
- await userController.createTokenSendEmail(userFarm, userFarm, farm_name);
+ await emailModel.createTokenSendEmail(userFarm, userFarm, farm_name);
} catch (e) {
console.log(e);
}
@@ -514,12 +604,15 @@ const userFarmController = {
module.exports = userFarmController;
async function appendOwners(userFarms) {
- const farm_ids = userFarms.map(userFarm => userFarm.farm_id);
- const owners = await userFarmModel.query()
- .whereIn('userFarm.farm_id', farm_ids).where('userFarm.role_id', 1)
+ const farm_ids = userFarms.map((userFarm) => userFarm.farm_id);
+ const owners = await userFarmModel
+ .query()
+ .whereIn('userFarm.farm_id', farm_ids)
+ .where('userFarm.role_id', 1)
.leftJoin('users', 'userFarm.user_id', 'users.user_id')
.leftJoin('farm', 'userFarm.farm_id', 'farm.farm_id')
- .orderBy('userFarm.step_one_end', 'asc').select('*');
+ .orderBy('userFarm.step_one_end', 'asc')
+ .select('*');
const map = {};
for (const userFarm of userFarms) {
map[userFarm.farm_id] = { ...userFarm, owner_name: null };
diff --git a/packages/api/src/jobs/certification/index.js b/packages/api/src/jobs/certification/index.js
new file mode 100644
index 0000000000..f648c5623a
--- /dev/null
+++ b/packages/api/src/jobs/certification/index.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const Queue = require('bull');
+
+const processExports = (queueConfig) => {
+ const retrieveQueue = new Queue('retrieve', queueConfig);
+ const excelQueue = new Queue('excel', queueConfig);
+ const zipQueue = new Queue('zip', queueConfig);
+ const pdfQueue = new Queue('pdf', queueConfig);
+ const emailQueue = new Queue('email', queueConfig);
+ const uploadQueue = new Queue('upload', queueConfig);
+ const retrieveFn = require('./do_retrieve');
+ const uploadFn = require('./upload');
+ const excelFn = require('./recordD');
+ const zipFn = require('./zip');
+ const pdfFn = require('./pdf');
+ const emailFn = require('./email');
+
+ retrieveQueue.process(retrieveFn(excelQueue, emailQueue));
+ excelQueue.process(excelFn(pdfQueue, zipQueue, emailQueue));
+ pdfQueue.process(pdfFn(zipQueue, emailQueue));
+ zipQueue.process(zipFn(uploadQueue, emailQueue));
+ uploadQueue.process(uploadFn(emailQueue));
+ emailQueue.process(emailFn);
+
+ retrieveQueue.on('error', (e) => console.error(e));
+ excelQueue.on('error', (e) => console.error(e));
+ pdfQueue.on('error', (e) => console.error(e));
+ emailQueue.on('error', (e) => console.error(e));
+ uploadQueue.on('error', (e) => console.error(e));
+ zipQueue.on('error', (e) => console.error(e));
+};
+
+module.exports = {
+ processExports,
+};
diff --git a/packages/api/src/jobs/certification/recordD.js b/packages/api/src/jobs/certification/recordD.js
index df469dc052..dea04a4ee3 100644
--- a/packages/api/src/jobs/certification/recordD.js
+++ b/packages/api/src/jobs/certification/recordD.js
@@ -2,6 +2,7 @@ const recordDGenerator = require('./record_d_generation');
const recordAGenerator = require('./record_a_generation');
const recordIGeneration = require('./record_i_generation');
const readmeGeneration = require('./readmeGeneration');
+const surveyRecordGeneration = require('./survey_record');
const i18n = require('../locales/i18n');
module.exports = (nextQueue, zipQueue, emailQueue) => (job) => {
console.log('STEP 2 > EXCEL GENERATE', job.id);
@@ -16,21 +17,31 @@ module.exports = (nextQueue, zipQueue, emailQueue) => (job) => {
farm_name,
measurement,
language_preference,
+ submission,
+ organicCertifierSurvey,
} = job.data;
- return i18n.changeLanguage(language_preference).then(() => Promise.all([
- recordDGenerator(recordD, exportId, from_date, to_date, farm_name),
- recordIGeneration(recordICrops, exportId, from_date, to_date, farm_name, measurement, true),
- recordAGenerator(recordA, exportId, from_date, to_date, farm_name, measurement),
- recordIGeneration(recordICleaners, exportId, from_date, to_date, farm_name, measurement),
- readmeGeneration(exportId, language_preference),
- ])).then(() => {
- if (job.data.submission) {
- return Promise.resolve(nextQueue.add(job.data, { removeOnComplete: true }));
- }
- return Promise.resolve(zipQueue.add(job.data, { removeOnComplete: true }));
- }).catch((e) => {
- console.log(e)
- return Promise.resolve(emailQueue.add({ fail: true, email: job.data.email }, { removeOnComplete: true }));
- })
-}
-
+ return i18n
+ .changeLanguage(language_preference)
+ .then(() =>
+ Promise.all([
+ recordDGenerator(recordD, exportId, from_date, to_date, farm_name),
+ recordIGeneration(recordICrops, exportId, from_date, to_date, farm_name, measurement, true),
+ recordAGenerator(recordA, exportId, from_date, to_date, farm_name, measurement),
+ recordIGeneration(recordICleaners, exportId, from_date, to_date, farm_name, measurement),
+ readmeGeneration(exportId, language_preference),
+ surveyRecordGeneration(emailQueue, submission, exportId, organicCertifierSurvey),
+ ]),
+ )
+ .then(() => {
+ if (job.data.submission) {
+ return Promise.resolve(nextQueue.add(job.data, { removeOnComplete: true }));
+ }
+ return Promise.resolve(zipQueue.add(job.data, { removeOnComplete: true }));
+ })
+ .catch((e) => {
+ console.log(e);
+ return Promise.resolve(
+ emailQueue.add({ fail: true, email: job.data.email }, { removeOnComplete: true }),
+ );
+ });
+};
diff --git a/packages/api/src/jobs/certification/record_a_generation.js b/packages/api/src/jobs/certification/record_a_generation.js
index a29a030804..0719fc9878 100644
--- a/packages/api/src/jobs/certification/record_a_generation.js
+++ b/packages/api/src/jobs/certification/record_a_generation.js
@@ -105,20 +105,36 @@ module.exports = (data, exportId, from_date, to_date, farm_name, measurement) =>
.add(` ${t('RECORD_A.NEW_AREA')}`);
sheet.cell('F5').value(f5Text);
- const g5Text = new RichText()
- .add(t('RECORD_A.TRANSITIONAL'), { bold: true })
- .add(` ${t('RECORD_A.AREA')}`);
+ const g5Text =
+ i18n.language === 'en'
+ ? new RichText()
+ .add(t('RECORD_A.TRANSITIONAL'), { bold: true })
+ .add(` ${t('RECORD_A.AREA')}`)
+ : new RichText().add(t('RECORD_A.AREA')).add(` ${t('RECORD_A.TRANSITIONAL')}`, {
+ bold: true,
+ });
sheet.cell('G5').value(g5Text);
- const h5Text = new RichText()
- .add(t('RECORD_A.CERTIFIED'), { bold: true })
- .add(` ${t('RECORD_A.ORGANIC_AREA')}`);
+ const h5Text =
+ i18n.language === 'en'
+ ? new RichText()
+ .add(t('RECORD_A.CERTIFIED'), { bold: true })
+ .add(` ${t('RECORD_A.ORGANIC_AREA')}`)
+ : new RichText()
+ .add(t('RECORD_A.ORGANIC_AREA'))
+ .add(` ${t('RECORD_A.CERTIFIED')}`, { bold: true });
sheet.cell('H5').value(h5Text);
- const i5Text = new RichText()
- .add(t('RECORD_A.NON_ORGANIC'))
- .add(` ${t('RECORD_A.SPLIT')}`, { bold: true })
- .add(` ${t('RECORD_A.PRODUCTION')}`);
+ const i5Text =
+ i18n.language === 'en'
+ ? new RichText()
+ .add(t('RECORD_A.NON_ORGANIC'))
+ .add(` ${t('RECORD_A.SPLIT')}`, { bold: true })
+ .add(` ${t('RECORD_A.PRODUCTION')}`)
+ : new RichText()
+ .add(t('RECORD_A.NON_ORGANIC'))
+ .add(` ${t('RECORD_A.PRODUCTION')}`)
+ .add(` ${t('RECORD_A.SPLIT')}`, { bold: true });
sheet.cell('I5').value(i5Text);
const j5Text = new RichText()
diff --git a/packages/api/src/jobs/certification/survey_record.js b/packages/api/src/jobs/certification/survey_record.js
new file mode 100644
index 0000000000..80b940091f
--- /dev/null
+++ b/packages/api/src/jobs/certification/survey_record.js
@@ -0,0 +1,368 @@
+const XlsxPopulate = require('xlsx-populate');
+const rp = require('request-promise');
+const surveyStackURL = 'https://app.surveystack.io/api/';
+
+module.exports = async (emailQueue, submission, exportId, organicCertifierSurvey) => {
+ if (!submission) {
+ emailQueue.add({ fail: true });
+ return Promise.resolve();
+ }
+
+ const submissionData = await rp({
+ uri: `${surveyStackURL}/submissions/${submission}`,
+ json: true,
+ });
+
+ const survey = await rp({
+ uri: `${surveyStackURL}/surveys/${submissionData.meta.survey.id}`,
+ json: true,
+ });
+
+ const ignoredQuestions = [
+ 'geoJSON',
+ 'script',
+ 'FarmOS Field',
+ 'farmOsField',
+ 'farmOsPlanting',
+ 'farmOsFarm',
+ 'FarmOS Planting',
+ 'instructionsImageSplit',
+ ];
+ const questionStyle = {
+ fontFamily: 'Calibri',
+ bold: true,
+ fontSize: 14,
+ horizontalAlignment: 'left',
+ };
+ const groupHeaderStyle = {
+ fontFamily: 'Calibri',
+ bold: true,
+ fontSize: 18,
+ horizontalAlignment: 'center',
+ };
+
+ const getGroupBorder = (direction) => {
+ return {
+ [`${direction}Border`]: {
+ color: '000000',
+ style: 'thin',
+ },
+ leftBorder: {
+ color: '000000',
+ style: 'thin',
+ },
+ rightBorder: {
+ color: '000000',
+ style: 'thin',
+ },
+ };
+ };
+ const defaultStyle = {
+ fontFamily: 'Calibri',
+ fontSize: 12,
+ horizontalAlignment: 'left',
+ };
+ const titleStyle = {
+ fontFamily: 'Calibri',
+ fontSize: 20,
+ bold: true,
+ horizontalAlignment: 'center',
+ border: { color: '000000', style: 'thick' },
+ };
+
+ /**
+ * Traverse down nested groups to get the answer of a question.
+ * If a question is not nested in a group, no traversing is done.
+ */
+ const getNestedAnswer = (parentGroups, name) => {
+ let answer = submissionData.data;
+ for (const group of parentGroups) {
+ if (group != null) {
+ answer = answer[group];
+ }
+ }
+ return answer[name]?.value;
+ };
+
+ const getQuestionInfo = (questionAnswerList, groupName = null, prevParentGroups = []) => {
+ return questionAnswerList
+ .map(({ label, name, type, hint, options, moreInfo, children }) => ({
+ Question: label,
+ Name: name,
+ ParentGroups: [...prevParentGroups, groupName],
+ Answer: getNestedAnswer([...prevParentGroups, groupName], name),
+ Type: type,
+ Hint: hint,
+ Options: options,
+ MoreInfo: moreInfo,
+ Children: ['group', 'page'].includes(type) ? children : null,
+ }))
+ .filter((entry) => !ignoredQuestions.includes(entry['Type']));
+ };
+
+ const questionAnswerMap = getQuestionInfo(survey.revisions[survey.revisions.length - 1].controls);
+
+ /**
+ * Writes the question in bold and answer without bolding to Excel sheet at the position specified by col and row
+ */
+ const writeSimpleQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(data['Answer'])
+ .style(defaultStyle);
+ return [col, row, 1];
+ };
+
+ /**
+ * Write all the selected options from the dropdown question as subsequent rows
+ */
+ const writeDropdownQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+
+ if (data['Answer'] != null) {
+ for (const answer of data['Answer']) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(answer)
+ .style(defaultStyle);
+ }
+ }
+ return [col, row, 1];
+ };
+
+ /**
+ * Write date questions in the full format
+ */
+ const writeDateQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+ if (data['Answer'] != null) {
+ const date = new Date(data['Answer']).toDateString();
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(date)
+ .style(defaultStyle);
+ }
+ return [col, row, 1];
+ };
+
+ /**
+ * Write instructions in italics
+ */
+ const writeInstructions = (sheet, col, row, data) => {
+ const instructions = data['Options']['source'].replace(/|<\/p>/g, '');
+ sheet
+ .cell(`${col}${row}`)
+ .value(instructions)
+ .style({ ...defaultStyle, italic: true });
+ return [col, row, 1];
+ };
+
+ /**
+ * Write multiple choice/checkbox type questions to the Excel Sheet.
+ * Label is in the left column and a 'X' is placed in the immediate right column if this option was selected
+ */
+ const writeMultiOptionQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+ if (![null, '', undefined].includes(data['Hint'])) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(`Hint: ${data['Hint']}`)
+ .style({ ...defaultStyle, italic: true });
+ }
+ if (![null, '', undefined].includes(data['MoreInfo'])) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(`Extra Info: ${data['MoreInfo']}`)
+ .style({ ...defaultStyle, italic: true });
+ }
+
+ if (data['Answer'] != null) {
+ const nonCustomAnswers = data['Options']['source'];
+ for (const ncAnswer of nonCustomAnswers) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(ncAnswer['label'])
+ .style(defaultStyle);
+ if (data['Answer'].includes(ncAnswer['value'])) {
+ sheet
+ .cell(`${String.fromCharCode(col.charCodeAt(0) + 1)}${row}`)
+ .value('X')
+ .style(defaultStyle); // Write 'X' to the right column
+ }
+ }
+
+ // Get the difference between given answers and all non-custom answers.
+ // If this list is non-empty, we know the user gave a custom answer
+
+ const customEntry = data['Answer'].filter(
+ (answer) => !nonCustomAnswers.map((ncAnswer) => ncAnswer['value']).includes(answer),
+ );
+
+ if (customEntry.length != 0) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(customEntry[0])
+ .style(defaultStyle);
+
+ sheet
+ .cell(`${String.fromCharCode(col.charCodeAt(0) + 1)}${row}`)
+ .value('X')
+ .style(defaultStyle);
+ }
+ }
+
+ return [col, row, 2];
+ };
+
+ /**
+ * Write a matrix question to the sheet in the same format as the matrix.
+ * Only include the valid question types
+ */
+ const writeMatrixQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+ if (![null, '', undefined].includes(data['Hint'])) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(`Hint: ${data['Hint']}`)
+ .style({ ...defaultStyle, italic: true });
+ }
+
+ if (![null, '', undefined].includes(data['MoreInfo'])) {
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(`Extra Info: ${data['MoreInfo']}`)
+ .style({ ...defaultStyle, italic: true });
+ }
+ // Get all the valid types of questions in the matrix
+ const categories = data['Options']['source']['content']
+ .map((c) => c['value'])
+ .filter((c) => !ignoredQuestions.includes(c));
+
+ const labels = data['Options']['source']['content']
+ .map((c) => c['label'])
+ .filter((c) => !ignoredQuestions.includes(c));
+
+ row += 1;
+ // Write column headers
+ for (let i = 0; i < categories.length; i++) {
+ sheet
+ .cell(`${String.fromCharCode(col.charCodeAt(0) + i)}${row}`)
+ .value(labels[i])
+ .style({ ...defaultStyle, bold: true, border: { color: '000000', style: 'thick' } });
+ }
+
+ // Fill in the matrix
+ if (data['Answer'] != null) {
+ for (const answer of data['Answer']) {
+ row += 1;
+ for (let i = 0; i < categories.length; i++) {
+ if (answer[categories[i]]) {
+ // Check if this answer has valid type
+ sheet
+ .cell(`${String.fromCharCode(col.charCodeAt(0) + i)}${row}`)
+ .value(answer[categories[i]]['value'])
+ .style({ ...defaultStyle, border: { color: '000000', style: 'thin' } });
+ }
+ }
+ }
+ }
+ return [col, row, categories.length];
+ };
+
+ /**
+ * Write groups or pages to the Excel sheet with special formatting
+ */
+ const writeCollection = (sheet, col, row, data) => {
+ sheet
+ .cell(`${col}${row}`)
+ .value(data['Question'])
+ .style({ ...groupHeaderStyle, ...getGroupBorder('top') });
+ const childInfo = getQuestionInfo(data['Children'], data['Name'], data['ParentGroups']);
+ var [currentFarthestCol, farthestCol] = [1, 1];
+ for (const child of childInfo) {
+ [col, row, currentFarthestCol] = typeToFuncMap[child['Type']](sheet, col, row + 2, child);
+ farthestCol = Math.max(currentFarthestCol, farthestCol);
+ }
+ sheet.cell(`${col}${row}`).style(getGroupBorder('bottom'));
+
+ return [col, row, farthestCol];
+ };
+
+ const writeLocationQs = (sheet, col, row, data) => {
+ sheet.cell(`${col}${row}`).value(data['Question']).style(questionStyle);
+ if (data['Answer'] != null) {
+ const longLat = data['Answer']['geometry']['coordinates'];
+ sheet
+ .cell(`${col}${(row += 1)}`)
+ .value(`Longitude:${longLat[0]}, Latitude:${longLat[1]}`)
+ .style(defaultStyle);
+ }
+ return [col, row, 1];
+ };
+
+ const typeToFuncMap = {
+ string: writeSimpleQs, // Text
+ number: writeSimpleQs,
+ ontology: writeDropdownQs, //Dropdown
+ location: writeLocationQs,
+ date: writeDateQs,
+ selectSingle: writeMultiOptionQs, // Multiple choice
+ selectMultiple: writeMultiOptionQs, // Checkbox
+ matrix: writeMatrixQs,
+ instructions: writeInstructions,
+ page: writeCollection,
+ group: writeCollection,
+ };
+
+ return XlsxPopulate.fromBlankAsync().then((workbook) => {
+ // Populate the workbook.
+ const mainSheet = workbook.sheet(0);
+ const surveyName = survey['name'];
+ var [currentCol, currentRow, farthestCol, currentFarthestCol] = ['A', 1, 1, 1];
+
+ // Write the survey_id and farm_id
+ mainSheet
+ .cell(`A${currentRow}`)
+ .value(`Survey ID: ${submissionData.meta.survey.id}`)
+ .style(defaultStyle);
+ mainSheet
+ .cell(`A${(currentRow += 1)}`)
+ .value(`Farm ID: ${organicCertifierSurvey.farm_id}`)
+ .style(defaultStyle);
+
+ // Write the title
+ mainSheet
+ .cell(`A${(currentRow += 1)}`)
+ .value(surveyName)
+ .style(titleStyle);
+ currentRow += 2;
+ for (const qa of questionAnswerMap) {
+ [currentCol, currentRow, currentFarthestCol] = typeToFuncMap[qa['Type']](
+ mainSheet,
+ currentCol,
+ currentRow,
+ qa,
+ );
+ currentRow += 2;
+ farthestCol = Math.max(currentFarthestCol, farthestCol);
+ }
+ // Resize cells
+ for (let i = 0; i < farthestCol; i++) {
+ const colToResize = String.fromCharCode('A'.charCodeAt(0) + i);
+ const maxStringLength = mainSheet
+ .range(`${colToResize}1:${colToResize}${currentRow}`)
+ .reduce((max, cell) => {
+ const value = cell.value() == null ? '' : cell.value();
+ if (value === undefined) return max;
+ return Math.max(max, value.toString().length);
+ }, 0);
+
+ mainSheet.column(colToResize).width(maxStringLength * (titleStyle.fontSize / 12));
+ }
+
+ // Write to file.
+ return workbook.toFileAsync(`${process.env.EXPORT_WD}/temp/${exportId}/${surveyName}.xlsx`);
+ });
+};
diff --git a/packages/api/src/jobs/index.js b/packages/api/src/jobs/index.js
index 02d52e9133..7b04495619 100644
--- a/packages/api/src/jobs/index.js
+++ b/packages/api/src/jobs/index.js
@@ -1,4 +1,18 @@
-const Queue = require('bull');
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
require('dotenv').config();
const redisConf = {
redis: {
@@ -6,36 +20,7 @@ const redisConf = {
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASSWORD,
},
-}
-const retrieveQueue = new Queue('retrieve', redisConf);
-const excelQueue = new Queue('excel', redisConf);
-const zipQueue = new Queue('zip', redisConf);
-const pdfQueue = new Queue('pdf', redisConf);
-const emailQueue = new Queue('email', redisConf);
-const uploadQueue = new Queue('upload', redisConf);
-const retrieveFn = require('./certification/do_retrieve');
-const uploadFn = require('./certification/upload');
-const excelFn = require('./certification/recordD');
-const zipFn = require('./certification/zip');
-const pdfFn = require('./certification/pdf');
-const emailFn = require('./certification/email');
-
-retrieveQueue.process(retrieveFn(excelQueue, emailQueue));
-excelQueue.process(excelFn(pdfQueue, zipQueue, emailQueue));
-pdfQueue.process(pdfFn(zipQueue, emailQueue));
-zipQueue.process(zipFn(uploadQueue, emailQueue));
-uploadQueue.process(uploadFn(emailQueue));
-emailQueue.process(emailFn);
-
-
-retrieveQueue.on('error', (e) => console.error(e));
-excelQueue.on('error', (e) => console.error(e));
-pdfQueue.on('error', (e) => console.error(e));
-emailQueue.on('error', (e) => console.error(e));
-uploadQueue.on('error', (e) => console.error(e));
-zipQueue.on('error', (e) => console.error(e));
-
+};
-module.exports = {
- zipQueue, emailQueue, excelQueue, pdfQueue,
-}
\ No newline at end of file
+require('./certification').processExports(redisConf);
+require('./notifications').sendOnSchedule(redisConf);
diff --git a/packages/api/src/jobs/locales/en/translation.json b/packages/api/src/jobs/locales/en/translation.json
index 35ade1f020..932cf3abae 100644
--- a/packages/api/src/jobs/locales/en/translation.json
+++ b/packages/api/src/jobs/locales/en/translation.json
@@ -72,7 +72,7 @@
"INPUT_CATEGORY": "Input Category",
"LOCATIONS": "Location(s)",
"NOTE": {
- "LIST_ALL": "List ALL Inputs used in the last 12 months or since your last submitted Record I. You may choose to use this document to keep a running record of inputs used throughout the season.",
+ "LIST_ALL": "List ALL Inputs used in the last 12 months or since your last submitted Record I. You may choose to use this document to keep a running record of inputs used throughout the season.",
"LIVESTOCK_INPUTS": "Note: Livestock Inputs: Feed, feed additives and feed supplements, health care products and production aids, animal bedding etc. are to be listed on Record LI-Livestock Inputs.",
"ONE": {
"PART_1": "Soil Amendments, crop nutrition, crop production aids and materials:",
@@ -96,4 +96,4 @@
},
"Y": "Y",
"YES": "Yes"
-}
\ No newline at end of file
+}
diff --git a/packages/api/src/jobs/locales/es/readme.pdf b/packages/api/src/jobs/locales/es/readme.pdf
index 94228f23d8..915dfdefef 100644
Binary files a/packages/api/src/jobs/locales/es/readme.pdf and b/packages/api/src/jobs/locales/es/readme.pdf differ
diff --git a/packages/api/src/jobs/locales/fr/readme.pdf b/packages/api/src/jobs/locales/fr/readme.pdf
index b762fef670..2029ae7d7d 100644
Binary files a/packages/api/src/jobs/locales/fr/readme.pdf and b/packages/api/src/jobs/locales/fr/readme.pdf differ
diff --git a/packages/api/src/jobs/locales/fr/translation.json b/packages/api/src/jobs/locales/fr/translation.json
new file mode 100644
index 0000000000..153b5d7715
--- /dev/null
+++ b/packages/api/src/jobs/locales/fr/translation.json
@@ -0,0 +1,99 @@
+{
+ "EXPORT_README_TITLE": "Comprendre votre export du certification",
+ "N": "N",
+ "N/A": "S.O",
+ "NO": "Non",
+ "NOT_SURE": "Pas sûr",
+ "OPERATION_NAME": "NOM DE L'EXPLOITATION",
+ "RECORD_A": {
+ "ACRES": "Acres",
+ "AREA": "Zone",
+ "BUILDING": "(bâtiments, forêt, domaine de la biodiversité, allée)",
+ "CERTIFIED": "certifié organique",
+ "CROPS_OR_ANIMALS": "Cultures ou types d'animaux par unité",
+ "CURRENT_STATUS": "Situation actuelle - marquer un par unité",
+ "HEADER": "DOSSIER A - IDENTIFICATION DES SITES",
+ "HECTARES": "Hectares",
+ "INDIVIDUAL_PRODUCTION_UNIT": "pour chaque unité de production individuelle (p. ex. site/terrain/serre/zone définie - comme approprié pour votre exploitation et indiquée sur votre carte)",
+ "NAME_OR_ID": "Nom ou numéro d'identification",
+ "NEW": "Nouvelle",
+ "NEW_AREA": "Zone (Ajoutée cette année)",
+ "NON_ORGANIC": "Surface non-biologique en",
+ "NON_PRODUCING": "Inexploitées",
+ "OPERATION NAME": "NOM DE L'EXPLOITATION",
+ "ORGANIC_AREA": "Zone",
+ "PLEASE_VERIFY": "Veuillez vérifier les détails et apporter les modifications nécessaires chaque année. Si l’opération se déroule sur plusieurs sites, veuillez vous assurer de décrire chaque site séparément. Veuillez vous référer à l'exemple d'onglet ci-dessous pour savoir comment remplir ce formulaire.",
+ "PRODUCTION": "production",
+ "REMOVED": "Retiré du programme",
+ "REPORTING_PERIOD": "Période considérée",
+ "ROW_FT": "Rangée (pi)",
+ "ROW_M": "Rangée (m)",
+ "SIZE_IN_PREFERRED_UNIT": "Taille dans l'unité de mesure préférée",
+ "SPLIT": "Diviser/Parallèle",
+ "SQ_FT": "Pieds carrés",
+ "SQ_M": "Mètres carrés",
+ "TRANSITIONAL": "transitoire",
+ "WHY_REMOVED": "Pourquoi enlevé ou d'autres notes"
+ },
+ "RECORD_D": {
+ "DATE_COMPLETED": "Date d'achèvement",
+ "FROM": "De",
+ "HEADER": "Dossier D - Semences et matériel de plantation",
+ "NOTE": {
+ "LIST_ALL": "Énumérez toutes les semences et matériels de plantation utilisées au cours de la période de déclaration.",
+ "ONE": "Assurez-vous que les reçus d'achat, les étiquettes, et les certifications biologiques pour toutes les semences/plantes soient disponibles pour examen pendant l'inspection.",
+ "TWO": {
+ "A": "Recherche de disponibilité commerciale selon COS 5.3 - (Document D1 ou l'équivalent)",
+ "B": "Documentation confirmant l'état non génétiquement manipulées",
+ "C": "Documentation confirmant que les traitements tels que les inoculums ou les enrobages des semences sont conformes à la liste des substances permises.",
+ "PART_1": "Où",
+ "PART_2": "semences et stocks non biologiques",
+ "PART_3": "est utilisé, les documents suivants doivent être disponibles pour examen."
+ }
+ },
+ "REPORTING_PERIOD": "Période de déclaration",
+ "TABLE_COLUMN": {
+ "IS_SEARCH_COMPLETED": "Si les semences ou stocks biologiques ne sont pa certifiés, une recherche a-t-elle été terminée? (O/N)",
+ "LIST_SEED_TREATMENTS": "Dressez la liste des traitements des semences (le cas échéant)",
+ "LOT_NUMBER": "Numéro de lot (le cas échéant)",
+ "NON_GE_DOCS_AVAILABLE": "Les documents non GM sont disponibles (O/N)",
+ "NOTES": "Notes/dattes vivaces/etc.",
+ "SEED_CROP_OR_PLANTING_STOCK": "Culture/variété de semences ou matériel de plantation",
+ "STATUS_CERTIFIED_ORGANIC": "Statut des semences/stocks = certifié biologique (O/N)",
+ "SUPPLIER": "Source/fournisseur",
+ "TREATMENT_DOCS_AVAILABLE": "Les documents de traitement sont disponibles (O/N)"
+ },
+ "TO": "À"
+ },
+ "RECORD_I": {
+ "CLEANERS": "Nettoyants",
+ "CROP_PRODUCTION_AIDS": "Auxiliaires pour la production végétale",
+ "HEADER": "Dossier I",
+ "INPUT_CATEGORY": "Catégorie du intrant",
+ "LOCATIONS": "Emplacement(s)",
+ "NOTE": {
+ "LIST_ALL": "Énumérez tous les intrants utilisées durant les 12 derniers mois ou depuis la présentation de votre dernier Dossier I. Vous pouvez choisir d'utiliser ce document pour tenir un registre des intrants utilisés tout au long de la saison.",
+ "LIVESTOCK_INPUTS": "Notez: intrants d'élevage: aliments, additifs alimentaires, compléments alimentaires, produits de santé, aides à la production, litières d'animaux, etc. doivent être inscrit au Dossier LI - Intrants de bétails.",
+ "ONE": {
+ "PART_1": "Amendments du sol, nutrition des cultures, auxiliaires et matières utilisés pour la production végétale:",
+ "PART_2": "p. ex. comme des paillis, des engrais, des pulvérisations foliaires, du compost, du lisier, des mélanges de sol à base de terreau, de la mousse de tourbe, des amendements du sol, etc."
+ },
+ "PLEASE_USE_SEPARATE_RECORD": "Veuillez utiliser un dossier distinct pour chaque catégorie d'intrant comme décrit ci-dessous et télécharger chacun à l'emplacement de téléchargement respectif dans la Section 99 - Télécharger:",
+ "PREP_INPUTS": "Notez: intrants de préparation: additifs alimentaires, autres ingrédients, auxiliaires technologiques doivent figurer sur la Dossier PM - liste des ingrédients-maîtres de transformation es des auxiliaires de traitement.",
+ "TWO": "Nettoyants, désinfectants, assainisseurs, substances antiparasitaires."
+ },
+ "REPORTING_PERIOD": "Période de déclaration",
+ "TABLE_COLUMN": {
+ "CROP_FIELD_APPLIED_TO": "Culture/champ appliqué à ou unité de production utilisée dans",
+ "DATE_USED": "Date utilisée",
+ "LISTED_IN_PSL": "Figurant sur la liste des substances permises? (O/N)",
+ "Notes": "Notes",
+ "PRODUCT_NAME": "Nom du produit",
+ "QUANTITY": "Quantité ({{unit}})",
+ "SUPPLIER": "Nom commercial ou source/fournisseur"
+ },
+ "VARIETALS": "Variété(s)"
+ },
+ "Y": "O",
+ "YES": "Oui"
+}
diff --git a/packages/api/src/jobs/locales/i18n.js b/packages/api/src/jobs/locales/i18n.js
index f51c128f2c..de6a632e8c 100644
--- a/packages/api/src/jobs/locales/i18n.js
+++ b/packages/api/src/jobs/locales/i18n.js
@@ -1,19 +1,20 @@
const i18n = require('i18next');
const Backend = require('i18next-fs-backend');
-i18n
- .use(Backend)
- .init({
+i18n.use(Backend).init(
+ {
fallbackLng: 'en',
- preload: ['en', 'es', 'pt'],
+ preload: ['en', 'es', 'pt', 'fr'],
ns: ['translation', 'crop'],
defaultNS: 'translation',
+ nsSeparator: ':',
backend: {
loadPath: 'src/jobs/locales/{{lng}}/{{ns}}.json',
},
- }, (err, t) => {
- if (err) return console.error(err)
- console.log('i18next is ready...');
- });
+ },
+ (err) => {
+ if (err) return console.error(err);
+ },
+);
module.exports = i18n;
diff --git a/packages/api/src/jobs/locales/i18next-parser.config.js b/packages/api/src/jobs/locales/i18next-parser.config.js
index bf03b72c71..6db52d46a8 100644
--- a/packages/api/src/jobs/locales/i18next-parser.config.js
+++ b/packages/api/src/jobs/locales/i18next-parser.config.js
@@ -2,5 +2,5 @@ module.exports = {
output: 'src/jobs/locales/$LOCALE/$NAMESPACE.json',
sort: true,
defaultValue: 'MISSING',
- locales: ['en', 'es', 'pt'],
+ locales: ['en', 'es', 'pt', 'fr'],
};
diff --git a/packages/api/src/jobs/locales/pt/readme.pdf b/packages/api/src/jobs/locales/pt/readme.pdf
index ff9f3bc38c..461f510612 100644
Binary files a/packages/api/src/jobs/locales/pt/readme.pdf and b/packages/api/src/jobs/locales/pt/readme.pdf differ
diff --git a/packages/api/src/jobs/notifications/index.js b/packages/api/src/jobs/notifications/index.js
new file mode 100644
index 0000000000..10503fa3be
--- /dev/null
+++ b/packages/api/src/jobs/notifications/index.js
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const axios = require('axios');
+const Queue = require('bull');
+const { sign } = require('jsonwebtoken');
+const apiUrl = process.env.API_URL || 'http://localhost:5001';
+const mockTimer = !!process.env.MOCK_TIMER;
+
+// UTC day to send weeklies for zones >= 7
+// (Zero is Sunday.)
+const WEEKLY_NOTIFICATION_DAY_EARLIER_ZONES =
+ process.env.WEEKLY_NOTIFICATION_DAY_EARLIER_ZONES || 0;
+// UTC day to send weeklies for zones < 7
+const WEEKLY_NOTIFICATION_DAY_LATER_ZONES = (WEEKLY_NOTIFICATION_DAY_EARLIER_ZONES + 1) % 7;
+
+const ONE_DAY = mockTimer ? 1000 * 60 * 24 : 1000 * 60 * 60 * 24;
+let utcDay = mockTimer ? WEEKLY_NOTIFICATION_DAY_EARLIER_ZONES : undefined;
+let utcHour = mockTimer ? 5 : undefined; // mock starts 2 "hours" before day shifts
+
+/*
+ The following table shows: 1) time zones as offsets from UTC, 2) UTC hour of local 6am standard time, and 3) local 6am ST date offset from UTC.
+ Example: at 1600 Monday UTC, it is 0600 Tuesday in UTC+14.
+
+| UTC offset(s) | -11,13 | -10,14 | -9 | -8 | -7 | -6 | -5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
+| -------------- | ------ | ------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| 6am ST as UTC | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 23 | 22 | 21 | 20 | 19 | 18 |
+| -------------- | ------ | ------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
+| Date offset | 0,1 | 0,1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
+*/
+
+const sendOnSchedule = (queueConfig) => {
+ const driverQueue = new Queue('Schedule driver ', queueConfig);
+ const apiQueue = new Queue('Notification API requests', queueConfig);
+
+ // At the top of every hour ...
+ driverQueue.process((job, done) => {
+ // ... clean completed and failed API requests that have been in queue for 1 day ...
+ apiQueue.clean(ONE_DAY);
+ apiQueue.clean(ONE_DAY, 'failed');
+
+ // ... find the UTC offsets where it just became 6am ...
+ if (!mockTimer) {
+ const now = new Date();
+ utcDay = now.getUTCDay();
+ utcHour = now.getUTCHours();
+ }
+ const timeZones = [6 - utcHour];
+ if (timeZones[0] < -11) timeZones[0] += 24;
+ if (timeZones[0] === -10 || timeZones[0] === -11) timeZones[1] = timeZones[0] + 24;
+
+ console.log(
+ `Scheduled notifications: UTC day ${utcDay}, ${utcHour}:00. It's now 6am at UTC offset(s) ${timeZones}`,
+ );
+
+ // ... and call the API to get farms for those offsets.
+ const token = sign({ requestTimedNotifications: true }, process.env.JWT_SCHEDULER_SECRET, {
+ expiresIn: '1d',
+ algorithm: 'HS256',
+ });
+
+ for (const timeZone of timeZones) {
+ const start = 3600 * timeZone; // hours to seconds
+ const end = 3600 * (timeZone + 1) - 1;
+ console.log(` offset range is ${start} to ${end} seconds`);
+
+ const reqConfig = { headers: { Authorization: `Bearer ${token}` } };
+ axios
+ .get(`${apiUrl}/farm/utc_offset_by_range/${start}/${end}`, reqConfig)
+ .then(function (res) {
+ // For each farm ...
+ for (const farmId of res.data) {
+ // ... send daily 6am notifications ...
+ apiQueue.add(
+ { farmId, type: 'Daily', reqConfig, isDayLaterThanUtc: timeZone >= 7 },
+ { jobId: `Daily-${utcDay}-${utcHour}-${farmId}` },
+ );
+
+ // ... and weekly 6am notifications if appropriate.
+ if (
+ (utcDay === WEEKLY_NOTIFICATION_DAY_LATER_ZONES && timeZone < 7) ||
+ (utcDay === WEEKLY_NOTIFICATION_DAY_EARLIER_ZONES && timeZone >= 7)
+ ) {
+ apiQueue.add(
+ { farmId, type: 'Weekly', reqConfig, isDayLaterThanUtc: timeZone >= 7 },
+ { jobId: `Weekly-${utcDay}-${utcHour}-${farmId}` },
+ );
+ }
+ }
+ });
+ }
+ if (mockTimer && ++utcHour === 24) {
+ utcHour = 0;
+ utcDay = ++utcDay % 7;
+ }
+
+ done();
+ });
+
+ // Create a recurring schedule: top of each hour.
+ // (Mock timer treats one real minute as one simulated hour.)
+ driverQueue.add({}, { repeat: { cron: `${mockTimer ? '*' : '0'} * * * *` } });
+
+ // Process a job for each API request.
+ apiQueue.process((job, done) => {
+ const { type, farmId, reqConfig, isDayLaterThanUtc } = job.data;
+ const urls = {
+ Daily: 'time_notification/daily_due_today_tasks',
+ Weekly: 'time_notification/weekly_unassigned_tasks',
+ };
+ axios
+ .post(`${apiUrl}/${urls[type]}/${farmId}`, { isDayLaterThanUtc }, reqConfig)
+ .then(function (res) {
+ if ([200, 201].includes(res.status)) {
+ console.log(
+ ` ${type} notifications for farm ${farmId}: status ${res.status}, ${res.data}`,
+ );
+ done();
+ } else {
+ console.log(`Retrying job ${job.jobId}`);
+ job.retry();
+ }
+ });
+ });
+};
+
+module.exports = {
+ sendOnSchedule,
+};
diff --git a/packages/api/src/jobs/notifications/notifyAllUsers.sql b/packages/api/src/jobs/notifications/notifyAllUsers.sql
new file mode 100644
index 0000000000..9c1c15b8ba
--- /dev/null
+++ b/packages/api/src/jobs/notifications/notifyAllUsers.sql
@@ -0,0 +1,50 @@
+-- This SQL is never executed by LiteFarm app or server code.
+-- It is intended for manual use in order to send a notification to all users.
+-- It could be modified to send to any arbitrary set of users.
+- The syntax of this "comment" is intentionally incorrect, to prevent running this file as a script.
+-- You should run the statements individually, modifying as you go.
+
+-- For safety, start a transaction. Before COMMIT; the changes will be visible to this session only.
+-- At any prior time, use ROLLBACK; to discard transaction changes.
+BEGIN TRANSACTION;
+
+-- Create the notification record.
+INSERT INTO notification (
+ title,
+ body,
+ farm_id,
+ created_at,
+ updated_at,
+ created_by_user_id,
+ updated_by_user_id,
+ variables,
+ context,
+ ref
+)
+VALUES (
+-- TODO: Fill in translated text from here ...
+ '{ "en": "English title", "es": "Spanish title", "pt": "Portuguese title", "fr": "French title" }', -- title
+ '{ "en": "English body", "es": "Spanish body", "pt": "Portuguese body", "fr": "French body" }', -- body
+-- ... to here.
+ NULL, -- farm_id
+ NOW(), -- created_at
+ NOW(), -- updated_at
+ '1', -- created_by_user_id
+ '1', -- updated_by_user_id
+ '[]'::jsonb, -- variables
+ '{}'::jsonb, -- context
+-- TODO: add "Take Me There" url
+ '{ "url": "/" }'::jsonb -- ref, alt form: '{ "entity": { "type": "INSERT_ENTITY_TYPE", "id": "INSERT_ENTITY_ID" } }'
+);
+
+-- Get id of the new notification.
+-- (Verify that the record returned is your notification.)
+SELECT * FROM notification ORDER BY created_at DESC LIMIT 1;
+
+-- "Send" notification to all users.
+-- TODO: Substitute your new notifications's id in the second line below.
+INSERT INTO notification_user (notification_id, user_id, alert, status, created_at, updated_at, created_by_user_id, updated_by_user_id)
+ SELECT 'SUBSTITUTE NEW NOTIFICATION ID HERE', user_id, TRUE, 'Unread', NOW(), NOW(), '1', '1' FROM users;
+
+-- Last chance to ROLLBACK; This will finalize changes.
+COMMIT;
\ No newline at end of file
diff --git a/packages/api/src/jobs/station_sync/countrySync.js b/packages/api/src/jobs/station_sync/countrySync.js
index d2856a94f5..235560c2ad 100644
--- a/packages/api/src/jobs/station_sync/countrySync.js
+++ b/packages/api/src/jobs/station_sync/countrySync.js
@@ -2,38 +2,43 @@ const { from } = require('rxjs');
const { delay, concatMap, catchError, finalize } = require('rxjs/operators');
const rp = require('request-promise');
-const knex = require('./../../util/knex')
const endPoints = require('../../endPoints');
-async function mapFarmsToCountryId(knex = knex) {
+async function mapFarmsToCountryId(knex) {
const countries = await knex('countries').select('id', 'country_name');
- const farms = await farmsWithNoCountryId();
+ const farms = await farmsWithNoCountryId(knex);
return new Promise((resolve) => {
from(farms)
.pipe(
- concatMap((field) =>
- from(getCountryIdFromFarm(field))
- .pipe(delay(1000)),
- ),
+ concatMap((field) => from(getCountryIdFromFarm(field)).pipe(delay(1000))),
catchError((error) => {
console.error(error);
}),
finalize(() => resolve()),
- ).subscribe(async (farmData) => {
- const { farm_id, results } = farmData;
- const country = results[0].address_components.find((component) =>
- component.types.includes('country'),
- )?.long_name;
- country && await insertCountryIdToFarm(farm_id, country, countries);
- })
-
- })
+ )
+ .subscribe(async (farmData) => {
+ const { farm_id, results } = farmData;
+ let country;
+ results.find((place) =>
+ place?.address_components?.find((component) => {
+ if (component?.types?.includes?.('country')) {
+ country = component.long_name;
+ return true;
+ }
+ return false;
+ }),
+ );
+ country && (await insertCountryIdToFarm(knex, farm_id, country, countries));
+ });
+ });
}
-const farmsWithNoCountryId = async () => {
- const data = await knex.raw('SELECT farm_id, grid_points FROM farm WHERE country_id IS NULL AND grid_points IS NOT NULL');
+const farmsWithNoCountryId = async (knex) => {
+ const data = await knex.raw(
+ 'SELECT farm_id, grid_points FROM farm WHERE country_id IS NULL AND grid_points IS NOT NULL',
+ );
return data.rows;
-}
+};
function getCountryIdFromFarm({ farm_id, grid_points }) {
const options = {
@@ -42,17 +47,22 @@ function getCountryIdFromFarm({ farm_id, grid_points }) {
latlng: `${grid_points.lat},${grid_points.lng}`,
key: process.env.GOOGLE_API_KEY,
},
- }
+ };
return rp(options).then((result) => {
- return Object.assign(JSON.parse(result), { farm_id })
+ return Object.assign(JSON.parse(result), { farm_id });
});
}
-
-async function insertCountryIdToFarm(farm, country, countries) {
+async function insertCountryIdToFarm(knex, farm, country, countries) {
if (country && country !== '') {
- const { id } = countries.find(c => c.country_name === country);
- await knex('farm').update({ country_id: id }).where({ farm_id: farm })
+ const lookup = countries.find((c) => c.country_name === country);
+ if (lookup?.id) {
+ await knex('farm').update({ country_id: lookup.id }).where({ farm_id: farm });
+ } else {
+ console.log(`Found no country matching '${country}'; farm_id ${farm}`);
+ }
+ } else {
+ console.log(`Found no country for farm_id ${farm}`);
}
}
diff --git a/packages/api/src/jobs/station_sync/updateTimeZoneOffsets.js b/packages/api/src/jobs/station_sync/updateTimeZoneOffsets.js
new file mode 100644
index 0000000000..05d068f1af
--- /dev/null
+++ b/packages/api/src/jobs/station_sync/updateTimeZoneOffsets.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const { Client } = require('@googlemaps/google-maps-services-js');
+
+const client = new Client({});
+
+async function mapTimeZoneOffsetsToFarms(knex) {
+ const date = new Date(Date.now());
+ const farmsWithLatLng = await knex('farm').select('*').whereNotNull('grid_points');
+ for (const farm of farmsWithLatLng) {
+ try {
+ const timeZone = await client.timezone({
+ params: {
+ location: farm.grid_points,
+ timestamp: date,
+ key: process.env.GOOGLE_API_KEY,
+ },
+ });
+ await knex('farm')
+ .update('utc_offset', timeZone.data.rawOffset)
+ .where('farm_id', farm.farm_id);
+ } catch (e) {
+ switch (e.response?.data?.status) {
+ case 'OVER_QUERY_LIMIT':
+ console.log('Hit query limit for timezones API: waiting for query limit to reset');
+ await new Promise((resolve) => setTimeout(resolve, 60000)); // Rate limit is on a per-minute basis
+ try {
+ const timeZone = await client.timezone({
+ params: {
+ location: farm.grid_points,
+ timestamp: new Date(Date.now()),
+ key: process.env.GOOGLE_API_KEY,
+ },
+ });
+ await knex('farm')
+ .update('utc_offset', timeZone.data.rawOffset)
+ .where('farm_id', farm.farm_id);
+ } catch (e) {
+ console.log(e);
+ }
+ break;
+ case 'OVER_DAILY_LIMIT':
+ console.log(
+ 'Over the daily limit fot the timezones API. Please double check credentials are valid and try again tomorrow',
+ );
+ throw new Error('OVER_DAILY_LIMIT');
+ default:
+ console.log(`Unable to set a timezone for farm: ${farm.farm_name}`);
+ break;
+ }
+ }
+ }
+}
+
+module.exports = mapTimeZoneOffsetsToFarms;
diff --git a/packages/api/src/middleware/acl/checkJwt.js b/packages/api/src/middleware/acl/checkJwt.js
index 63992ae145..eae63af2f8 100644
--- a/packages/api/src/middleware/acl/checkJwt.js
+++ b/packages/api/src/middleware/acl/checkJwt.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (checkJwt.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,7 +15,6 @@
const jwt = require('express-jwt');
-
const checkJwt = jwt({
secret: process.env.JWT_SECRET,
algorithms: ['HS256'],
@@ -26,6 +25,9 @@ const checkJwt = jwt({
'/password_reset',
'/user/accept_invitation',
'/user_farm/accept_invitation',
+ '/notification_user/subscribe',
+ /\/time_notification\//i,
+ /\/farm\/utc_offset_by_range\//i,
],
});
diff --git a/packages/api/src/middleware/acl/checkSchedulerJwt.js b/packages/api/src/middleware/acl/checkSchedulerJwt.js
new file mode 100644
index 0000000000..81679a4499
--- /dev/null
+++ b/packages/api/src/middleware/acl/checkSchedulerJwt.js
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const jwt = require('express-jwt');
+
+const checkSchedulerJwt = jwt({
+ secret: process.env.JWT_SCHEDULER_SECRET,
+ algorithms: ['HS256'],
+ requestProperty: 'auth',
+});
+
+module.exports = checkSchedulerJwt;
diff --git a/packages/api/src/middleware/acl/checkScope.js b/packages/api/src/middleware/acl/checkScope.js
index 280a9d9fd0..bdbc40bb49 100644
--- a/packages/api/src/middleware/acl/checkScope.js
+++ b/packages/api/src/middleware/acl/checkScope.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (checkScope.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,16 +17,21 @@ const userFarmModel = require('../../models/userFarmModel');
const getScopes = async (user_id, farm_id, { checkConsent }) => {
// essential to fetch the most updated userFarm info to know user's most updated granted access
- const permissionQuery = userFarmModel
- .query()
- .distinct('permissions.name', 'userFarm.role_id')
- .join('rolePermissions', 'userFarm.role_id', 'rolePermissions.role_id')
- .join('permissions', 'permissions.permission_id', 'rolePermissions.permission_id')
- .where('userFarm.farm_id', farm_id)
- .where('userFarm.user_id', user_id)
- .where('userFarm.status', 'Active');
+ try {
+ const permissionQuery = userFarmModel
+ .query()
+ .distinct('permissions.name', 'userFarm.role_id')
+ .join('rolePermissions', 'userFarm.role_id', 'rolePermissions.role_id')
+ .join('permissions', 'permissions.permission_id', 'rolePermissions.permission_id')
+ .where('userFarm.farm_id', farm_id)
+ .where('userFarm.user_id', user_id)
+ .where('userFarm.status', 'Active');
- return checkConsent ? permissionQuery.where('userFarm.has_consent', true) : permissionQuery;
+ return checkConsent ? permissionQuery.where('userFarm.has_consent', true) : permissionQuery;
+ } catch (error) {
+ console.log('getScopes query error', error);
+ return [];
+ }
};
/**
@@ -51,22 +56,28 @@ const checkScope = (expectedScopes, { checkConsent = true } = {}) => {
const { user_id } = req.user;
const { farm_id } = headers; // these are the minimum props needed for most endpoints' authorization
- if (!user_id) return res.status(400).send('Missing user_id in headers');
- if (!farm_id) return res.status(400).send('Missing farm_id in headers');
-
- const scopes = await getScopes(user_id, farm_id, { checkConsent });
+ if (!user_id || user_id === 'undefined')
+ return res.status(400).send('Missing user_id in headers');
+ if (!farm_id || farm_id === 'undefined')
+ return res.status(400).send('Missing farm_id in headers');
+ try {
+ const scopes = await getScopes(user_id, farm_id, { checkConsent });
- const allowed = expectedScopes.some(function (expectedScope) {
- return scopes.find((permission) => permission.name === expectedScope);
- });
- if (scopes.length) {
- req.role = scopes[0].role_id;
+ const allowed = expectedScopes.some(function (expectedScope) {
+ return scopes.find((permission) => permission.name === expectedScope);
+ });
+ if (scopes.length) {
+ req.role = scopes[0].role_id;
+ }
+ return allowed
+ ? next()
+ : res
+ .status(403)
+ .send(`User does not have the following permission(s): ${expectedScopes.join(', ')}`);
+ } catch (error) {
+ console.log('Error checking permissions', error);
+ return res.status(403).send('Error checking permissions');
}
- return allowed
- ? next()
- : res
- .status(403)
- .send(`User does not have the following permission(s): ${expectedScopes.join(', ')}`);
};
};
diff --git a/packages/api/src/middleware/acl/hasTimeNotificationsAccess.js b/packages/api/src/middleware/acl/hasTimeNotificationsAccess.js
new file mode 100644
index 0000000000..be82c36c64
--- /dev/null
+++ b/packages/api/src/middleware/acl/hasTimeNotificationsAccess.js
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+/**
+ * Middleware for checking whether or not the client is authorized to
+ * access timed notifications.
+ * @param {Request} req - The HTTP request object.
+ * @param {Response} res - The HTTP response object.
+ * @param {Function} next - Calls the next middleware in the stack
+ */
+const hasTimeNotificationsAccess = (req, res, next) => {
+ if (req.auth.requestTimedNotifications === true) {
+ next();
+ } else {
+ return res.status(403).send('Not authorized to access timed notifications');
+ }
+};
+module.exports = hasTimeNotificationsAccess;
diff --git a/packages/api/src/middleware/validation/assignTask.js b/packages/api/src/middleware/validation/assignTask.js
new file mode 100644
index 0000000000..4bac7580b6
--- /dev/null
+++ b/packages/api/src/middleware/validation/assignTask.js
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (authFarmId.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const userFarmModel = require('../../models/userFarmModel');
+const TaskModel = require('../../models/taskModel');
+
+const adminRoles = [1, 2, 5];
+
+async function validateAssigneeId(req, res, next) {
+ const { user_id } = req.user;
+ const { farm_id } = req.headers;
+ const { assignee_user_id } = req.body;
+ if (!adminRoles.includes(req.role) && user_id !== assignee_user_id && assignee_user_id !== null) {
+ return res.status(403).send('Not authorized to assign other people for this task');
+ }
+
+ // if the assignee_user_id is null, this means that the task is 'Unassigned' which is a valid
+ if (assignee_user_id === null) {
+ return next();
+ }
+
+ const userFarm = await userFarmModel
+ .query()
+ .where({
+ user_id: assignee_user_id,
+ farm_id,
+ })
+ .whereIn('status', ['Active', 'Invited']);
+ if (!userFarm?.length) {
+ return res.status(400).send('Assignee does not have access to the farm');
+ }
+ return next();
+}
+
+async function checkTaskStatusForAssignment(req, res, next) {
+ const { task_id } = req.params;
+
+ const checkTaskStatus = await TaskModel.getTaskStatus(task_id);
+ if (checkTaskStatus.complete_date || checkTaskStatus.abandon_date) {
+ return res.status(400).send('Task has already been completed or abandoned');
+ }
+
+ if (
+ !adminRoles.includes(req.role) &&
+ checkTaskStatus.assignee_user_id != req.user.user_id &&
+ checkTaskStatus.assignee_user_id !== null
+ ) {
+ return res
+ .status(403)
+ .send('Farm workers are not allowed to reassign a task assigned to another worker');
+ }
+
+ req.checkTaskStatus = checkTaskStatus;
+
+ next();
+}
+
+module.exports = { validateAssigneeId, checkTaskStatusForAssignment };
diff --git a/packages/api/src/middleware/validation/completeManagementPlanTaskCheck.js b/packages/api/src/middleware/validation/completeManagementPlanTaskCheck.js
index 4323bebcee..d65caffd74 100644
--- a/packages/api/src/middleware/validation/completeManagementPlanTaskCheck.js
+++ b/packages/api/src/middleware/validation/completeManagementPlanTaskCheck.js
@@ -19,7 +19,7 @@ const taskModel = require('../../models/taskModel');
const validateManagementPlanTasks = async (req, res, next) => {
const tasks = await taskModel.query().join('management_tasks', 'management_tasks.task_id', 'task.task_id')
.join('planting_management_plan', 'planting_management_plan.planting_management_plan_id', 'management_tasks.planting_management_plan_id')
- .where('planting_management_plan.management_plan_id', req.params.management_plan_id).whereNull('completed_time').whereNull('abandoned_time');
+ .where('planting_management_plan.management_plan_id', req.params.management_plan_id).whereNull('complete_date').whereNull('abandon_date');
if (tasks.length) return res.status(400).send(`Can't complete or abandon management plans with pending tasks`);
return next();
};
diff --git a/packages/api/src/middleware/validation/deleteLocation.js b/packages/api/src/middleware/validation/deleteLocation.js
index 74bae68bc7..2edb9d7a20 100644
--- a/packages/api/src/middleware/validation/deleteLocation.js
+++ b/packages/api/src/middleware/validation/deleteLocation.js
@@ -13,28 +13,96 @@
* GNU General Public License for more details, see .
*/
-const plantingManagementPlanModel = require('../../models/plantingManagementPlanModel');
-const taskModel = require('../../models/taskModel');
-const { raw } = require('objection');
+const { Model } = require('objection');
+const managementPlanModel = require('../../models/managementPlanModel');
async function validateLocationDependency(req, res, next) {
-
const location_id = req?.params?.location_id;
- const managementPlans = await plantingManagementPlanModel.query()
- .join('management_plan', 'management_plan.management_plan_id', 'planting_management_plan.management_plan_id')
- .where('planting_management_plan.location_id', location_id)
- .where('management_plan.deleted', false).whereNull('complete_date').whereNull('abandon_date');
- if (managementPlans.length) {
- return res.status(400).send('Location cannot be deleted when it has a managementPlan');
+ const tasks = await Model.knex().raw(
+ `
+ SELECT DISTINCT lt.task_id,
+ lt.location_id
+ FROM location_tasks lt
+ JOIN task t on t.task_id = lt.task_id
+ WHERE lt.location_id = :location_id
+ AND t.complete_date is null
+ AND t.abandon_date is null
+ UNION
+ SELECT DISTINCT mt.task_id, pmp.location_id
+ FROM management_tasks mt
+ JOIN task t on t.task_id = mt.task_id
+ JOIN planting_management_plan pmp on pmp.planting_management_plan_id = mt.planting_management_plan_id
+ WHERE pmp.location_id = :location_id
+ AND t.complete_date is null
+ AND t.abandon_date is null
+ UNION
+ SELECT DISTINCT pt.task_id, pmp.location_id
+ from plant_task pt
+ JOIN task t on t.task_id = pt.task_id
+ JOIN planting_management_plan pmp on pt.planting_management_plan_id = pmp.planting_management_plan_id
+ WHERE pmp.location_id = :location_id
+ AND t.complete_date is null
+ AND t.abandon_date is null
+ UNION
+ SELECT DISTINCT tt.task_id, pmp.location_id
+ from transplant_task tt
+ JOIN task t on t.task_id = tt.task_id
+ JOIN planting_management_plan pmp on tt.planting_management_plan_id = pmp.planting_management_plan_id
+ WHERE pmp.location_id = :location_id
+ AND t.complete_date is null
+ AND t.abandon_date is null
+ `,
+ { location_id },
+ );
+ if (tasks.rows.length) {
+ return res.status(400).send('Location cannot be deleted when it has incomplete tasks');
}
- const tasks = await taskModel.query().whereNotDeleted()
- .join('location_tasks', 'location_tasks.task_id', 'task.task_id')
- .where('location_tasks.location_id', location_id)
- .whereNull('task.completed_time')
- .whereNull('task.abandoned_time');
- if (tasks.length) {
- return res.status(400).send('Location cannot be deleted when it is referenced by a task');
+
+ const managementPlans = await managementPlanModel
+ .query()
+ .whereNotDeleted()
+ .withGraphJoined(
+ `[crop_variety.[crop], crop_management_plan.[planting_management_plans.[transplant_task.[task],
+ plant_task.[task] ]]]`,
+ {
+ aliases: {
+ crop_management_plan: 'cmp',
+ planting_management_plans: 'pmps',
+ },
+ },
+ )
+ .where('crop_variety.farm_id', req.headers.farm_id)
+ .where('management_plan.complete_date', null)
+ .where('management_plan.abandon_date', null);
+ //TODO: deprecate req.headers.farm_id and move farm_id to req.context in hasFarmAccess
+
+ for (const {
+ crop_management_plan: { planting_management_plans },
+ } of managementPlans) {
+ let managementPlanLocationId;
+ let completeDate;
+ for (const plantingManagementPlan of planting_management_plans) {
+ if (
+ plantingManagementPlan.transplant_task &&
+ (plantingManagementPlan.transplant_task.task.complete_date > completeDate || !completeDate)
+ ) {
+ completeDate = plantingManagementPlan.transplant_task.task.complete_date;
+ managementPlanLocationId = plantingManagementPlan.location_id;
+ } else if (
+ !completeDate &&
+ !managementPlanLocationId &&
+ (plantingManagementPlan.plant_task ||
+ (plantingManagementPlan.plant_task === null &&
+ plantingManagementPlan.transplant_task === null)) &&
+ plantingManagementPlan.location_id
+ ) {
+ managementPlanLocationId = plantingManagementPlan.location_id;
+ }
+ }
+ if (managementPlanLocationId === location_id) {
+ return res.status(400).send('Location cannot be deleted when it has a managementPlan');
+ }
}
return next();
diff --git a/packages/api/src/models/cropModel.js b/packages/api/src/models/cropModel.js
index f3f348ba23..4bef1a3c9d 100644
--- a/packages/api/src/models/cropModel.js
+++ b/packages/api/src/models/cropModel.js
@@ -186,7 +186,10 @@ class Crop extends BaseModel {
yield_per_area: { type: ['number', null] },
average_seed_weight: { type: ['number', null] },
yield_per_plant: { type: ['number', null] },
- seeding_type: { type: ['string', null], enum: ['SEED', 'SEEDLING_OR_PLANTING_STOCK', null] },
+ seeding_type: {
+ type: ['string', null],
+ enum: ['SEED', 'SEEDLING_OR_PLANTING_STOCK', null],
+ },
lifecycle: { type: ['string', null], enum: ['ANNUAL', 'PERENNIAL', null] },
needs_transplant: { type: ['boolean', null] },
germination_days: { type: ['integer', null] },
@@ -199,7 +202,7 @@ class Crop extends BaseModel {
},
plant_spacing: { type: ['number', null] },
seeding_rate: { type: ['number', null] },
- hs_code_id: { type: ['string', null] },
+ hs_code_id: { type: ['string', 'number', null] },
...this.baseProperties,
},
additionalProperties: false,
diff --git a/packages/api/src/models/cropVarietyModel.js b/packages/api/src/models/cropVarietyModel.js
index 2d8d2793fd..edd611b081 100644
--- a/packages/api/src/models/cropVarietyModel.js
+++ b/packages/api/src/models/cropVarietyModel.js
@@ -127,7 +127,7 @@ class CropVariety extends BaseModel {
harvest_days: { type: ['integer', null] },
termination_days: { type: ['integer', null] },
seeding_rate: { type: ['number', null] },
- hs_code_id: { type: ['string', null] },
+ hs_code_id: { type: ['string', 'number', null] },
...this.baseProperties,
},
additionalProperties: false,
diff --git a/packages/api/src/models/documentModel.js b/packages/api/src/models/documentModel.js
index 72496a0b8c..f95b2bb87f 100644
--- a/packages/api/src/models/documentModel.js
+++ b/packages/api/src/models/documentModel.js
@@ -25,7 +25,6 @@ class Document extends baseModel {
return 'document_id';
}
-
static get jsonSchema() {
return {
type: 'object',
@@ -40,10 +39,20 @@ class Document extends baseModel {
no_expiration: { type: ['boolean', null] },
type: {
type: ['string', null],
- enum: ['CLEANING_PRODUCT', 'CROP_COMPLIANCE', 'FERTILIZING_PRODUCT',
- 'PEST_CONTROL_PRODUCT', 'SOIL_AMENDMENT', 'SOIL_SAMPLE_RESULTS',
- 'WATER_SAMPLE_RESULTS', 'OTHER'],
+ enum: [
+ 'CLEANING_PRODUCT',
+ 'CROP_COMPLIANCE',
+ 'FERTILIZING_PRODUCT',
+ 'PEST_CONTROL_PRODUCT',
+ 'SOIL_AMENDMENT',
+ 'SOIL_SAMPLE_RESULTS',
+ 'WATER_SAMPLE_RESULTS',
+ 'INVOICES',
+ 'RECEIPTS',
+ 'OTHER',
+ ],
},
+ archived: { type: 'boolean' },
...this.baseProperties,
},
additionalProperties: false,
diff --git a/packages/api/src/models/emailTokenModel.js b/packages/api/src/models/emailTokenModel.js
index 0cf793f335..5788087dcf 100644
--- a/packages/api/src/models/emailTokenModel.js
+++ b/packages/api/src/models/emailTokenModel.js
@@ -1,33 +1,91 @@
-const Model = require('objection').Model;
-
-class emailTokenModel extends Model {
- static get tableName() {
- return 'emailToken';
- }
-
- static get idColumn() {
- return ['invitation_id'];
- }
-
- // Optional JSON schema. This is not the database schema! Nothing is generated
- // based on this. This is only used for validation. Whenever a model instance
- // is created it is checked against this schema. http://json-schema.org/.
- static get jsonSchema() {
- return {
- type: 'object',
- required: ['user_id', 'farm_id'],
-
- properties: {
- user_id: { type: 'string' },
- farm_id: { type: 'string' },
- invitation_id: { type: 'string' },
- times_sent: { type: 'integer' },
- created_at: { type: 'date-time' },
- updated_at: { type: 'date-time' },
- },
- additionalProperties: false,
- };
- }
-}
-
-module.exports = emailTokenModel;
+const { createToken } = require('../util/jwt');
+const { emails, sendEmail } = require('../templates/sendEmailTemplate');
+const Model = require('objection').Model;
+
+class emailTokenModel extends Model {
+ static get tableName() {
+ return 'emailToken';
+ }
+
+ static get idColumn() {
+ return ['invitation_id'];
+ }
+
+ // Optional JSON schema. This is not the database schema! Nothing is generated
+ // based on this. This is only used for validation. Whenever a model instance
+ // is created it is checked against this schema. http://json-schema.org/.
+ static get jsonSchema() {
+ return {
+ type: 'object',
+ required: ['user_id', 'farm_id'],
+
+ properties: {
+ user_id: { type: 'string' },
+ farm_id: { type: 'string' },
+ invitation_id: { type: 'string' },
+ times_sent: { type: 'integer' },
+ created_at: { type: 'date-time' },
+ updated_at: { type: 'date-time' },
+ },
+ additionalProperties: false,
+ };
+ }
+
+ static async createTokenSendEmail(user, userFarm, farm_name) {
+ console.log('createTokenSendEmail');
+ let token;
+ const emailSent = await emailTokenModel
+ .query()
+ .where({
+ user_id: userFarm.user_id,
+ farm_id: userFarm.farm_id,
+ })
+ .first();
+ if (!emailSent || emailSent.times_sent < 3) {
+ const timesSent = emailSent && emailSent.times_sent ? ++emailSent.times_sent : 1;
+ if (timesSent === 1) {
+ const emailToken = await emailTokenModel
+ .query()
+ .insert({
+ user_id: userFarm.user_id,
+ farm_id: userFarm.farm_id,
+ times_sent: timesSent,
+ })
+ .returning('*');
+ token = await createToken('invite', {
+ ...user,
+ ...userFarm,
+ invitation_id: emailToken.invitation_id,
+ });
+ } else {
+ const [emailToken] = await emailTokenModel
+ .query()
+ .patch({ times_sent: timesSent })
+ .where({
+ user_id: user.user_id,
+ farm_id: userFarm.farm_id,
+ })
+ .returning('*');
+ token = await createToken('invite', {
+ ...user,
+ ...userFarm,
+ invitation_id: emailToken.invitation_id,
+ });
+ }
+ await this.sendTokenEmail(farm_name, user, token);
+ }
+ }
+
+ static async sendTokenEmail(farm, user, token) {
+ const sender = 'system@litefarm.org';
+ const template_path = emails.INVITATION;
+ await sendEmail(
+ template_path,
+ { first_name: user.first_name, farm, locale: user.language_preference, farm_name: farm },
+ user.email,
+ { sender, buttonLink: `/callback/?invite_token=${token}` },
+ );
+ }
+}
+
+module.exports = emailTokenModel;
diff --git a/packages/api/src/models/farmModel.js b/packages/api/src/models/farmModel.js
index e62cfb4fc6..03caaf34d3 100644
--- a/packages/api/src/models/farmModel.js
+++ b/packages/api/src/models/farmModel.js
@@ -25,7 +25,6 @@ class Farm extends baseModel {
return [...super.hidden, 'sandbox_farm'];
}
-
static get idColumn() {
return 'farm_id';
}
@@ -63,7 +62,176 @@ class Farm extends baseModel {
},
currency: {
type: 'string',
- enum: ['AFN', 'ALL', 'DZD', 'USD', 'EUR', 'AOA', 'XCD', 'ARS', 'AMD', 'AWG', 'AUD', 'AZN', 'BSD', 'BHD', 'BDT', 'BBD', 'BYR', 'BZD', 'XOF', 'BMD', 'BTN', 'INR', 'BOB', 'BOV', 'BAM', 'BWP', 'NOK', 'BRL', 'BND', 'BGN', 'BIF', 'CVE', 'KHR', 'XAF', 'CAD', 'KYD', 'CLF', 'CLP', 'CNY', 'COP', 'COU', 'KMF', 'CDF', 'NZD', 'CRC', 'HRK', 'CUC', 'CUP', 'ANG', 'CZK', 'DKK', 'DJF', 'DOP', 'EGP', 'SVC', 'ERN', 'ETB', 'FKP', 'FJD', 'XPF', 'GMD', 'GEL', 'GHS', 'GIP', 'GTQ', 'GBP', 'GNF', 'GYD', 'HTG', 'HNL', 'HKD', 'HUF', 'ISK', 'IDR', 'XDR', 'IRR', 'IQD', 'ILS', 'JMD', 'JPY', 'JOD', 'KZT', 'KES', 'KPW', 'KRW', 'KWD', 'KGS', 'LAK', 'LBP', 'LSL', 'ZAR', 'LRD', 'LYD', 'CHF', 'MOP', 'MKD', 'MGA', 'MWK', 'MYR', 'MVR', 'MRU', 'MUR', 'XUA', 'MXN', 'MXV', 'MDL', 'MNT', 'MAD', 'MZN', 'MMK', 'NAD', 'NPR', 'NIO', 'NGN', 'OMR', 'PKR', 'PAB', 'PGK', 'PYG', 'PEN', 'PHP', 'PLN', 'QAR', 'RON', 'RUB', 'RWF', 'SHP', 'WST', 'STN', 'SAR', 'RSD', 'SCR', 'SLL', 'SGD', 'XSU', 'SBD', 'SOS', 'SSP', 'LKR', 'SDG', 'SRD', 'SZL', 'SEK', 'CHE', 'CHW', 'SYP', 'TWD', 'TJS', 'TZS', 'THB', 'TOP', 'TTD', 'TND', 'TRY', 'TMT', 'UGX', 'UAH', 'AED', 'USN', 'UYI', 'UYU', 'UZS', 'VUV', 'VEF', 'VND', 'YER', 'ZMW', 'ZWL'],
+ enum: [
+ 'AFN',
+ 'ALL',
+ 'DZD',
+ 'USD',
+ 'EUR',
+ 'AOA',
+ 'XCD',
+ 'ARS',
+ 'AMD',
+ 'AWG',
+ 'AUD',
+ 'AZN',
+ 'BSD',
+ 'BHD',
+ 'BDT',
+ 'BBD',
+ 'BYR',
+ 'BZD',
+ 'XOF',
+ 'BMD',
+ 'BTN',
+ 'INR',
+ 'BOB',
+ 'BOV',
+ 'BAM',
+ 'BWP',
+ 'NOK',
+ 'BRL',
+ 'BND',
+ 'BGN',
+ 'BIF',
+ 'CVE',
+ 'KHR',
+ 'XAF',
+ 'CAD',
+ 'KYD',
+ 'CLF',
+ 'CLP',
+ 'CNY',
+ 'COP',
+ 'COU',
+ 'KMF',
+ 'CDF',
+ 'NZD',
+ 'CRC',
+ 'HRK',
+ 'CUC',
+ 'CUP',
+ 'ANG',
+ 'CZK',
+ 'DKK',
+ 'DJF',
+ 'DOP',
+ 'EGP',
+ 'SVC',
+ 'ERN',
+ 'ETB',
+ 'FKP',
+ 'FJD',
+ 'XPF',
+ 'GMD',
+ 'GEL',
+ 'GHS',
+ 'GIP',
+ 'GTQ',
+ 'GBP',
+ 'GNF',
+ 'GYD',
+ 'HTG',
+ 'HNL',
+ 'HKD',
+ 'HUF',
+ 'ISK',
+ 'IDR',
+ 'XDR',
+ 'IRR',
+ 'IQD',
+ 'ILS',
+ 'JMD',
+ 'JPY',
+ 'JOD',
+ 'KZT',
+ 'KES',
+ 'KPW',
+ 'KRW',
+ 'KWD',
+ 'KGS',
+ 'LAK',
+ 'LBP',
+ 'LSL',
+ 'ZAR',
+ 'LRD',
+ 'LYD',
+ 'CHF',
+ 'MOP',
+ 'MKD',
+ 'MGA',
+ 'MWK',
+ 'MYR',
+ 'MVR',
+ 'MRU',
+ 'MUR',
+ 'XUA',
+ 'MXN',
+ 'MXV',
+ 'MDL',
+ 'MNT',
+ 'MAD',
+ 'MZN',
+ 'MMK',
+ 'NAD',
+ 'NPR',
+ 'NIO',
+ 'NGN',
+ 'OMR',
+ 'PKR',
+ 'PAB',
+ 'PGK',
+ 'PYG',
+ 'PEN',
+ 'PHP',
+ 'PLN',
+ 'QAR',
+ 'RON',
+ 'RUB',
+ 'RWF',
+ 'SHP',
+ 'WST',
+ 'STN',
+ 'SAR',
+ 'RSD',
+ 'SCR',
+ 'SLL',
+ 'SGD',
+ 'XSU',
+ 'SBD',
+ 'SOS',
+ 'SSP',
+ 'LKR',
+ 'SDG',
+ 'SRD',
+ 'SZL',
+ 'SEK',
+ 'CHE',
+ 'CHW',
+ 'SYP',
+ 'TWD',
+ 'TJS',
+ 'TZS',
+ 'THB',
+ 'TOP',
+ 'TTD',
+ 'TND',
+ 'TRY',
+ 'TMT',
+ 'UGX',
+ 'UAH',
+ 'AED',
+ 'USN',
+ 'UYI',
+ 'UYU',
+ 'UZS',
+ 'VUV',
+ 'VEF',
+ 'VND',
+ 'YER',
+ 'ZMW',
+ 'ZWL',
+ ],
},
date_format: {
type: 'string',
@@ -72,6 +240,7 @@ class Farm extends baseModel {
},
},
default_initial_location_id: { type: ['string', null] },
+ utc_offset: { type: 'integer' },
...this.baseProperties,
// sandbox_bool: { type: 'boolean' },
},
@@ -106,7 +275,6 @@ class Farm extends baseModel {
},
};
}
-
}
module.exports = Farm;
diff --git a/packages/api/src/models/notificationModel.js b/packages/api/src/models/notificationModel.js
new file mode 100644
index 0000000000..4eccd3f775
--- /dev/null
+++ b/packages/api/src/models/notificationModel.js
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const baseModel = require('./baseModel');
+
+class Notification extends baseModel {
+ static get tableName() {
+ return 'notification';
+ }
+
+ static get idColumn() {
+ return 'notification_id';
+ }
+
+ // Optional JSON schema. This is not the database schema! Nothing is generated
+ // based on this. This is only used for validation. Whenever a model instance
+ // is created it is checked against this schema. http://json-schema.org/.
+ static get jsonSchema() {
+ return {
+ type: 'object',
+ properties: {
+ notification_id: { type: 'string' },
+ translation_key: { type: 'string' },
+ variables: { type: 'array' },
+ context: { type: 'object' },
+ farm_id: { type: 'string' },
+ title: { type: 'object' },
+ body: { type: 'object' },
+ ref: { type: 'object' },
+ ...this.baseProperties,
+ },
+ additionalProperties: false,
+ };
+ }
+}
+
+module.exports = Notification;
diff --git a/packages/api/src/models/notificationUserModel.js b/packages/api/src/models/notificationUserModel.js
new file mode 100644
index 0000000000..4bc77d8f2d
--- /dev/null
+++ b/packages/api/src/models/notificationUserModel.js
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const Model = require('objection').Model;
+const baseModel = require('./baseModel');
+const Notification = require('./notificationModel');
+
+/**
+ * Models data persistence for users' notifications.
+ */
+class NotificationUser extends baseModel {
+ /**
+ * Tracks open subscription channels for server-sent events. To support multiple sessions by the same user,
+ * keys are user IDs; values are Maps with timestamp keys and HTTP response object values.
+ * @member {Map}
+ * @static
+ */
+ static subscriptions = new Map();
+
+ /**
+ * Identifies the database table for this Model.
+ * @static
+ * @returns {string} Names of the database table.
+ */
+ static get tableName() {
+ return 'notification_user';
+ }
+
+ /**
+ * Identifies the primary key fields for this Model.
+ * @static
+ * @returns {string[]} Names of the primary key fields.
+ */
+ static get idColumn() {
+ return ['notification_id', 'user_id'];
+ }
+
+ /**
+ * Supports validating instances of this Model class.
+ * @static
+ * @returns {Object} A description of valid instances.
+ */
+ static get jsonSchema() {
+ return {
+ type: 'object',
+ required: ['user_id'],
+ properties: {
+ notification_id: { type: 'string' },
+ user_id: { type: 'string' },
+ alert: { type: 'boolean' },
+ status: {
+ type: 'string',
+ /**
+ * @name userNotificationStatusType
+ * @desc Enumerated type for user notification status.
+ * @enum
+ * */
+ enum: ['Unread', 'Read', 'Archived'],
+ },
+ ...this.baseProperties,
+ },
+ additionalProperties: false,
+ };
+ }
+
+ /**
+ * Defines this Model's associations with other Models.
+ * @static
+ * @returns {Object} A description of Model associations.
+ */
+ static get relationMappings() {
+ return {
+ notification: {
+ relation: Model.BelongsToOneRelation,
+ modelClass: Notification,
+ join: {
+ from: 'notification_user.notification_id',
+ to: 'notification.notification_id',
+ },
+ },
+ };
+ }
+
+ /**
+ * Retrieves notifications for a specified user and farm context.
+ * @param {uuid} farm_id - The farm context.
+ * @param {uuid} user_id - The specified user.
+ * @static
+ * @async
+ * @returns {Promise} An array of data objects.
+ */
+ static async getNotificationsForFarmUser(farm_id, user_id) {
+ return NotificationUser.query()
+ .join('notification', 'notification_user.notification_id', 'notification.notification_id')
+ .select(
+ 'notification.notification_id',
+ 'user_id',
+ 'alert',
+ 'status',
+ 'title',
+ 'body',
+ 'variables',
+ 'ref',
+ 'context',
+ 'notification_user.created_at',
+ )
+ .whereNotDeleted()
+ .where((builder) => {
+ builder.whereNull('farm_id').orWhere({ farm_id });
+ })
+ .andWhere({ user_id })
+ .andWhere({ 'notification.deleted': false })
+ .orderBy('notification_user.created_at', 'desc')
+ .limit(100)
+ .context({ showHidden: true });
+ }
+
+ /**
+ * Stores modifications for a set of user notifications
+ * @param {uuid} userId - The specified user.
+ * @param {uuid[]} notificationIds - An array of notification identifiers.
+ * @param {object} modifications - The altered data values.u
+ * @static
+ * @async
+ */
+ static async update(userId, notificationIds, modifications) {
+ await NotificationUser.query()
+ .patch(modifications)
+ .whereIn('notification_id', notificationIds)
+ .andWhere('user_id', userId)
+ .context({ user_id: userId });
+ }
+
+ /**
+ * Clears the alert indicator for a specified set of the user's notifications.
+ * @param {uuid} userId - The specified user.
+ * @param {uuid} farmId - The user session's current farm.
+ * @param {uuid[]} notificationIds - An array of notification identifiers.
+ * @static
+ * @async
+ */
+ static async clearAlerts(userId, farmId, notificationIds) {
+ const count = await NotificationUser.query()
+ .patch({ alert: false })
+ .whereIn('notification_id', notificationIds)
+ .andWhere('user_id', userId)
+ .andWhere('alert', true)
+ .context({ user_id: userId });
+ const userSubs = NotificationUser.subscriptions.get(userId);
+ userSubs?.forEach((subscriber) => {
+ subscriber?.forEach((subscription) => {
+ if (farmId === subscription.farm_id) {
+ subscription.sendAlert(-count);
+ }
+ });
+ });
+ }
+
+ /**
+ * Creates a notification and initiates status tracking for a specified set of recipients.
+ * @param {Object} notification - A notification to be created.
+ * @param {uuid[]} userIds - The user IDs of the recipients.
+ * @static
+ * @async
+ */
+ static async notify(notification, userIds) {
+ if (!userIds.length) return;
+ const { notification_id } = await Notification.query()
+ .insert(notification)
+ .context({ user_id: '1' });
+ await Promise.all(
+ userIds.map(async (user_id) => {
+ await NotificationUser.query()
+ .insert({ user_id, notification_id })
+ .context({ user_id: '1' });
+ }),
+ );
+ NotificationUser.alert(notification.farm_id, userIds);
+ }
+
+ /**
+ * Alerts any recipients with open subscription channels of a new notification.
+ * @param {uuid} farm_id - The farm context of the new notification (`null` for all farms).
+ * @param {uuid[]} userIds - The user IDs of the recipients.
+ * @static
+ */
+ static alert(farm_id, userIds) {
+ userIds.forEach((user_id) => {
+ const userSubs = NotificationUser.subscriptions.get(user_id);
+ userSubs?.forEach((subscriber) => {
+ subscriber?.forEach((subscription) => {
+ if (farm_id === subscription.farm_id || farm_id === null) {
+ subscription.sendAlert();
+ }
+ });
+ });
+ });
+ }
+}
+
+module.exports = NotificationUser;
diff --git a/packages/api/src/models/showedSpotlightModel.js b/packages/api/src/models/showedSpotlightModel.js
index 7f8da15390..4008714f07 100644
--- a/packages/api/src/models/showedSpotlightModel.js
+++ b/packages/api/src/models/showedSpotlightModel.js
@@ -47,6 +47,8 @@ class ShowedSpotlight extends Model {
adjust_line_end: { type: ['string', 'null'] },
navigation: { type: 'boolean' },
navigation_end: { type: ['string', 'null'] },
+ notification: { type: 'boolean' },
+ notification_end: { type: ['string', 'null'] },
introduce_map: { type: 'boolean' },
introduce_map_end: { type: ['string', 'null'] },
crop_catalog: { type: 'boolean' },
diff --git a/packages/api/src/models/taskModel.js b/packages/api/src/models/taskModel.js
index 0501b4abd9..c9d2867152 100644
--- a/packages/api/src/models/taskModel.js
+++ b/packages/api/src/models/taskModel.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (taskModel.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,7 +10,7 @@
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
+ * GNU General Public License for more details, see < .>
*/
const Model = require('objection').Model;
@@ -45,11 +45,10 @@ class TaskModel extends BaseModel {
duration: { type: ['number', null] },
wage_at_moment: { type: ['number', null] },
happiness: { anyOf: [{ type: 'integer', minimum: 0, maximum: 5 }, { type: 'null' }] },
- planned_time: { type: 'date-time' },
- completed_time: { anyOf: [{ type: 'null' }, { type: 'date-time' }] },
+ complete_date: { anyOf: [{ type: 'null' }, { type: 'date' }] },
late_time: { type: ['date-time', null] },
for_review_time: { type: ['date-time', null] },
- abandoned_time: { anyOf: [{ type: 'null' }, { type: 'date-time' }] },
+ abandon_date: { anyOf: [{ type: 'null' }, { type: 'date' }] },
abandonment_reason: {
type: 'string',
enum: [
@@ -140,10 +139,10 @@ class TaskModel extends BaseModel {
},
taskType: {
- relation: Model.HasManyRelation,
+ relation: Model.BelongsToOneRelation,
modelClass: require('./taskTypeModel'),
join: {
- from: 'task.type',
+ from: 'task.task_type_id',
to: 'task_type.task_type_id',
},
},
@@ -176,7 +175,6 @@ class TaskModel extends BaseModel {
},
to: 'planting_management_plan.planting_management_plan_id',
},
-
},
locations: {
modelClass: require('./locationModel'),
@@ -193,6 +191,160 @@ class TaskModel extends BaseModel {
},
};
}
+
+ /**
+ * Gets the assignee of a task.
+ * @param {number} taskId - the ID of the task.
+ * @static
+ * @async
+ * @returns {Object} - Object {assignee_user_id, assignee_role_id, wage_at_moment, override_hourly_wage}
+ */
+ static async getTaskAssignee(taskId) {
+ return await TaskModel.query()
+ .whereNotDeleted()
+ .join('users', 'task.assignee_user_id', 'users.user_id')
+ .join('userFarm as uf', 'users.user_id', 'uf.user_id')
+ .join('role', 'role.role_id', 'uf.role_id')
+ .select(
+ TaskModel.knex().raw(
+ 'users.user_id as assignee_user_id, role.role_id as assignee_role_id, task.wage_at_moment, task.override_hourly_wage',
+ ),
+ )
+ .where('task.task_id', taskId)
+ .first();
+ }
+
+ /**
+ * Gets the type of a task
+ * @param taskId {number} - id of the Task.
+ * @return {Promise}
+ * @static
+ * @async
+ */
+ static async getTaskType(taskId) {
+ return await TaskModel.query()
+ .join('task_type', 'task.task_type_id', 'task_type.task_type_id')
+ .whereNotDeleted()
+ .select('task_type.*')
+ .where('task.task_id', taskId)
+ .first();
+ }
+
+ /**
+ * Gets the tasks that are due this week and are unassigned
+ * @param {number} taskIds - the IDs of the task.
+ * @static
+ * @async
+ * @returns {Object} - Object {task_type_id, task_id}
+ */
+ static async getUnassignedTasksDueThisWeekFromIds(taskIds, isDayLaterThanUTC = false) {
+ const dayLaterInterval = isDayLaterThanUTC ? '"1 day"' : '"0 days"';
+ return await TaskModel.query().select('*').whereIn('task_id', taskIds).whereRaw(
+ `
+ task.assignee_user_id IS NULL
+ AND task.complete_date IS NULL
+ AND task.abandon_date IS NULL
+ AND task.due_date <= (now() + ('1 week')::interval + (?)::interval)::date
+ AND task.due_date >= (now() + (?)::interval)::date
+ `,
+ [dayLaterInterval, dayLaterInterval],
+ );
+ }
+
+ /**
+ * Gets the tasks that are due this week and are unassigned
+ * @param {uuid} taskId - the ID of the task whose status is being checked
+ * @static
+ * @async
+ * @returns {Object} - Object {complete_date, abandon_date, assignee_user_id, task_translation_key}
+ */
+ static async getTaskStatus(taskId) {
+ return await TaskModel.query()
+ .leftOuterJoin('task_type', 'task.task_type_id', 'task_type.task_type_id')
+ .select('complete_date', 'abandon_date', 'assignee_user_id', 'task_translation_key')
+ .where('task_id', taskId)
+ .andWhere('task.deleted', false)
+ .first();
+ }
+
+ /**
+ * Assign the task to the user with the given assigneeUserId.
+ * @param {uuid} taskId - the ID of the task
+ * @param {uuid} assigneeUserId - the ID of user whose the task is being assigned too
+ * @param {Object} user - the user who requested this task assignment
+ * @static
+ * @async
+ * @returns {Object} - Task Object
+ */
+ static async assignTask(taskId, assigneeUserId, user) {
+ return await TaskModel.query()
+ .context(user)
+ .patchAndFetchById(taskId, { assignee_user_id: assigneeUserId });
+ }
+
+ /**
+ * Assign tasks to the user with the given assigneeUserId.
+ * @param {uuid} taskIds - the IDs of the tasks
+ * @param {uuid} assigneeUserId - the ID of user whose the task is being assigned too
+ * @param {Object} user - the user who requested this task assignment
+ * @static
+ * @async
+ * @returns {Object} - Task Object
+ */
+ static async assignTasks(taskIds, assigneeUserId, user) {
+ return await TaskModel.query()
+ .context(user)
+ .patch({
+ assignee_user_id: assigneeUserId,
+ })
+ .whereIn('task_id', taskIds);
+ }
+
+ /**
+ * Checks whether a given user in a given farm has tasks that are due today.
+ * @param {string} userId user id
+ * @param {Array} taskIds task ids from a farm
+ * @static
+ * @async
+ * @returns {boolean} true if the user has tasks due today or false if not
+ */
+ static async hasTasksDueTodayForUserFromFarm(userId, taskIds, isDayLaterThanUTC = false) {
+ const today = new Date();
+ if (isDayLaterThanUTC) today.setDate(today.getDate() + 1);
+ const tasksDueToday = await TaskModel.query()
+ .select('*')
+ .whereIn('task_id', taskIds)
+ .whereNotDeleted()
+ .andWhere('task.assignee_user_id', userId)
+ .andWhere('task.due_date', today);
+
+ return tasksDueToday && tasksDueToday.length;
+ }
+
+ /**
+ * Returns all available tasks on the given date from the given taskIds
+ * Available in this case means unassigned, incomplete, not abandoned, and not deleted
+ * @param {Array} taskIds - taskIds to search
+ * @param {string} date - the date to search
+ * @param {Object} user - the user who requested this task assignment
+ * @static
+ * @async
+ * @returns {Object} - Task Object.
+ */
+ static async getAvailableTasksOnDate(taskIds, date, user) {
+ return await TaskModel.query()
+ .leftOuterJoin('task_type', 'task.task_type_id', 'task_type.task_type_id')
+ .context(user)
+ .select('*')
+ .where((builder) => {
+ builder.where('task.due_date', date);
+ builder.whereIn('task.task_id', taskIds);
+ builder.where('task.assignee_user_id', null);
+ builder.where('task.complete_date', null);
+ builder.where('task.abandon_date', null);
+ builder.where('task.deleted', false);
+ });
+ }
}
module.exports = TaskModel;
diff --git a/packages/api/src/models/taskTypeModel.js b/packages/api/src/models/taskTypeModel.js
index 4ea40fd8e8..62dfbd9986 100644
--- a/packages/api/src/models/taskTypeModel.js
+++ b/packages/api/src/models/taskTypeModel.js
@@ -45,6 +45,20 @@ class TaskName extends baseModel {
additionalProperties: false,
};
}
+
+ /**
+ * Gets the task translation key id
+ * @param {number} task_type_id - the IDs of the task.
+ * @static
+ * @async
+ * @returns {String} - Object {task_type_id, task_id}
+ */
+ static async getTaskTranslationKeyById(taskTypeId) {
+ return await TaskName.query()
+ .select('task_translation_key')
+ .where('task_type_id', taskTypeId)
+ .first();
+ }
}
module.exports = TaskName;
diff --git a/packages/api/src/models/userFarmModel.js b/packages/api/src/models/userFarmModel.js
index 7ca95a6e76..612e9caf1a 100644
--- a/packages/api/src/models/userFarmModel.js
+++ b/packages/api/src/models/userFarmModel.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (userFarmModel.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -10,7 +10,7 @@
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
+ * GNU General Public License for more details, see < .>
*/
const Model = require('objection').Model;
@@ -21,11 +21,11 @@ class userFarm extends Model {
}
static get idColumn() {
- return ['user_id', 'farm_id'];
+ return ['user_id', 'farm_id'];
}
static get hidden() {
- return ['created_at', 'created_by_user_id', 'updated_by_user_id', 'updated_at', 'deleted' ]
+ return ['created_at', 'created_by_user_id', 'updated_by_user_id', 'updated_at', 'deleted'];
}
static get hiddenFromOtherUsers() {
@@ -41,8 +41,8 @@ class userFarm extends Model {
let fieldsToBeHidden = [];
if (this.user_id === user_id) {
fieldsToBeHidden = hidden;
- }else{
- fieldsToBeHidden = [...hidden, ...hiddenFromOtherUsers]
+ } else {
+ fieldsToBeHidden = [...hidden, ...hiddenFromOtherUsers];
}
for (const property of fieldsToBeHidden) {
delete this[property];
@@ -97,8 +97,8 @@ class userFarm extends Model {
static get relationMappings() {
return {
- user:{
- modelClass:require('./userModel'),
+ user: {
+ modelClass: require('./userModel'),
relation: Model.HasOneRelation,
join: {
from: 'userFarm.user_id',
@@ -106,23 +106,103 @@ class userFarm extends Model {
},
},
farm: {
- modelClass:require('./farmModel'),
+ modelClass: require('./farmModel'),
relation: Model.HasOneRelation,
join: {
from: 'userFarm.farm_id',
to: 'farm.farm_id',
},
-
},
role: {
- modelClass:require('./roleModel'),
+ modelClass: require('./roleModel'),
relation: Model.HasOneRelation,
join: {
from: 'userFarm.role_id',
to: 'role.role_id',
},
},
+ };
+ }
+
+ /**
+ * Retrieves role for a specified user.
+ * @param {uuid} userId - The specified user.
+ * @static
+ * @async
+ * @returns {number} Number corresponding to role_id.
+ */
+ static async getUserRoleId(userId) {
+ return userFarm
+ .query()
+ .join('role', 'userFarm.role_id', 'role.role_id')
+ .select('role.role_id')
+ .where('userFarm.user_id', userId)
+ .first();
+ }
+
+ /**
+ * Checks if the user exists on a particular farm.
+ * @param user_id
+ * @param farm_id
+ * @return {Objection.QueryBuilder}
+ * @static
+ * @async
+ */
+ static async checkIfUserExistsOnFarm(user_id, farm_id) {
+ return userFarm.query().where({ user_id, farm_id }).first();
+ }
+
+ /**
+ * Gets a userFarm record by email.
+ * @param email
+ * @param farm_id
+ * @param trx - optional transaction
+ * @return {Objection.QueryBuilder}
+ */
+ static async getUserFarmByEmail(email, farm_id, trx) {
+ const transaction = trx ?? (await this.startTransaction());
+ const result = await userFarm
+ .query(transaction)
+ .join('users', 'userFarm.user_id', '=', 'users.user_id')
+ .join('farm', 'farm.farm_id', '=', 'userFarm.farm_id')
+ .join('role', 'userFarm.role_id', '=', 'role.role_id')
+ .where({ 'users.email': email, 'userFarm.farm_id': farm_id })
+ .first()
+ .select('*');
+ if (trx === null || trx === undefined) {
+ await transaction.commit();
}
+ return result;
+ }
+ /**
+ * Gets the userIds of FM/FO/EO from the farm with the given farmId
+ * @param {uuid} farmId - The specified user.
+ * @static
+ * @async
+ * @returns {Object} Object {userId} of FM/FO/EO
+ */
+ static async getFarmManagementByFarmId(farmId) {
+ return await userFarm
+ .query()
+ .select('user_id')
+ .whereIn('role_id', [1, 2, 5])
+ .where('userFarm.farm_id', farmId);
+ }
+
+ /**
+ * Gets the userIds of active users from a given farm
+ * @param {uuid} farmId farm id
+ * @static
+ * @async
+ * @returns {Array} Array [user_id]
+ */
+ static async getActiveUsersFromFarmId(farmId) {
+ return await userFarm
+ .query()
+ .select('userFarm.user_id')
+ .join('users', 'userFarm.user_id', 'users.user_id')
+ .where('userFarm.farm_id', farmId)
+ .andWhere('users.status_id', 1);
}
}
diff --git a/packages/api/src/models/userModel.js b/packages/api/src/models/userModel.js
index 7833866efb..4602203d34 100644
--- a/packages/api/src/models/userModel.js
+++ b/packages/api/src/models/userModel.js
@@ -57,8 +57,8 @@ class User extends Model {
let fieldsToBeHidden = [];
if (this.user_id === user_id) {
fieldsToBeHidden = hidden;
- }else{
- fieldsToBeHidden = [...hidden, ...hiddenFromOtherUsers]
+ } else {
+ fieldsToBeHidden = [...hidden, ...hiddenFromOtherUsers];
}
for (const property of fieldsToBeHidden) {
delete this[property];
@@ -80,12 +80,18 @@ class User extends Model {
first_name: { type: 'string', minLength: 1, maxLength: 255 },
last_name: { type: 'string', maxLength: 255 },
profile_picture: { type: 'string' },
- phone_number: { type: 'string' },
- user_address: { type: 'string' },
+ phone_number: { type: ['string', null] },
+ user_address: { type: ['string', null] },
email: { type: 'email' },
notification_setting: {
type: 'object',
- required: ['alert_weather', 'alert_worker_finish', 'alert_action_after_scouting', 'alert_before_planned_date', 'alert_pest'],
+ required: [
+ 'alert_weather',
+ 'alert_worker_finish',
+ 'alert_action_after_scouting',
+ 'alert_before_planned_date',
+ 'alert_pest',
+ ],
properties: {
alert_weather: { type: 'boolean' },
alert_worker_finish: { type: 'boolean' },
@@ -100,14 +106,36 @@ class User extends Model {
type: 'string',
enum: ['OTHER', 'PREFER_NOT_TO_SAY', 'MALE', 'FEMALE'],
},
- birth_year: { type: ['number', null], multipleOf: 1.0, minimum: 1900, maximum: new Date().getFullYear() },
- do_not_email: {type: 'boolean'},
+ birth_year: {
+ type: ['number', null],
+ multipleOf: 1.0,
+ minimum: 1900,
+ maximum: new Date().getFullYear(),
+ },
+ do_not_email: { type: 'boolean' },
created_at: { type: 'date-time' },
updated_at: { type: 'date-time' },
},
additionalProperties: false,
};
}
+
+ static async getNameFromUserId(userId) {
+ const user = await User.query().findById(userId).first();
+ return `${user?.first_name} ${user?.last_name}`;
+ }
+
+ /**
+ * Gets a user by their email.
+ * @param {string} email
+ * @return {Objection.QueryBuilder}
+ * @static
+ * @async
+ */
+ static async getUserByEmail(email) {
+ console.log('Getting user by email');
+ return User.query().where('email', email).first();
+ }
}
module.exports = User;
diff --git a/packages/api/src/routes/documentRoute.js b/packages/api/src/routes/documentRoute.js
index 339d8bf61b..bde212ddf5 100644
--- a/packages/api/src/routes/documentRoute.js
+++ b/packages/api/src/routes/documentRoute.js
@@ -23,28 +23,43 @@ const validateFileExtension = require('../middleware/validation/uploadDocument')
const documentController = require('../controllers/documentController');
const multerDiskUpload = require('../util/fileUpload');
-
-router.get('/farm/:farm_id',
+router.get(
+ '/farm/:farm_id',
hasFarmAccess({ params: 'farm_id' }),
- checkScope(['get:document']), documentController.getDocumentsByFarmId());
+ checkScope(['get:document']),
+ documentController.getDocumentsByFarmId(),
+);
-router.post('/upload/farm/:farm_id',
+router.post(
+ '/upload/farm/:farm_id',
hasFarmAccess({ params: 'farm_id' }),
- checkScope(['add:document']), multerDiskUpload, validateFileExtension, documentController.uploadDocument());
+ checkScope(['add:document']),
+ multerDiskUpload,
+ validateFileExtension,
+ documentController.uploadDocument(),
+);
-router.patch('/archive/:document_id',
+router.patch(
+ '/archive/:document_id',
hasFarmAccess({ params: 'document_id' }),
checkScope(['edit:document']),
- documentController.archiveDocument());
+ documentController.patchDocumentArchive(),
+);
-router.post('/farm/:farm_id',
+router.post(
+ '/farm/:farm_id',
hasFarmAccess({ params: 'farm_id' }),
- checkScope(['add:document']), validateFilesLength, documentController.createDocument());
+ checkScope(['add:document']),
+ validateFilesLength,
+ documentController.createDocument(),
+);
-router.put('/:document_id',
+router.put(
+ '/:document_id',
hasFarmAccess({ params: 'document_id' }),
checkScope(['edit:document']),
validateFilesLength,
- documentController.updateDocument());
+ documentController.updateDocument(),
+);
module.exports = router;
diff --git a/packages/api/src/routes/farmRoute.js b/packages/api/src/routes/farmRoute.js
index 13deef74f4..90a9b8a398 100644
--- a/packages/api/src/routes/farmRoute.js
+++ b/packages/api/src/routes/farmRoute.js
@@ -16,10 +16,11 @@
const express = require('express');
const router = express.Router();
const farmController = require('../controllers/farmController');
-const organicCertifierSurveyController = require('../controllers/organicCertifierSurveyController');
const authFarmId = require('../middleware/acl/authFarmId');
const hasFarmAccess = require('../middleware/acl/hasFarmAccess');
const checkScope = require('../middleware/acl/checkScope');
+const checkSchedulerJwt = require('../middleware/acl/checkSchedulerJwt');
+const hasTimeNotificationsAccess = require('../middleware/acl/hasTimeNotificationsAccess');
router.get('/:farm_id', authFarmId, farmController.getFarmByID());
@@ -43,7 +44,7 @@ router.patch(
router.patch(
'/owner_operated/:farm_id',
hasFarmAccess({ params: 'farm_id' }),
- checkScope(['edit:farms']),
+ checkScope(['edit:farms'], { checkConsent: false }),
farmController.patchOwnerOperated(),
);
@@ -62,4 +63,11 @@ router.delete(
farmController.deleteFarm(),
);
+router.get(
+ '/utc_offset_by_range/:min/:max',
+ checkSchedulerJwt,
+ hasTimeNotificationsAccess,
+ farmController.getFarmsByOffsetRange,
+);
+
module.exports = router;
diff --git a/packages/api/src/routes/notificationUserRoute.js b/packages/api/src/routes/notificationUserRoute.js
new file mode 100644
index 0000000000..04714fbc1c
--- /dev/null
+++ b/packages/api/src/routes/notificationUserRoute.js
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const NotificationUserController = require('../controllers/notificationUserController');
+const checkUserFarmStatus = require('../middleware/acl/checkUserFarmStatus');
+const express = require('express');
+const router = express.Router();
+
+router.get('/subscribe', NotificationUserController.subscribeToAlerts);
+router.get('/', checkUserFarmStatus(), NotificationUserController.getNotifications);
+router.patch('/', checkUserFarmStatus(), NotificationUserController.patchNotifications);
+router.patch('/clear_alerts', checkUserFarmStatus(), NotificationUserController.clearAlerts);
+
+module.exports = router;
diff --git a/packages/api/src/routes/taskRoute.js b/packages/api/src/routes/taskRoute.js
index 43a01a06f7..47f59603c2 100644
--- a/packages/api/src/routes/taskRoute.js
+++ b/packages/api/src/routes/taskRoute.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (fertilizerRoute.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,96 +18,235 @@ const router = express.Router();
const hasFarmAccess = require('../middleware/acl/hasFarmAccess');
const checkScope = require('../middleware/acl/checkScope');
const { modelMapping, isWorkerToSelfOrAdmin } = require('../middleware/validation/task');
+const {
+ validateAssigneeId,
+ checkTaskStatusForAssignment,
+} = require('../middleware/validation/assignTask');
const taskController = require('../controllers/taskController');
const { createOrPatchProduct } = require('../middleware/validation/product');
-router.patch('/assign/:task_id', hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.assignTask());
-
-router.patch('/assign_all_tasks_on_date/:task_id', hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.assignAllTasksOnDate());
-
-router.patch('/abandon/:task_id', hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.abandonTask());
-
-router.get('/:farm_id', hasFarmAccess({ params: 'farm_id' }), taskController.getTasksByFarmId());
+router.patch(
+ '/assign/:task_id',
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ validateAssigneeId,
+ checkTaskStatusForAssignment,
+ taskController.assignTask,
+);
+
+router.patch(
+ '/assign_all_tasks_on_date/:task_id',
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ validateAssigneeId,
+ checkTaskStatusForAssignment,
+ taskController.assignAllTasksOnDate,
+);
+
+router.patch(
+ '/patch_due_date/:task_id',
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.patchTaskDate,
+);
+
+router.patch(
+ '/abandon/:task_id',
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.abandonTask,
+);
+
+router.get('/:farm_id', hasFarmAccess({ params: 'farm_id' }), taskController.getTasksByFarmId);
/**
* endpoint name should follow
* /task/task_type.task_translation_key.toLowerCase()
*/
-router.post('/harvest_tasks', hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+router.post(
+ '/harvest_tasks',
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
isWorkerToSelfOrAdmin({ hasManyTasks: true }),
- taskController.createHarvestTasks());
-
-router.post('/soil_amendment_task', modelMapping['soil_amendment_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(),
- createOrPatchProduct('soil_amendment_task'), taskController.createTask('soil_amendment_task'));
-
-router.post('/cleaning_task', modelMapping['cleaning_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(),
- createOrPatchProduct('cleaning_task'), taskController.createTask('cleaning_task'));
-
-router.post('/pest_control_task', modelMapping['pest_control_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(),
- createOrPatchProduct('pest_control_task'), taskController.createTask('pest_control_task'));
-
-router.post('/irrigation_task', modelMapping['irrigation_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('irrigation_task'));
-
-router.post('/scouting_task', modelMapping['scouting_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('scouting_task'));
-
-router.post('/soil_task', modelMapping['soil_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('soil_task'));
-
-router.post('/field_work_task', modelMapping['field_work_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('field_work_task'));
-
-router.post('/harvest_task', modelMapping['harvest_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('harvest_task'));
-
-router.post('/transplant_task', modelMapping['transplant_task'],
- hasFarmAccess({ mix: 'transplant_task' }), isWorkerToSelfOrAdmin(), taskController.createTransplantTask());
-
-router.post('/custom_task', modelMapping['custom_task'],
- hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }), isWorkerToSelfOrAdmin(), taskController.createTask('custom_task'));
-
-router.patch('/complete/soil_amendment_task/:task_id', modelMapping['soil_amendment_task'],
- hasFarmAccess({ params: 'task_id' }), checkScope(['edit:task']),
- createOrPatchProduct('soil_amendment_task'), taskController.completeTask('soil_amendment_task'));
-
-router.patch('/complete/cleaning_task/:task_id', modelMapping['cleaning_task'],
- hasFarmAccess({ params: 'task_id' }), checkScope(['edit:task']),
- createOrPatchProduct('cleaning_task'), taskController.completeTask('cleaning_task'));
-
-router.patch('/complete/pest_control_task/:task_id', modelMapping['pest_control_task'],
- hasFarmAccess({ params: 'task_id' }), checkScope(['edit:task']),
- createOrPatchProduct('pest_control_task'), taskController.completeTask('pest_control_task'));
-
-router.patch('/complete/irrigation_task/:task_id', modelMapping['irrigation_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('irrigation_task'));
-
-router.patch('/complete/scouting_task/:task_id', modelMapping['scouting_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('scouting_task'));
-
-router.patch('/complete/soil_task/:task_id', modelMapping['soil_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('soil_task'));
-
-router.patch('/complete/field_work_task/:task_id', modelMapping['field_work_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('field_work_task'));
-
-router.patch('/complete/harvest_task/:task_id', modelMapping['harvest_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeHarvestTask());
-
-router.patch('/complete/plant_task/:task_id', modelMapping['plant_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('plant_task'));
-
-router.patch('/complete/transplant_task/:task_id', modelMapping['plant_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('transplant_task'));
-
-router.patch('/complete/custom_task/:task_id', modelMapping['custom_task'], hasFarmAccess({ params: 'task_id' }),
- checkScope(['edit:task']), taskController.completeTask('custom_task'));
-
-router.get('/harvest_uses/farm/:farm_id', hasFarmAccess({ params: 'farm_id' }), taskController.getHarvestUsesByFarmId());
+ taskController.createHarvestTasks,
+);
+
+router.post(
+ '/soil_amendment_task',
+ modelMapping['soil_amendment_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ createOrPatchProduct('soil_amendment_task'),
+ taskController.createTask('soil_amendment_task'),
+);
+
+router.post(
+ '/cleaning_task',
+ modelMapping['cleaning_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ createOrPatchProduct('cleaning_task'),
+ taskController.createTask('cleaning_task'),
+);
+
+router.post(
+ '/pest_control_task',
+ modelMapping['pest_control_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ createOrPatchProduct('pest_control_task'),
+ taskController.createTask('pest_control_task'),
+);
+
+router.post(
+ '/irrigation_task',
+ modelMapping['irrigation_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('irrigation_task'),
+);
+
+router.post(
+ '/scouting_task',
+ modelMapping['scouting_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('scouting_task'),
+);
+
+router.post(
+ '/soil_task',
+ modelMapping['soil_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('soil_task'),
+);
+
+router.post(
+ '/field_work_task',
+ modelMapping['field_work_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('field_work_task'),
+);
+
+router.post(
+ '/harvest_task',
+ modelMapping['harvest_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('harvest_task'),
+);
+
+router.post(
+ '/transplant_task',
+ modelMapping['transplant_task'],
+ hasFarmAccess({ mix: 'transplant_task' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTransplantTask,
+);
+
+router.post(
+ '/custom_task',
+ modelMapping['custom_task'],
+ hasFarmAccess({ mixed: 'taskManagementPlanAndLocation' }),
+ isWorkerToSelfOrAdmin(),
+ taskController.createTask('custom_task'),
+);
+
+router.patch(
+ '/complete/soil_amendment_task/:task_id',
+ modelMapping['soil_amendment_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ createOrPatchProduct('soil_amendment_task'),
+ taskController.completeTask('soil_amendment_task'),
+);
+
+router.patch(
+ '/complete/cleaning_task/:task_id',
+ modelMapping['cleaning_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ createOrPatchProduct('cleaning_task'),
+ taskController.completeTask('cleaning_task'),
+);
+
+router.patch(
+ '/complete/pest_control_task/:task_id',
+ modelMapping['pest_control_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ createOrPatchProduct('pest_control_task'),
+ taskController.completeTask('pest_control_task'),
+);
+
+router.patch(
+ '/complete/irrigation_task/:task_id',
+ modelMapping['irrigation_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('irrigation_task'),
+);
+
+router.patch(
+ '/complete/scouting_task/:task_id',
+ modelMapping['scouting_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('scouting_task'),
+);
+
+router.patch(
+ '/complete/soil_task/:task_id',
+ modelMapping['soil_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('soil_task'),
+);
+
+router.patch(
+ '/complete/field_work_task/:task_id',
+ modelMapping['field_work_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('field_work_task'),
+);
+
+router.patch(
+ '/complete/harvest_task/:task_id',
+ modelMapping['harvest_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeHarvestTask,
+);
+
+router.patch(
+ '/complete/plant_task/:task_id',
+ modelMapping['plant_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('plant_task'),
+);
+
+router.patch(
+ '/complete/transplant_task/:task_id',
+ modelMapping['plant_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('transplant_task'),
+);
+
+router.patch(
+ '/complete/custom_task/:task_id',
+ modelMapping['custom_task'],
+ hasFarmAccess({ params: 'task_id' }),
+ checkScope(['edit:task']),
+ taskController.completeTask('custom_task'),
+);
+
+router.get(
+ '/harvest_uses/farm/:farm_id',
+ hasFarmAccess({ params: 'farm_id' }),
+ taskController.getHarvestUsesByFarmId,
+);
module.exports = router;
diff --git a/packages/api/src/routes/timeNotificationRoute.js b/packages/api/src/routes/timeNotificationRoute.js
new file mode 100644
index 0000000000..eee0cb8d5c
--- /dev/null
+++ b/packages/api/src/routes/timeNotificationRoute.js
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const timeNotificationController = require('../controllers/timeNotificationController');
+const express = require('express');
+const checkSchedulerJwt = require('../middleware/acl/checkSchedulerJwt');
+const hasTimeNotificationsAccess = require('../middleware/acl/hasTimeNotificationsAccess');
+const router = express.Router();
+
+router.post(
+ '/weekly_unassigned_tasks/:farm_id',
+ checkSchedulerJwt,
+ hasTimeNotificationsAccess,
+ timeNotificationController.postWeeklyUnassignedTasks,
+);
+
+router.post(
+ '/daily_due_today_tasks/:farm_id',
+ checkSchedulerJwt,
+ hasTimeNotificationsAccess,
+ timeNotificationController.postDailyDueTodayTasks,
+);
+
+module.exports = router;
diff --git a/packages/api/src/routes/userRoute.js b/packages/api/src/routes/userRoute.js
index fa6b31400d..7c3a809165 100644
--- a/packages/api/src/routes/userRoute.js
+++ b/packages/api/src/routes/userRoute.js
@@ -1,42 +1,64 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (userRoute.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-const express = require('express');
-const router = express.Router();
-const userController = require('../controllers/userController');
-const checkScope = require('../middleware/acl/checkScope');
-const isSelf = require('../middleware/acl/isSelf');
-const hasFarmAccess = require('../middleware/acl/hasFarmAccess');
-const checkInviteJwt = require('../middleware/acl/checkInviteJwt');
-const checkInvitationTokenContent = require('../middleware/acl/checkInviteTokenContent');
-const checkInvitationAndGoogleJwtContent = require('../middleware/acl/checkInviteAndGoogleJwtContent');
-const checkPasswordCreated = require('../middleware/acl/checkPasswordCreated');
-const checkGoogleJwt = require('../middleware/acl/checkGoogleJwt');
-
-router.post('/', userController.addUser());
-
-router.post('/invite', hasFarmAccess({ body: 'farm_id' }), checkScope(['add:users']), userController.addInvitedUser());
-
-router.post('/pseudo', hasFarmAccess({ body: 'farm_id' }), checkScope(['add:users']), userController.addPseudoUser());
-
-router.post('/accept_invitation', checkInviteJwt, checkInvitationTokenContent, checkPasswordCreated, userController.acceptInvitationAndPostPassword());
-
-router.put('/accept_invitation', checkGoogleJwt, checkInvitationAndGoogleJwtContent, checkPasswordCreated, userController.acceptInvitationWithGoogleAccount());
-
-router.get('/:user_id', isSelf, userController.getUserByID());
-
-router.put('/:user_id', isSelf, userController.updateUser());
-
-module.exports = router;
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const express = require('express');
+const router = express.Router();
+const userController = require('../controllers/userController');
+const checkScope = require('../middleware/acl/checkScope');
+const isSelf = require('../middleware/acl/isSelf');
+const hasFarmAccess = require('../middleware/acl/hasFarmAccess');
+const checkInviteJwt = require('../middleware/acl/checkInviteJwt');
+const checkInvitationTokenContent = require('../middleware/acl/checkInviteTokenContent');
+const checkInvitationAndGoogleJwtContent = require('../middleware/acl/checkInviteAndGoogleJwtContent');
+const checkPasswordCreated = require('../middleware/acl/checkPasswordCreated');
+const checkGoogleJwt = require('../middleware/acl/checkGoogleJwt');
+
+router.post('/', userController.addUser);
+
+router.post(
+ '/invite',
+ hasFarmAccess({ body: 'farm_id' }),
+ checkScope(['add:users']),
+ userController.addInvitedUser,
+);
+
+router.post(
+ '/pseudo',
+ hasFarmAccess({ body: 'farm_id' }),
+ checkScope(['add:users']),
+ userController.addPseudoUser,
+);
+
+router.post(
+ '/accept_invitation',
+ checkInviteJwt,
+ checkInvitationTokenContent,
+ checkPasswordCreated,
+ userController.acceptInvitationAndPostPassword,
+);
+
+router.put(
+ '/accept_invitation',
+ checkGoogleJwt,
+ checkInvitationAndGoogleJwtContent,
+ checkPasswordCreated,
+ userController.acceptInvitationWithGoogleAccount,
+);
+
+router.get('/:user_id', isSelf, userController.getUserByID);
+
+router.put('/:user_id', isSelf, userController.updateUser);
+
+module.exports = router;
diff --git a/packages/api/src/server.js b/packages/api/src/server.js
index b64107282b..9cbebf4f7e 100644
--- a/packages/api/src/server.js
+++ b/packages/api/src/server.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (server.js) is part of LiteFarm.
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,8 +59,8 @@ const organicCertifierSurveyRoutes = require('./routes/organicCertifierSurveyRou
const passwordResetRoutes = require('./routes/passwordResetRoute.js');
const showedSpotlightRoutes = require('./routes/showedSpotlightRoute.js');
-const waterBalanceScheduler = require('./jobs/waterBalance/waterBalance');
-const nitrogenBalanceScheduler = require('./jobs/nitrogenBalance/nitrogenBalance');
+// const waterBalanceScheduler = require('./jobs/waterBalance/waterBalance');
+// const nitrogenBalanceScheduler = require('./jobs/nitrogenBalance/nitrogenBalance');
// const farmDataScheduler = require('./jobs/sendFarmData/sendFarmData');
const userLogRoute = require('./routes/userLogRoute');
const supportTicketRoute = require('./routes/supportTicketRoute');
@@ -69,6 +69,8 @@ const farmTokenRoute = require('./routes/farmTokenRoute');
const documentRoute = require('./routes/documentRoute');
const taskRoute = require('./routes/taskRoute');
const productRoute = require('./routes/productRoute');
+const notificationUserRoute = require('./routes/notificationUserRoute');
+const timeNotificationRoute = require('./routes/timeNotificationRoute');
// register API
const router = promiseRouter();
@@ -77,18 +79,71 @@ app.get('/', (req, res) => {
res.sendStatus(200);
});
-app.use(bodyParser.json())
+/**
+ * Configures Express to send custom JSON for specified object keys (database column names).
+ * Postgres `date` type fields, which have no time portion, are retrieved as JS Date objects with midnight UTC time.
+ * `JSON.stringify` transforms the Date object to '2020-01-15T00:00:00.000Z' which the API transmits to the client.
+ * A Pacific time client using local form, '2020-01-14T16:00:00.000-08:00', and ignoring time, ends up with wrong date.
+ * To address this, we make stringify produce '2020-01-15T00:00:00.000', the date with midnight of unspecified timezone.
+ * Clients treat this as midnight local time, preserving the correct date value.
+ * Note that the code will also handle string values with format YYYY-MM-DD or YYYY-MM-DDT00:00:00.000 --
+ * values that do not come from the database, but occur as "literals", if only in test.
+ * Strings that are not dates, have non-midnight times, or timezones other than Z are not changed, with a log message--
+ * these unexpected values will likely lead to errors.
+ */
+app.set('json replacer', (key, value) => {
+ // A list of database column names with Postgres type `date`.
+ // (Except as bindings for `date` type database columns, avoid these keys in objects sent via JSON/HTTPS.)
+ const pgDateTypeFields = [
+ 'abandon_date',
+ 'complete_date',
+ 'due_date',
+ 'effective_date',
+ 'germination_date',
+ 'harvest_date',
+ 'plant_date',
+ 'seed_date',
+ 'shift_date',
+ 'start_date',
+ 'termination_date',
+ 'transition_date',
+ 'transplant_date',
+ 'valid_until',
+ ];
+
+ if (value && pgDateTypeFields.includes(key)) {
+ // Valid values *must* start YYYY-MM-DD. Time portion of midnight *may* be present. Time zone Z *may* be present.
+ const validDateTypeValues = /^(\d{4}-[0-1]\d-[0-3]\d)(T00:00:00\.000)?Z?$/;
+
+ const matches = value.match(validDateTypeValues);
+ if (matches) return `${matches[1]}T00:00:00.000`; // YYYY-MM-DD with midnight time, no timezone indicator.
+
+ console.log(
+ `JSON payload problem: key '${key}' is reserved for db date fields; unexpected value ${value}.`,
+ );
+ }
+ return value;
+});
+
+app
+ .use(bodyParser.json())
.use(bodyParser.urlencoded({ extended: true }))
// prevent CORS errors
.use(cors())
.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
- res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
+ res.header(
+ 'Access-Control-Allow-Headers',
+ 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
+ );
if (req.method === 'OPTIONS') {
res.header('Access-Control-Allow-Methods', 'PUT, POST, PATCH, DELETE, GET');
return res.status(200).json({});
- } else if ((req.method === 'DELETE' || req.method === 'GET') && Object.keys(req.body).length > 0) {
+ } else if (
+ (req.method === 'DELETE' || req.method === 'GET') &&
+ Object.keys(req.body).length > 0
+ ) {
// TODO: Find new bugs caused by this change
return res.sendStatus(400);
}
@@ -138,7 +193,8 @@ app.use(bodyParser.json())
.use('/document', documentRoute)
.use('/task', taskRoute)
.use('/product', productRoute)
-
+ .use('/notification_user', notificationUserRoute)
+ .use('/time_notification', timeNotificationRoute)
// handle errors
.use((req, res, next) => {
const error = new Error('Not found');
@@ -156,7 +212,11 @@ app.use(bodyParser.json())
});
const port = process.env.PORT || 5000;
-if (environment === 'development' || environment === 'production' || environment === 'integration') {
+if (
+ environment === 'development' ||
+ environment === 'production' ||
+ environment === 'integration'
+) {
app.listen(port, () => {
// eslint-disable-next-line no-console
console.log('LiteFarm Backend listening on port ' + port + '!');
diff --git a/packages/api/src/templates/emails/help_request_email/html.pug b/packages/api/src/templates/emails/help_request_email/html.pug
index 3cd1c08fb0..d392ab2bc3 100644
--- a/packages/api/src/templates/emails/help_request_email/html.pug
+++ b/packages/api/src/templates/emails/help_request_email/html.pug
@@ -7,7 +7,7 @@ block content
.support-header
span=`${t('HELP_REQUEST.TYPE_HEADER')}:`
.support-content
- | #{support_type}
+ p=`${t('HELP_REQUEST.' + support_type.toUpperCase().replace(/\s/g, '_'))}`
.support-container
.support-header
span=`${t('HELP_REQUEST.MESSAGE_HEADER')}:`
diff --git a/packages/api/src/templates/locales/en.json b/packages/api/src/templates/locales/en.json
index 8134df49a4..d21cc652d7 100644
--- a/packages/api/src/templates/locales/en.json
+++ b/packages/api/src/templates/locales/en.json
@@ -13,6 +13,10 @@
"RESPONSE": "Thanks for reaching out. Someone on our support team will be in touch within 48 hours. A summary of your request is shown below.",
"TYPE_HEADER": "Type of support",
"MESSAGE_HEADER": "Message",
+ "REQUEST_INFORMATION": "Request Information",
+ "REPORT_A_BUG": "Report a bug",
+ "REQUEST_A_FEATURE": "Request a feature",
+ "OTHER": "Other",
"CONTACT_METHOD_HEADER": "Preferred contact method",
"SUBJECT": "Your LiteFarm request for help"
},
diff --git a/packages/api/src/templates/locales/es.json b/packages/api/src/templates/locales/es.json
index 984db81fcd..4e50138511 100644
--- a/packages/api/src/templates/locales/es.json
+++ b/packages/api/src/templates/locales/es.json
@@ -4,7 +4,11 @@
"TYPE_HEADER": "Tipo de soporte",
"MESSAGE_HEADER": "Mensaje",
"CONTACT_METHOD_HEADER": "Metodo de contacto preferido",
- "SUBJECT": "Su solicitud de ayuda de LiteFarm"
+ "SUBJECT": "Su solicitud de ayuda de LiteFarm",
+ "REQUEST_INFORMATION": "Solicitar Información",
+ "REPORT_A_BUG": "Reportar un error",
+ "REQUEST_A_FEATURE": "Solicitar una característica",
+ "OTHER": "Otro"
},
"TEMPLATE": {
"DEAR": "Querido",
@@ -33,7 +37,7 @@
},
"PASSWORD_RESET_REQUEST": {
"DID_YOU_FORGET": "Olvidó su clave en Litefarm? No se preocupe! Haga clic en el botón de Cambiar y su acceso será restaurado pronto.",
- "RESET": "Cambiar Clave",
+ "RESET": "Cambiar contraseña",
"IGNORE": "Si no solicitó que le enviaramos este correo, por favor ignórelo. No habrá cambios en su cuenta.",
"SUBJECT": "Solicitud de recuperacion de clave"
},
@@ -97,6 +101,6 @@
"SUBJECT": "sus documentos de certificacion de Litefarm",
"HI": "Hola",
"GET_YOUR_EXPORT": "Obtener documentos",
- "LANGUAGE_DELAY" : "Los cultivos e insumos en el reporte estan en Ingles, pero muy pronto estara disponible en Español. Pedimos disculpas por los inconvenientes."
+ "LANGUAGE_DELAY": "Los cultivos e insumos en el reporte estan en Ingles, pero muy pronto estara disponible en Español. Pedimos disculpas por los inconvenientes."
}
}
\ No newline at end of file
diff --git a/packages/api/src/templates/locales/fr.json b/packages/api/src/templates/locales/fr.json
index 3404a6854d..4c102692c9 100644
--- a/packages/api/src/templates/locales/fr.json
+++ b/packages/api/src/templates/locales/fr.json
@@ -1,101 +1,105 @@
{
"TEMPLATE": {
- "DEAR": "Dear",
- "CHEERS": "Cheers",
- "LITEFARM_TEAM": "The LiteFarm team",
- "NO_RESPONSE": "Please do not reply to this email.",
- "GET_IN_TOUCH": "To get in touch with us, click",
- "HELP": "help",
- "OR": "or",
- "CONTACT": "contact us"
+ "DEAR": "Cher / chère",
+ "CHEERS": "Bien à vous",
+ "LITEFARM_TEAM": "L'équipe LiteFarm",
+ "NO_RESPONSE": "S'il vous plait ne répondez pas à cet email.",
+ "GET_IN_TOUCH": "Pour nous contacter, cliquez",
+ "HELP": "aide-moi",
+ "OR": "ou",
+ "CONTACT": "contactez nous"
},
"HELP_REQUEST": {
- "RESPONSE": "Thanks for reaching out. Someone on our support team will be in touch within 48 hours. A summary of your request is shown below.",
- "TYPE_HEADER": "Type of support",
+ "RESPONSE": "Merci de nous avoir contactés. Un membre de notre équipe d'assistance vous contactera dans les 48 heures. Un récapitulatif de votre demande est présenté ci-dessous.",
+ "TYPE_HEADER": "Type d'aide",
"MESSAGE_HEADER": "Message",
- "CONTACT_METHOD_HEADER": "Preferred contact method",
- "SUBJECT": "Your LiteFarm request for help"
+ "CONTACT_METHOD_HEADER": "Méthode de contact préférée",
+ "SUBJECT": "Votre demande d'aide LiteFarm",
+ "REQUEST_INFORMATION": "Informations requises",
+ "REPORT_A_BUG": "Signaler un bogue",
+ "REQUEST_A_FEATURE": "Demander une fonctionnalité",
+ "OTHER": "Autre"
},
"INVITE": {
- "GREAT_FOLK": "The great folks at",
- "INVITED_YOU": "have invited you to join their team on LiteFarm! LiteFarm is an open-source software tool for helping farmers manage their farms. You can read more about LiteFarm at",
- "YOU_CAN_ACCEPT": "You can accept this invitation (on any device) using the button below",
- "SUBJECT0": "You’ve been invited to join",
- "SUBJECT1": "on LiteFarm!"
+ "GREAT_FOLK": "Les gens formidables de",
+ "INVITED_YOU": "vous ont invité à rejoindre leur équipe sur LiteFarm ! LiteFarm est un outil logiciel open source pour aider les agriculteurs à gérer leurs fermes. Vous pouvez en savoir plus sur LiteFarm à",
+ "YOU_CAN_ACCEPT": "Vous pouvez accepter cette invitation (sur n'importe quel appareil) en utilisant le bouton ci-dessous",
+ "SUBJECT0": "Vous avez été invité à rejoindre",
+ "SUBJECT1": "sur LiteFarm!"
},
"PASSWORD_RESET_REQUEST": {
- "DID_YOU_FORGET": "Did you forget your LiteFarm password? Not a problem! Click the \"Reset\" button below and your access will soon be restored.",
- "RESET": "Reset Password",
- "IGNORE": "If you didn't ask us to send you this email, you can ignore it. No changes have been made to your account.",
- "SUBJECT": "Password Reset Request"
+ "DID_YOU_FORGET": "Avez-vous oublié votre mot de passe LiteFarm ? Pas de problème! Cliquez sur le bouton \"Réinitialiser\" ci-dessous et votre accès sera bientôt restauré.",
+ "RESET": "Réinitialiser",
+ "IGNORE": "Si vous ne nous avez pas demandé de vous envoyer ce message, vous pouvez l'ignorer. Aucune modification n'a été apportée à votre compte.",
+ "SUBJECT": "Demande de réinitialisation du mot de passe"
},
"PASSWORD_RESET_CONFIRMATION": {
- "UPDATED": "We’ve updated your LiteFarm password. Click ‘Log In’ below to access your account.",
- "SUBJECT": "Your LiteFarm password has been changed"
+ "UPDATED": "Nous avons mis à jour votre mot de passe LiteFarm. Cliquez sur 'Connexion' ci-dessous pour accéder à votre compte.",
+ "SUBJECT": "Votre mot de passe LiteFarm a été modifié"
},
"RESTORE_ACCESS": {
- "ADMIN": "It looks like one of the administrators at",
- "RESTORED": "has renewed your access to their farm on LiteFarm. Welcome back!",
- "CLICK_BELOW": "You can log back in by clicking below",
- "SUBJECT0": "Your access to",
- "SUBJECT1": "has been restored!"
+ "ADMIN": "Il semble que l'un des administrateurs de",
+ "RESTORED": "a renouvelé votre accès à leur ferme sur LiteFarm. Content de te revoir!",
+ "CLICK_BELOW": "Vous pouvez vous reconnecter en cliquant ci-dessousw",
+ "SUBJECT0": "Votre accès à",
+ "SUBJECT1": "a été restauré !"
},
"REVOKE_ACCESS": {
- "ADMIN": "It looks like one of the administrators at",
- "REVOKE": "has revoked your access to their farm on LiteFarm. If this comes as a surprise, you should reach out to your contact there to fix the problem.",
- "SUBJECT0": "You've lost access to",
- "SUBJECT1": "on LiteFarm!"
+ "ADMIN": "Il semble que l'un des administrateurs de",
+ "REVOKE": "a révoqué votre accès à sa ferme sur LiteFarm. Si cela vous surprend, vous devez contacter votre contact là-bas pour résoudre le problème.",
+ "SUBJECT0": "Vous avez perdu l'accès à",
+ "SUBJECT1": "sur LiteFarm!"
},
"ACCEPT_INVITE_CONFIRMATION": {
- "CONGRATS": "Congrats on becoming the newest",
- "AT": "at",
- "CLICK_BELOW": "You can log-in (on any device) using the button below",
- "SUBJECT": "You've successfully joined"
+ "CONGRATS": "Félicitations d'être devenu le plus récent",
+ "AT": "à",
+ "CLICK_BELOW": "Vous pouvez vous connecter (sur n'importe quel appareil) en utilisant le bouton ci-dessous",
+ "SUBJECT": "Vous avez rejoint avec succès"
},
"CREATE_ACCOUNT_CONFIRMATION": {
- "WELCOME": "Welcome to LiteFarm! LiteFarm is an open-source software tool for helping farmers manage their farms. You can read more about LiteFarm at",
- "CLICK_BELOW": "You can also log-in (on any device) using the button below",
- "SUBJECT": "Welcome to LiteFarm!"
+ "WELCOME": "Bienvenue à Lite Farm ! LiteFarm est un outil logiciel open source pour aider les agriculteurs à gérer leurs fermes. Vous pouvez en savoir plus sur LiteFarm à",
+ "CLICK_BELOW": "Vous pouvez également vous connecter (sur n'importe quel appareil) en utilisant le bouton ci-dessous",
+ "SUBJECT": "Bienvenue à LiteFarm !"
},
"WITHHOLD_CONSENT": {
- "RECENT": "Recently, while joining",
- "WITHHOLD": "on the LiteFarm application, you decided to withhold your consent regarding the LiteFarm privacy policy. This is absolutely your right, however, it means you won't be able to access the application. We're very sorry about this.",
- "DEACTIVATE": "We've de-activated your association to",
- "HOWEVER": "However, we still have the basic information you shared with us while setting up your user account. If you're associated with other farms, we also have any information you entered while working with those farms as well.",
- "RIGHT": "You have the following rights regarding your data",
- "COPY": "To know what data we have about you and request a copy of it",
- "UPDATE": "To update or correct any data we have about you",
- "STOP": "Request that we stop collecting your data (you've just done this)",
- "TRANSFER": "Request a transfer of your data",
- "DELETE": "Request that we delete your data",
- "TO_REQUEST": "To request any of these actions, send an email to",
- "SUPPORT": "with your request and we'll take care of you.",
- "OTHERWISE": "Otherwise, if you change your mind, you can log-in (on any device) at any time and accept our privacy policy using the button below",
- "RESTORE": "If you do so, you'll once again be able to access the LiteFarm system.",
- "SUBJECT": "You didnt agree with the LiteFarm privacy policy – here are your options"
+ "RECENT": "Récemment, en rejoignant",
+ "WITHHOLD": "sur l'application LiteFarm, vous avez décidé de refuser votre consentement concernant la politique de confidentialité de LiteFarm. C'est tout à fait votre droit, cependant, cela signifie que vous ne pourrez pas accéder à l'application. Nous en sommes vraiment désolés.",
+ "DEACTIVATE": "Nous avons désactivé votre association pour",
+ "HOWEVER": "Cependant, nous avons toujours les informations de base que vous avez partagées avec nous lors de la configuration de votre compte utilisateur. Si vous êtes associé à d'autres fermes, nous avons également toutes les informations que vous avez saisies lorsque vous travaillez avec ces fermes.",
+ "RIGHT": "Vous disposez des droits suivants concernant vos données",
+ "COPY": "Le droit de savoir quelles données nous avons sur vous et d'en demander une copie",
+ "UPDATE": "Le droit de mettre à jour ou de corriger les données que nous possédons à votre sujet",
+ "STOP": "le droit de demander que nous arrêtions de collecter vos données (vous venez de le faire)",
+ "TRANSFER": "Le droit de demander un transfert de vos données",
+ "DELETE": "Le droit de demander que nous supprimions vos données",
+ "TO_REQUEST": "le droit de demander l'une de ces actions, envoyer un courriel à",
+ "SUPPORT": "avec votre demande et nous nous occuperons de vous.",
+ "OTHERWISE": "Sinon, si vous changez d'avis, vous pouvez vous connecter (sur n'importe quel appareil) à tout moment et accepter notre politique de confidentialité en utilisant le bouton ci-dessous.",
+ "RESTORE": "Si vous le faites, vous pourrez à nouveau accéder au système LiteFarm.",
+ "SUBJECT": "Vous n'êtes pas d'accord avec la politique de confidentialité de LiteFarm - voici vos options"
},
"EXPORT_MAP": {
- "EXPORT": "Here’s the farm map export for",
- "REQUESTED": "that you requested on LiteFarm.",
- "GREETING": "Have a great day!",
- "SUBJECT0": "Here’s your farm map for",
- "SUBJECT1": "on LiteFarm"
+ "EXPORT": "Voici l'exportation de la carte de la ferme pour",
+ "REQUESTED": "que vous avez demandé sur LiteFarm.",
+ "GREETING": "Bonne journée!",
+ "SUBJECT0": "Voici votre carte de ferme pour",
+ "SUBJECT1": "sur LiteFarm"
},
"COMMON": {
- "JOIN": "Join",
- "LOG_IN": "Log In",
- "OWNER": "MISSING",
- "EXTENSION_OFFICER": "MISSING",
- "WORKER": "MISSING",
- "MANAGER": "MISSING"
+ "JOIN": "Rejoindre",
+ "LOG_IN": "Connexion",
+ "OWNER": "Propriétaire",
+ "EXTENSION_OFFICER": "Agent de vulgarisation",
+ "WORKER": "Ouvrier",
+ "MANAGER": "Gestionnaire"
},
"EXPORT": {
- "HI": "EXPORT.HI",
- "SEASON": "EXPORT.SEASON",
- "CERTIFICATION": "EXPORT.CERTIFICATION",
- "GET_YOUR_EXPORT": "EXPORT.GET_YOUR_EXPORT",
- "SUBJECT": "EXPORT.SUBJECT",
- "PRIVACY": "EXPORT.PRIVACY",
- "LANGUAGE_DELAY": "EXPORT.LANGUAGE_DELAY"
+ "HI": "Bonjour",
+ "SEASON": "Nous espérons que vous avez eu une saison fantastique à",
+ "CERTIFICATION": " Vous pouvez cliquer sur le lien ci-dessous pour télécharger un fichier zip de vos documents de certification et tous les documents à l'appui (photos d'emballages de semences, reçus d'entrée, etc.) pour votre période de déclaration.",
+ "GET_YOUR_EXPORT": "Obtenir vos documents",
+ "SUBJECT": "Export de documents de certification de LiteFarm",
+ "PRIVACY": "Chez LiteFarm, nous prenons votre vie privée au sérieux, donc vous devrez être connecté avant que vous puissiez accéder votre export. Désolée pour le dérangement. Bonne chance avec votre soumission et merci d'utiliser LiteFarm!",
+ "LANGUAGE_DELAY": "Les cultures et les intrants dans les documents sont en anglais, mais ils seront disponible en français très prochainement. Nous sommes sincèrement désolés pour tout inconvénient."
}
-}
\ No newline at end of file
+}
diff --git a/packages/api/src/templates/locales/pt.json b/packages/api/src/templates/locales/pt.json
index 057b991305..1f68b6df87 100644
--- a/packages/api/src/templates/locales/pt.json
+++ b/packages/api/src/templates/locales/pt.json
@@ -14,7 +14,11 @@
"TYPE_HEADER": "Tipo de suporte",
"MESSAGE_HEADER": "Mensagem",
"CONTACT_METHOD_HEADER": "Método de contato preferido",
- "SUBJECT": "Seu pedido de ajuda da LiteFarm"
+ "SUBJECT": "Seu pedido de ajuda da LiteFarm",
+ "REQUEST_INFORMATION": "Pedir informação",
+ "REPORT_A_BUG": "Reportar um erro",
+ "REQUEST_A_FEATURE": "Solicite um recurso",
+ "OTHER": "Outro"
},
"INVITE": {
"GREAT_FOLK": "O grande pessoal da",
@@ -83,10 +87,10 @@
"MANAGER": "Gerente"
},
"EXPORT_MAP": {
- "EXPORT": "Aqui está a exportação do mapa da fazenda para",
+ "EXPORT": "Aqui está a exportação do mapa de ",
"REQUESTED": "que você solicitou do LiteFarm.",
"GREETING": "Tenha um ótimo dia!",
- "SUBJECT0": "Aqui está o mapa de sua fazenda para",
+ "SUBJECT0": "Aqui está o mapa de ",
"SUBJECT1": "em LiteFarm"
},
"EXPORT": {
diff --git a/packages/api/src/templates/sendEmailTemplate.js b/packages/api/src/templates/sendEmailTemplate.js
index 0f215a2d84..91f2f06d92 100644
--- a/packages/api/src/templates/sendEmailTemplate.js
+++ b/packages/api/src/templates/sendEmailTemplate.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (sendEmailTemplate.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -69,15 +69,18 @@ const emailTransporter = new EmailTemplates({
},
});
-function sendEmail(template_path, replacements, email_to, {
- sender = 'system@litefarm.org',
- buttonLink = null,
- attachments = [],
-}) {
+function sendEmail(
+ template_path,
+ replacements,
+ email_to,
+ { sender = 'system@litefarm.org', buttonLink = null, attachments = [] },
+) {
try {
replacements.url = homeUrl();
replacements.year = new Date().getFullYear();
- replacements.buttonLink = buttonLink ? `${homeUrl()}${buttonLink}` : `${homeUrl()}/?email=${encodeURIComponent(email_to)}`;
+ replacements.buttonLink = buttonLink
+ ? `${homeUrl()}${buttonLink}`
+ : `${homeUrl()}/?email=${encodeURIComponent(email_to)}`;
replacements.imgBaseUrl = homeUrl('https://beta.litefarm.org');
const mailOptions = {
message: {
@@ -90,8 +93,12 @@ function sendEmail(template_path, replacements, email_to, {
if (template_path.path === emails.HELP_REQUEST_EMAIL.path) {
mailOptions.message.cc = 'support@litefarm.org';
}
- if (attachments.length && attachments[0] && [emails.HELP_REQUEST_EMAIL.path, emails.MAP_EXPORT_EMAIL.path].includes(template_path.path)) {
- mailOptions.message.attachments = attachments.map(file => ({
+ if (
+ attachments.length &&
+ attachments[0] &&
+ [emails.HELP_REQUEST_EMAIL.path, emails.MAP_EXPORT_EMAIL.path].includes(template_path.path)
+ ) {
+ mailOptions.message.attachments = attachments.map((file) => ({
filename: file.originalname,
content: file.buffer,
}));
@@ -106,5 +113,3 @@ module.exports = {
emails,
sendEmail,
};
-
-
diff --git a/packages/api/src/util/jwt.js b/packages/api/src/util/jwt.js
index c23389fc13..eb795800ee 100644
--- a/packages/api/src/util/jwt.js
+++ b/packages/api/src/util/jwt.js
@@ -2,19 +2,22 @@ const { sign } = require('jsonwebtoken');
const ACCESS_TOKEN_EXPIRES_IN = '7d';
const RESET_PASSWORD_TOKEN_EXPIRES_IN = '1d';
+const SCHEDULER_TOKEN_EXPIRES_IN = '1d';
+
const tokenType = {
access: process.env.JWT_SECRET,
invite: process.env.JWT_INVITE_SECRET,
passwordReset: process.env.JWT_RESET_SECRET,
farm: process.env.JWT_FARM_SECRET,
-}
+ scheduler: process.env.JWT_SCHEDULER_SECRET,
+};
const expireTime = {
access: ACCESS_TOKEN_EXPIRES_IN,
invite: ACCESS_TOKEN_EXPIRES_IN,
passwordReset: RESET_PASSWORD_TOKEN_EXPIRES_IN,
farm: ACCESS_TOKEN_EXPIRES_IN,
-
-}
+ scheduler: SCHEDULER_TOKEN_EXPIRES_IN,
+};
function createToken(type, payload) {
return sign(payload, tokenType[type], {
@@ -27,4 +30,4 @@ module.exports = {
createToken,
expireTime,
tokenType,
-}
+};
diff --git a/packages/api/tests/crop_variety.test.js b/packages/api/tests/crop_variety.test.js
index 73970f7576..4c84c475e2 100644
--- a/packages/api/tests/crop_variety.test.js
+++ b/packages/api/tests/crop_variety.test.js
@@ -13,7 +13,6 @@
* GNU General Public License for more details, see .
*/
-
const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
@@ -22,7 +21,7 @@ const knex = require('../src/util/knex');
jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
const mocks = require('./mock.factories');
-const faker = require('faker');
+const { faker } = require('@faker-js/faker');
const { tableCleanup } = require('./testEnvironment');
const cropVarietyModel = require('../src/models/cropVarietyModel');
@@ -35,9 +34,14 @@ describe('CropVariety Tests', () => {
token = global.token;
});
-
- function postCropVarietyRequest(data, { user_id = newOwner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).post('/crop_variety')
+ function postCropVarietyRequest(
+ data,
+ { user_id = newOwner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
+ chai
+ .request(server)
+ .post('/crop_variety')
.set('Content-Type', 'application/json')
.set('user_id', user_id)
.set('farm_id', farm_id)
@@ -46,15 +50,18 @@ describe('CropVariety Tests', () => {
}
function getRequest(url, { user_id = newOwner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).get(url)
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .end(callback);
+ chai.request(server).get(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
}
- function putCropVarietyRequest(data, { user_id = newOwner.user_id, farm_id = farm.farm_id }, callback) {
+ function putCropVarietyRequest(
+ data,
+ { user_id = newOwner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
const { crop_variety_id } = data;
- chai.request(server).put(`/crop_variety/${crop_variety_id}`)
+ chai
+ .request(server)
+ .put(`/crop_variety/${crop_variety_id}`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
@@ -62,29 +69,28 @@ describe('CropVariety Tests', () => {
}
function deleteRequest(url, { user_id = newOwner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).delete(url)
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .end(callback);
+ chai.request(server).delete(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
}
function fakeUserFarm(role = 1) {
- return ({ ...mocks.fakeUserFarm(), role_id: role });
+ return { ...mocks.fakeUserFarm(), role_id: role };
}
function fakeCropVariety(crop_id, farm_id = farm.farm_id) {
const cropVariety = mocks.fakeCropVariety();
- return ({ ...cropVariety, farm_id, crop_id });
+ return { ...cropVariety, farm_id, crop_id };
}
-
beforeEach(async () => {
[newOwner] = await mocks.usersFactory();
[farm] = await mocks.farmFactory();
- const [ownerFarm] = await mocks.userFarmFactory({
- promisedUser: [newOwner],
- promisedFarm: [farm],
- }, fakeUserFarm(1));
+ const [ownerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [newOwner],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(1),
+ );
middleware = require('../src/middleware/acl/checkJwt');
middleware.mockImplementation((req, res, next) => {
@@ -105,39 +111,60 @@ describe('CropVariety Tests', () => {
let worker;
let workerFarm;
-
beforeEach(async () => {
- [cropVariety] = await mocks.crop_varietyFactory({ promisedFarm: [farm] }, {
- ...mocks.fakeCropVariety(),
- crop_variety_name: 'cropVariety',
- });
+ [cropVariety] = await mocks.crop_varietyFactory(
+ { promisedFarm: [farm] },
+ {
+ ...mocks.fakeCropVariety(),
+ crop_variety_name: 'cropVariety',
+ },
+ );
[worker] = await mocks.usersFactory();
- [workerFarm] = await mocks.userFarmFactory({ promisedUser: [worker], promisedFarm: [farm] }, fakeUserFarm(3));
+ [workerFarm] = await mocks.userFarmFactory(
+ { promisedUser: [worker], promisedFarm: [farm] },
+ fakeUserFarm(3),
+ );
});
describe('Get cropVariety', () => {
test('Workers should get cropVariety by farm id', async (done) => {
- getRequest(`/crop_variety/farm/${farm.farm_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body[0].crop_variety_id).toBe(cropVariety.crop_variety_id);
- done();
- });
+ getRequest(
+ `/crop_variety/farm/${farm.farm_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body[0].crop_variety_id).toBe(cropVariety.crop_variety_id);
+ done();
+ },
+ );
});
test('Workers should get cropVariety by id', async (done) => {
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
- done();
- });
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
+ done();
+ },
+ );
});
test('Should filter out deleted cropVariety', async (done) => {
- await cropVarietyModel.query().context(newOwner).findById(cropVariety.crop_variety_id).delete();
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(404);
- done();
- });
+ await cropVarietyModel
+ .query()
+ .context(newOwner)
+ .findById(cropVariety.crop_variety_id)
+ .delete();
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(404);
+ done();
+ },
+ );
});
describe('Get cropVariety authorization tests', () => {
@@ -148,152 +175,245 @@ describe('CropVariety Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
test('Owner should get cropVariety by farm id', async (done) => {
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, { user_id: newOwner.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
- done();
- });
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ { user_id: newOwner.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
+ done();
+ },
+ );
});
test('Manager should get cropVariety by farm id', async (done) => {
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, { user_id: manager.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
- done();
- });
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ { user_id: manager.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.crop_variety_id).toBe(cropVariety.crop_variety_id);
+ done();
+ },
+ );
});
test('Should get status 403 if an unauthorizedUser tries to get cropVariety by farm id', async (done) => {
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, { user_id: unAuthorizedUser.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ { user_id: unAuthorizedUser.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Circumvent authorization by modifying farm_id', async (done) => {
- getRequest(`/crop_variety/${cropVariety.crop_variety_id}`, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ getRequest(
+ `/crop_variety/${cropVariety.crop_variety_id}`,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
-
-
});
-
});
- describe('Delete cropVariety', function() {
+ describe('Delete cropVariety', function () {
let cropVarietyNotInUse;
beforeEach(async () => {
- [cropVarietyNotInUse] = await mocks.crop_varietyFactory({ promisedFarm: [farm] }, {
- ...mocks.fakeCropVariety(),
- crop_variety_name: 'cropVarietyNotInUse',
- });
+ [cropVarietyNotInUse] = await mocks.crop_varietyFactory(
+ { promisedFarm: [farm] },
+ {
+ ...mocks.fakeCropVariety(),
+ crop_variety_name: 'cropVarietyNotInUse',
+ },
+ );
});
test('should delete a cropVariety that is not in use', async (done) => {
- deleteRequest(`/crop_variety/${cropVarietyNotInUse.crop_variety_id}`, {}, async (err, res) => {
- expect(res.status).toBe(200);
- const cropVarietysDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: true }).where('farm_id', farm.farm_id);
- expect(cropVarietysDeleted.length).toBe(1);
- expect(cropVarietysDeleted[0].deleted).toBe(true);
- expect(cropVarietysDeleted[0].crop_variety_name).toBe(cropVarietyNotInUse.crop_variety_name);
- done();
- });
+ deleteRequest(
+ `/crop_variety/${cropVarietyNotInUse.crop_variety_id}`,
+ {},
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const cropVarietysDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: true })
+ .where('farm_id', farm.farm_id);
+ expect(cropVarietysDeleted.length).toBe(1);
+ expect(cropVarietysDeleted[0].deleted).toBe(true);
+ expect(cropVarietysDeleted[0].crop_variety_name).toBe(
+ cropVarietyNotInUse.crop_variety_name,
+ );
+ done();
+ },
+ );
});
test('Should delete a cropVariety referenced by a completed management plan', async (done) => {
- const [{ farm_id, user_id }] = await mocks.userFarmFactory({}, { status: 'Active', role_id: 1 });
- const [{ crop_variety_id, management_plan_id }] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id }],
- }, {
- complete_date: new Date('December 18, 1995 03:24:00'),
- });
- deleteRequest(`/crop_variety/${crop_variety_id}`, { user_id, farm_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const cropVarietiesDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: true }).where('farm_id', farm_id);
- expect(cropVarietiesDeleted.length).toBe(1);
- expect(cropVarietiesDeleted[0].deleted).toBe(true);
- expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
- const managementPlan = await knex('management_plan').where({ management_plan_id }).first();
- expect(managementPlan.deleted).toBe(true);
- done();
- });
+ const [{ farm_id, user_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [{ crop_variety_id, management_plan_id }] = await mocks.management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ },
+ {
+ complete_date: new Date('December 18, 1995 03:24:00'),
+ },
+ );
+ deleteRequest(
+ `/crop_variety/${crop_variety_id}`,
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const cropVarietiesDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: true })
+ .where('farm_id', farm_id);
+ expect(cropVarietiesDeleted.length).toBe(1);
+ expect(cropVarietiesDeleted[0].deleted).toBe(true);
+ expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
+ const managementPlan = await knex('management_plan')
+ .where({ management_plan_id })
+ .first();
+ expect(managementPlan.deleted).toBe(true);
+ done();
+ },
+ );
});
test('Should delete a cropVariety referenced by a abandoned management plan', async (done) => {
- const [{ farm_id, user_id }] = await mocks.userFarmFactory({}, { status: 'Active', role_id: 1 });
- const [{ crop_variety_id, management_plan_id }] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id }],
- }, {
- abandon_date: new Date('December 18, 1995 03:24:00'),
- });
- deleteRequest(`/crop_variety/${crop_variety_id}`, { user_id, farm_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const cropVarietiesDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: true }).where('farm_id', farm_id);
- expect(cropVarietiesDeleted.length).toBe(1);
- expect(cropVarietiesDeleted[0].deleted).toBe(true);
- expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
- const managementPlan = await knex('management_plan').where({ management_plan_id }).first();
- expect(managementPlan.deleted).toBe(true);
- done();
- });
+ const [{ farm_id, user_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [{ crop_variety_id, management_plan_id }] = await mocks.management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ },
+ {
+ abandon_date: new Date('December 18, 1995 03:24:00'),
+ },
+ );
+ deleteRequest(
+ `/crop_variety/${crop_variety_id}`,
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const cropVarietiesDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: true })
+ .where('farm_id', farm_id);
+ expect(cropVarietiesDeleted.length).toBe(1);
+ expect(cropVarietiesDeleted[0].deleted).toBe(true);
+ expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
+ const managementPlan = await knex('management_plan')
+ .where({ management_plan_id })
+ .first();
+ expect(managementPlan.deleted).toBe(true);
+ done();
+ },
+ );
});
test('Management plan with any complete date or abandon date is considered completed or abandoned', async (done) => {
- const [{ farm_id, user_id }] = await mocks.userFarmFactory({}, { status: 'Active', role_id: 1 });
- const [{ crop_variety_id }] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id }],
- }, {
- abandon_date: new Date(faker.date.future()),
- });
- deleteRequest(`/crop_variety/${crop_variety_id}`, { user_id, farm_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const cropVarietiesDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: true }).where('farm_id', farm_id);
- expect(cropVarietiesDeleted.length).toBe(1);
- expect(cropVarietiesDeleted[0].deleted).toBe(true);
- expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
- done();
- });
+ const [{ farm_id, user_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [{ crop_variety_id }] = await mocks.management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ },
+ {
+ abandon_date: new Date(faker.date.future()),
+ },
+ );
+ deleteRequest(
+ `/crop_variety/${crop_variety_id}`,
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const cropVarietiesDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: true })
+ .where('farm_id', farm_id);
+ expect(cropVarietiesDeleted.length).toBe(1);
+ expect(cropVarietiesDeleted[0].deleted).toBe(true);
+ expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
+ done();
+ },
+ );
});
test('Should not delete a cropVariety that is part of an active management plan', async (done) => {
- const [{ farm_id, user_id }] = await mocks.userFarmFactory({}, { status: 'Active', role_id: 1 });
- const [managementPlan] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id }],
- }, {});
- deleteRequest(`/crop_variety/${managementPlan.crop_variety_id}`, { user_id, farm_id }, async (err, res) => {
- expect(res.status).toBe(400);
- const cropVarietyNotDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: false }).where('farm_id', farm_id);
- expect(cropVarietyNotDeleted.length).toBe(0);
- done();
- });
- })
-
+ const [{ farm_id, user_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [managementPlan] = await mocks.management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ },
+ {},
+ );
+ deleteRequest(
+ `/crop_variety/${managementPlan.crop_variety_id}`,
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ const cropVarietyNotDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: false })
+ .where('farm_id', farm_id);
+ expect(cropVarietyNotDeleted.length).toBe(0);
+ done();
+ },
+ );
+ });
describe('Delete cropVariety Authorization test', () => {
let worker;
@@ -303,77 +423,112 @@ describe('CropVariety Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
test('Manager should delete a cropVariety that has past management plan', async (done) => {
- const [{farm_id, user_id}] = await mocks.userFarmFactory({}, {status: 'Active', role_id: 2});
- const [{crop_variety_id}] = await mocks.management_planFactory({
- promisedFarm: [{farm_id}]
- }, {
- start_date: new Date('December 17, 1995 03:24:00'),
- complete_date: new Date('December 18, 1995 03:24:00'),
- });
+ const [{ farm_id, user_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 2 },
+ );
+ const [{ crop_variety_id }] = await mocks.management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ },
+ {
+ start_date: new Date('December 17, 1995 03:24:00'),
+ complete_date: new Date('December 18, 1995 03:24:00'),
+ },
+ );
console.log(crop_variety_id);
- deleteRequest(`/crop_variety/${crop_variety_id}`, { user_id, farm_id }, async (err, response) => {
- expect(response.status).toBe(200);
- const cropVarietiesDeleted = await cropVarietyModel.query().whereDeleted().context({ showHidden: true }).where('farm_id', farm_id);
- expect(cropVarietiesDeleted.length).toBe(1);
- expect(cropVarietiesDeleted[0].deleted).toBe(true);
- expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
- done();
- });
+ deleteRequest(
+ `/crop_variety/${crop_variety_id}`,
+ { user_id, farm_id },
+ async (err, response) => {
+ expect(response.status).toBe(200);
+ const cropVarietiesDeleted = await cropVarietyModel
+ .query()
+ .whereDeleted()
+ .context({ showHidden: true })
+ .where('farm_id', farm_id);
+ expect(cropVarietiesDeleted.length).toBe(1);
+ expect(cropVarietiesDeleted[0].deleted).toBe(true);
+ expect(cropVarietiesDeleted[0].crop_variety_id).toBe(crop_variety_id);
+ done();
+ },
+ );
});
test('should return 403 if unauthorized user tries to delete a cropVariety that is not in use', async (done) => {
- deleteRequest(`/crop_variety/${cropVarietyNotInUse.crop_variety_id}`, { user_id: unAuthorizedUser.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/crop_variety/${cropVarietyNotInUse.crop_variety_id}`,
+ { user_id: unAuthorizedUser.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Circumvent authorization by modifying farm_id', async (done) => {
- deleteRequest(`/crop_variety/${cropVarietyNotInUse.crop_variety_id}`, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/crop_variety/${cropVarietyNotInUse.crop_variety_id}`,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('should return 403 if a worker tries to delete a cropVariety that is not in use', async (done) => {
- deleteRequest(`/crop_variety/${cropVarietyNotInUse.crop_variety_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/crop_variety/${cropVarietyNotInUse.crop_variety_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
-
describe('Put cropVariety', () => {
-
test('Owner should be able to edit a cropVariety', async (done) => {
- let newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
+ const newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
putCropVarietyRequest(newCropVariety, {}, async (err, res) => {
expect(res.status).toBe(200);
- const cropVarietyRes = await cropVarietyModel.query().where('crop_variety_id', cropVariety.crop_variety_id).first();
+ const cropVarietyRes = await cropVarietyModel
+ .query()
+ .where('crop_variety_id', cropVariety.crop_variety_id)
+ .first();
expect(cropVarietyRes.crop_variety_name).toBe(newCropVariety.crop_variety_name);
done();
});
@@ -387,72 +542,101 @@ describe('CropVariety Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
test('Manager should be able to edit a cropVariety', async (done) => {
- let newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
- putCropVarietyRequest(newCropVariety, { user_id: manager.user_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const cropVarietyRes = await cropVarietyModel.query().where('crop_variety_id', cropVariety.crop_variety_id).first();
- expect(cropVarietyRes.crop_variety_name).toBe(newCropVariety.crop_variety_name);
- done();
- });
+ const newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
+ putCropVarietyRequest(
+ newCropVariety,
+ { user_id: manager.user_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const cropVarietyRes = await cropVarietyModel
+ .query()
+ .where('crop_variety_id', cropVariety.crop_variety_id)
+ .first();
+ expect(cropVarietyRes.crop_variety_name).toBe(newCropVariety.crop_variety_name);
+ done();
+ },
+ );
});
test('should return 403 when a worker tries to edit cropVariety', async (done) => {
- let newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
+ const newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
putCropVarietyRequest(newCropVariety, { user_id: worker.user_id }, async (err, res) => {
expect(res.status).toBe(403);
- const cropVarietyRes = await cropVarietyModel.query().where('crop_variety_id', cropVariety.crop_variety_id).first();
+ const cropVarietyRes = await cropVarietyModel
+ .query()
+ .where('crop_variety_id', cropVariety.crop_variety_id)
+ .first();
expect(cropVarietyRes.crop_variety_name).toBe(cropVariety.crop_variety_name);
done();
});
});
test('should return 403 when an unauthorized tries to edit cropVariety', async (done) => {
- let newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
- putCropVarietyRequest(newCropVariety, { user_id: unAuthorizedUser.user_id }, async (err, res) => {
- expect(res.status).toBe(403);
- const cropVarietyRes = await cropVarietyModel.query().where('crop_variety_id', cropVariety.crop_variety_id).first();
- expect(cropVarietyRes.crop_variety_name).toBe(cropVariety.crop_variety_name);
- done();
- });
+ const newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
+ putCropVarietyRequest(
+ newCropVariety,
+ { user_id: unAuthorizedUser.user_id },
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ const cropVarietyRes = await cropVarietyModel
+ .query()
+ .where('crop_variety_id', cropVariety.crop_variety_id)
+ .first();
+ expect(cropVarietyRes.crop_variety_name).toBe(cropVariety.crop_variety_name);
+ done();
+ },
+ );
});
test('Circumvent authorization by modifying farm_id', async (done) => {
- let newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
- putCropVarietyRequest(newCropVariety, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(403);
- const cropVarietyRes = await cropVarietyModel.query().where('crop_variety_id', cropVariety.crop_variety_id).first();
- expect(cropVarietyRes.crop_variety_name).toBe(cropVariety.crop_variety_name);
- done();
- });
+ const newCropVariety = { ...cropVariety, ...mocks.fakeCropVariety() };
+ putCropVarietyRequest(
+ newCropVariety,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ const cropVarietyRes = await cropVarietyModel
+ .query()
+ .where('crop_variety_id', cropVariety.crop_variety_id)
+ .first();
+ expect(cropVarietyRes.crop_variety_name).toBe(cropVariety.crop_variety_name);
+ done();
+ },
+ );
});
-
});
});
-
-
});
});
@@ -463,7 +647,7 @@ describe('CropVariety Tests', () => {
});
test('should return 400 status if cropVariety is posted w/o crop_variety_name', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
delete cropVariety.crop_variety_name;
postCropVarietyRequest(cropVariety, {}, (err, res) => {
expect(res.status).toBe(400);
@@ -473,7 +657,7 @@ describe('CropVariety Tests', () => {
});
test('should return 403 status if headers.farm_id is set to null', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.farm_id = null;
postCropVarietyRequest(cropVariety, {}, (err, res) => {
expect(res.status).toBe(403);
@@ -482,7 +666,7 @@ describe('CropVariety Tests', () => {
});
test('should post and get a valid cropVariety', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
delete cropVariety.nutrient_credits;
postCropVarietyRequest(cropVariety, {}, async (err, res) => {
@@ -496,7 +680,7 @@ describe('CropVariety Tests', () => {
});
test('should post and get a valid cropVariety with null compliance info', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
cropVariety.compliance_file_url = '';
cropVariety.organic = null;
@@ -513,11 +697,14 @@ describe('CropVariety Tests', () => {
});
});
- describe('crop_variety_name + genus + species uniqueness tests', function() {
+ describe('crop_variety_name + genus + species uniqueness tests', function () {
test('should return 400 status if cropVariety is posted w/o variety name', async (done) => {
let cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
- [cropVariety] = await mocks.crop_varietyFactory({ promisedFarm: [farm], createdUser: [newOwner] }, cropVariety);
+ [cropVariety] = await mocks.crop_varietyFactory(
+ { promisedFarm: [farm], createdUser: [newOwner] },
+ cropVariety,
+ );
postCropVarietyRequest(cropVariety, {}, (err, res) => {
expect(res.status).toBe(400);
done();
@@ -525,12 +712,15 @@ describe('CropVariety Tests', () => {
});
test('should post a cropVariety and its variety', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
- const [cropVariety1] = await mocks.crop_varietyFactory({
- promisedFarm: [farm],
- createdUser: [newOwner],
- }, cropVariety);
+ const [cropVariety1] = await mocks.crop_varietyFactory(
+ {
+ promisedFarm: [farm],
+ createdUser: [newOwner],
+ },
+ cropVariety,
+ );
cropVariety.crop_variety_name += ' - 1';
postCropVarietyRequest(cropVariety, {}, async (err, res) => {
expect(res.status).toBe(201);
@@ -549,53 +739,63 @@ describe('CropVariety Tests', () => {
let unAuthorizedUser;
let farmunAuthorizedUser;
-
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
[crop] = await mocks.cropFactory({ promisedFarm: [farm] });
});
-
test('owner should return 403 status if cropVariety is posted by unauthorized user', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
postCropVarietyRequest(cropVariety, { user_id: unAuthorizedUser.user_id }, (err, res) => {
expect(res.status).toBe(403);
- expect(res.error.text).toBe('User does not have the following permission(s): add:crop_variety');
+ expect(res.error.text).toBe(
+ 'User does not have the following permission(s): add:crop_variety',
+ );
done();
});
});
test('should return 403 status if cropVariety is posted by newWorker', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
postCropVarietyRequest(cropVariety, { user_id: worker.user_id }, (err, res) => {
expect(res.status).toBe(403);
- expect(res.error.text).toBe('User does not have the following permission(s): add:crop_variety');
+ expect(res.error.text).toBe(
+ 'User does not have the following permission(s): add:crop_variety',
+ );
done();
});
});
test('manager should post and get a valid cropVariety', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
postCropVarietyRequest(cropVariety, { user_id: manager.user_id }, async (err, res) => {
expect(res.status).toBe(201);
@@ -607,20 +807,21 @@ describe('CropVariety Tests', () => {
});
test('Circumvent authorization by modify farm_id', async (done) => {
- let cropVariety = fakeCropVariety(crop.crop_id);
+ const cropVariety = fakeCropVariety(crop.crop_id);
cropVariety.crop_variety_name = `${cropVariety.cropVariety_specie} - ${cropVariety.crop_variety_name}`;
- postCropVarietyRequest(cropVariety, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- expect(res.error.text).toBe('user not authorized to access farm');
- done();
- });
+ postCropVarietyRequest(
+ cropVariety,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ expect(res.error.text).toBe('user not authorized to access farm');
+ done();
+ },
+ );
});
-
});
-
-
});
});
diff --git a/packages/api/tests/documents.test.js b/packages/api/tests/documents.test.js
index a83137f2ee..a030321238 100644
--- a/packages/api/tests/documents.test.js
+++ b/packages/api/tests/documents.test.js
@@ -7,8 +7,6 @@ jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
const mocks = require('./mock.factories');
const { tableCleanup } = require('./testEnvironment');
-const moment = require('moment');
-
describe('Document tests', () => {
let middleware;
@@ -19,24 +17,26 @@ describe('Document tests', () => {
req.user.user_id = req.get('user_id');
next();
});
- })
+ });
function getRequest(url, { user_id, farm_id }, callback) {
- chai.request(server).get(url)
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .end(callback);
+ chai.request(server).get(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
}
- function archiveDocumentRequest(document_id, { user_id, farm_id }, callback) {
- chai.request(server).patch(`/document/archive/${document_id}`)
+ function patchDocumentArchiveRequest(document_id, data, { user_id, farm_id }, callback) {
+ chai
+ .request(server)
+ .patch(`/document/archive/${document_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
+ .send(data)
.end(callback);
}
function postManagementPlanRequest(url, data, { user_id, farm_id }, callback) {
- chai.request(server).post(url)
+ chai
+ .request(server)
+ .post(url)
.set('Content-Type', 'application/json')
.set('user_id', user_id)
.set('farm_id', farm_id)
@@ -46,7 +46,9 @@ describe('Document tests', () => {
function putDocumentRequest(data, { user_id, farm_id }, callback) {
const { document_id } = data;
- chai.request(server).put(`/document/${document_id}`)
+ chai
+ .request(server)
+ .put(`/document/${document_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -54,7 +56,7 @@ describe('Document tests', () => {
}
function fakeUserFarm(role = 1) {
- return ({ ...mocks.fakeUserFarm(), role_id: role });
+ return { ...mocks.fakeUserFarm(), role_id: role };
}
afterAll(async (done) => {
@@ -78,10 +80,10 @@ describe('Document tests', () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
getRequest(`/document/farm/${farm_id}`, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(200)
+ expect(res.status).toBe(200);
expect(res.body.length).toBe(1);
done();
- })
+ });
});
test('EO should GET documents if they exist', async (done) => {
@@ -93,132 +95,166 @@ describe('Document tests', () => {
done();
});
});
-
-
});
describe('Post and put documents tests', () => {
- function getFakeDocument(farm_id, numberOfFiles, files = Array.apply(null, { length: numberOfFiles }).map(_ => mocks.fakeFile())) {
+ function getFakeDocument(
+ farm_id,
+ numberOfFiles,
+ files = Array.apply(null, { length: numberOfFiles }).map(() => mocks.fakeFile()),
+ ) {
return { ...mocks.fakeDocument(), farm_id, files };
}
describe('Post document test', () => {
test('Should return 400 when files === []', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 0), {
- user_id,
- farm_id,
- }, (err, res) => {
- expect(res.status).toBe(400);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 0),
+ {
+ user_id,
+ farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('Should return 400 when files is not an array', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 0, 'files'), {
- user_id,
- farm_id,
- }, (err, res) => {
- expect(res.status).toBe(400);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 0, 'files'),
+ {
+ user_id,
+ farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('Should post document with multiple files', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 4), {
- user_id,
- farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(201);
- const files = await knex('file').where({ document_id: res.body.document_id });
- expect(files.length).toBe(4);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 4),
+ {
+ user_id,
+ farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(201);
+ const files = await knex('file').where({ document_id: res.body.document_id });
+ expect(files.length).toBe(4);
+ done();
+ },
+ );
});
describe('Post document authorization test', function () {
test('Worker should not POST documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 4), {
- user_id,
- farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 4),
+ {
+ user_id,
+ farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Owner should POST a document', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 1), {
- user_id,
- farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(201);
- const files = await knex('file').where({ document_id: res.body.document_id });
- expect(files.length).toBe(1);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 1),
+ {
+ user_id,
+ farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(201);
+ const files = await knex('file').where({ document_id: res.body.document_id });
+ expect(files.length).toBe(1);
+ done();
+ },
+ );
});
test('Manager should POST a document', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 1), {
- user_id,
- farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(201);
- const files = await knex('file').where({ document_id: res.body.document_id });
- expect(files.length).toBe(1);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 1),
+ {
+ user_id,
+ farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(201);
+ const files = await knex('file').where({ document_id: res.body.document_id });
+ expect(files.length).toBe(1);
+ done();
+ },
+ );
});
test('EO should POST a document', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- postManagementPlanRequest(`/document/farm/${farm_id}`, getFakeDocument(farm_id, 1), {
- user_id,
- farm_id,
- }, async (err, res) => {
- expect(res.status).toBe(201);
- const files = await knex('file').where({ document_id: res.body.document_id });
- expect(files.length).toBe(1);
- done();
- });
+ postManagementPlanRequest(
+ `/document/farm/${farm_id}`,
+ getFakeDocument(farm_id, 1),
+ {
+ user_id,
+ farm_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(201);
+ const files = await knex('file').where({ document_id: res.body.document_id });
+ expect(files.length).toBe(1);
+ done();
+ },
+ );
});
});
});
- describe('Put document test', () => {
-
+ describe.only('Put document test', () => {
async function documentWithFilesFactory(farm_id, numberOfFiles = 2) {
const [document] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
const files = [];
- for(let i = 0; i {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const document = await documentWithFilesFactory(farm_id,1);
+ const document = await documentWithFilesFactory(farm_id, 1);
const newDocument = getFakeDocument(farm_id, 2);
- let data = { document_id: document.document_id, ...newDocument };
+ const data = { document_id: document.document_id, ...newDocument };
data.valid_until = fakeDate;
putDocumentRequest(data, { user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(201);
const document = await knex('document').where({ document_id: res.body.document_id });
expect(document[0].name).toBe(newDocument.name);
expect(document[0].type).toBe(newDocument.type);
- expect(formatDate(document[0].valid_until)).toBe(fakeDate);
+ expect(document[0].valid_until).toEqual(fakeDate);
const files = await knex('file').where({ document_id: res.body.document_id });
expect(files.length).toBe(2);
done();
@@ -227,35 +263,34 @@ describe('Document tests', () => {
test('Owner should be able to edit a document, delete files', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const document = await documentWithFilesFactory(farm_id,3);
+ const document = await documentWithFilesFactory(farm_id, 3);
const newDocument = getFakeDocument(farm_id, 1);
- let data = { document_id: document.document_id, ...newDocument };
+ const data = { document_id: document.document_id, ...newDocument };
data.valid_until = fakeDate;
putDocumentRequest(data, { user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(201);
const document = await knex('document').where({ document_id: res.body.document_id });
expect(document[0].name).toBe(newDocument.name);
expect(document[0].type).toBe(newDocument.type);
- expect(formatDate(document[0].valid_until)).toBe(fakeDate);
+ expect(document[0].valid_until).toEqual(fakeDate);
const files = await knex('file').where({ document_id: res.body.document_id });
expect(files.length).toBe(1);
done();
});
});
-
test('Manager shoud be able to edit a document', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
- const document = await documentWithFilesFactory(farm_id,3);
+ const document = await documentWithFilesFactory(farm_id, 3);
const newDocument = getFakeDocument(farm_id, 1);
- let data = { document_id: document.document_id, ...newDocument };
+ const data = { document_id: document.document_id, ...newDocument };
data.valid_until = fakeDate;
putDocumentRequest(data, { user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(201);
const document = await knex('document').where({ document_id: res.body.document_id });
expect(document[0].name).toBe(newDocument.name);
expect(document[0].type).toBe(newDocument.type);
- expect(formatDate(document[0].valid_until)).toBe(fakeDate);
+ expect(document[0].valid_until).toEqual(fakeDate);
const files = await knex('file').where({ document_id: res.body.document_id });
expect(files.length).toBe(1);
done();
@@ -264,16 +299,16 @@ describe('Document tests', () => {
test('EO shoud be able to edit a document', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
- const document = await documentWithFilesFactory(farm_id,3);
+ const document = await documentWithFilesFactory(farm_id, 3);
const newDocument = getFakeDocument(farm_id, 1);
- let data = { document_id: document.document_id, ...newDocument };
+ const data = { document_id: document.document_id, ...newDocument };
data.valid_until = fakeDate;
putDocumentRequest(data, { user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(201);
const document = await knex('document').where({ document_id: res.body.document_id });
expect(document[0].name).toBe(newDocument.name);
expect(document[0].type).toBe(newDocument.type);
- expect(formatDate(document[0].valid_until)).toBe(fakeDate);
+ expect(document[0].valid_until).toEqual(fakeDate);
const files = await knex('file').where({ document_id: res.body.document_id });
expect(files.length).toBe(1);
done();
@@ -284,7 +319,7 @@ describe('Document tests', () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
const document = await documentWithFilesFactory(farm_id);
const newDocument = getFakeDocument(farm_id, 1);
- let data = { document_id: document.document_id, ...newDocument };
+ const data = { document_id: document.document_id, ...newDocument };
putDocumentRequest(data, { user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(403);
done();
@@ -297,49 +332,91 @@ describe('Document tests', () => {
test('User should be able to archive documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
const [{ document_id }] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- archiveDocumentRequest(document_id, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(200);
- done();
- })
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: true },
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const document = await knex('document').where({ document_id });
+ expect(document[0].archived).toBe(true);
+ done();
+ },
+ );
});
- describe('Archive document authorization tests', () => {
+ test('User should be able to unarchive documents', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
+ const [{ document_id }] = await mocks.documentFactory(
+ { promisedFarm: [{ farm_id }] },
+ mocks.fakeDocument({ archived: true }),
+ );
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: false },
+ { user_id, farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const document = await knex('document').where({ document_id });
+ expect(document[0].archived).toBe(false);
+ done();
+ },
+ );
+ });
+ describe('Archive document authorization tests', () => {
test('Owner should be able to archive documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
const [{ document_id }] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- archiveDocumentRequest(document_id, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(200);
- done();
- })
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: true },
+ { user_id, farm_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ done();
+ },
+ );
});
test('Manager should be able to archive documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
const [{ document_id }] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- archiveDocumentRequest(document_id, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(200);
- done();
- })
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: true },
+ { user_id, farm_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ done();
+ },
+ );
});
test('EO should be able to archive documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
const [{ document_id }] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- archiveDocumentRequest(document_id, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(200);
- done();
- })
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: true },
+ { user_id, farm_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ done();
+ },
+ );
});
test('Worker should NOT be able to archive documents', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
const [{ document_id }] = await mocks.documentFactory({ promisedFarm: [{ farm_id }] });
- archiveDocumentRequest(document_id, { user_id, farm_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- })
+ patchDocumentArchiveRequest(
+ document_id,
+ { archived: true },
+ { user_id, farm_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
-
});
-
});
-})
-
+});
diff --git a/packages/api/tests/insightsAPI.test.js b/packages/api/tests/insightsAPI.test.js
index 6fee4447da..8a70015081 100644
--- a/packages/api/tests/insightsAPI.test.js
+++ b/packages/api/tests/insightsAPI.test.js
@@ -16,9 +16,9 @@
const chai = require('chai');
const chaiHttp = require('chai-http');
chai.use(chaiHttp);
-const chai_assert = chai.assert; // Using Assert style
-const chai_expect = chai.expect; // Using Expect style
-const chai_should = chai.should(); // Using Should style
+const chai_assert = chai.assert; // Using Assert style
+const chai_expect = chai.expect; // Using Expect style
+const chai_should = chai.should(); // Using Should style
const knex = require('../src/util/knex');
const server = require('./../src/server');
const mocks = require('./mock.factories');
@@ -26,7 +26,7 @@ const { tableCleanup } = require('./testEnvironment');
const insightHelpers = require('../src/controllers/insightHelpers.js');
jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
-let faker = require('faker');
+const { faker } = require('@faker-js/faker');
const moment = require('moment');
const insigntController = require('../src/controllers/insightController');
@@ -50,7 +50,6 @@ xdescribe('insights test', () => {
});
describe('People Fed', () => {
-
async function generateSaleData(crop, quantity, user) {
const [{ user_id, farm_id }] = user ? user : await createUserFarm(1);
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
@@ -64,11 +63,13 @@ xdescribe('insights test', () => {
promisedCropVariety: [{ crop_variety_id }],
});
const [{ sale_id }] = await mocks.saleFactory({ promisedUserFarm: [{ user_id, farm_id }] });
- const [{ crop_sale_id }] = await mocks.cropSaleFactory({
+ const [{ crop_sale_id }] = await mocks.cropSaleFactory(
+ {
promisedCrop: [{ crop_id }],
promisedSale: [{ sale_id }],
},
- { quantity_kg: quantity, sale_value: 3 });
+ { quantity_kg: quantity, sale_value: 3 },
+ );
return { user_id, farm_id, management_plan_id };
}
@@ -100,11 +101,15 @@ xdescribe('insights test', () => {
await knex.raw('DELETE FROM "harvestUseType"');
});
test('Should get 9 meals in calories from a crop with 250 calories and 3kg sale', async (done) => {
- const { user_id, farm_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- energy: 250,
- }, 3);
+ const { user_id, farm_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ energy: 250,
+ },
+ 3,
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -115,20 +120,29 @@ xdescribe('insights test', () => {
});
test('Should get 9 meals in calories from a crop with 250 calories and 1kg sale and 2 kg harvest log', async (done) => {
- const { user_id, farm_id, management_plan_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- energy: 250,
- }, 1);
- const harvestUseType = await mocks.harvest_use_typeFactory({}, {
- harvest_use_type_id: 2,
- harvest_use_type_name: 'test',
- });
- await mocks.harvest_useFactory({
+ const { user_id, farm_id, management_plan_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ energy: 250,
+ },
+ 1,
+ );
+ const harvestUseType = await mocks.harvest_use_typeFactory(
+ {},
+ {
+ harvest_use_type_id: 2,
+ harvest_use_type_name: 'test',
+ },
+ );
+ await mocks.harvest_useFactory(
+ {
promisedManagementPlan: [{ management_plan_id }],
promisedHarvestUseType: harvestUseType,
},
- { quantity_kg: 2 });
+ { quantity_kg: 2 },
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -139,20 +153,29 @@ xdescribe('insights test', () => {
});
test('Should get 9 meals in protein from a crop with 5.2g protein 1kg sale and 2 kg harvest log', async (done) => {
- const { user_id, farm_id, management_plan_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- protein: 5.2,
- }, 1);
- const harvestUseType = await mocks.harvest_use_typeFactory({}, {
- harvest_use_type_id: 2,
- harvest_use_type_name: 'test',
- });
- await mocks.harvest_useFactory({
+ const { user_id, farm_id, management_plan_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ protein: 5.2,
+ },
+ 1,
+ );
+ const harvestUseType = await mocks.harvest_use_typeFactory(
+ {},
+ {
+ harvest_use_type_id: 2,
+ harvest_use_type_name: 'test',
+ },
+ );
+ await mocks.harvest_useFactory(
+ {
promisedManagementPlan: [{ management_plan_id }],
promisedHarvestUseType: harvestUseType,
},
- { quantity_kg: 2 });
+ { quantity_kg: 2 },
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -163,20 +186,29 @@ xdescribe('insights test', () => {
});
test('Should get 9 meals in fat from a crop with 75g fat 1kg sale and 2 kg harvest log', async (done) => {
- const { user_id, farm_id, management_plan_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- lipid: 75,
- }, 1);
- const harvestUseType = await mocks.harvest_use_typeFactory({}, {
- harvest_use_type_id: 2,
- harvest_use_type_name: 'test',
- });
- await mocks.harvest_useFactory({
+ const { user_id, farm_id, management_plan_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ lipid: 75,
+ },
+ 1,
+ );
+ const harvestUseType = await mocks.harvest_use_typeFactory(
+ {},
+ {
+ harvest_use_type_id: 2,
+ harvest_use_type_name: 'test',
+ },
+ );
+ await mocks.harvest_useFactory(
+ {
promisedManagementPlan: [{ management_plan_id }],
promisedHarvestUseType: harvestUseType,
},
- { quantity_kg: 2 });
+ { quantity_kg: 2 },
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -187,20 +219,29 @@ xdescribe('insights test', () => {
});
test('Should get 9 meals in vitamin c from a crop with 9g vitamin c 1kg sale and 2 kg harvest log', async (done) => {
- const { user_id, farm_id, management_plan_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- vitc: 9,
- }, 1);
- const harvestUseType = await mocks.harvest_use_typeFactory({}, {
- harvest_use_type_id: 2,
- harvest_use_type_name: 'test',
- });
- await mocks.harvest_useFactory({
+ const { user_id, farm_id, management_plan_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ vitc: 9,
+ },
+ 1,
+ );
+ const harvestUseType = await mocks.harvest_use_typeFactory(
+ {},
+ {
+ harvest_use_type_id: 2,
+ harvest_use_type_name: 'test',
+ },
+ );
+ await mocks.harvest_useFactory(
+ {
promisedManagementPlan: [{ management_plan_id }],
promisedHarvestUseType: harvestUseType,
},
- { quantity_kg: 2 });
+ { quantity_kg: 2 },
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -211,20 +252,29 @@ xdescribe('insights test', () => {
});
test('Should get 9 meals in vitamin A from a crop with 90g vitamin a 1kg sale and 2 kg harvest log', async (done) => {
- const { user_id, farm_id, management_plan_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- vita_rae: 90,
- }, 1);
- const harvestUseType = await mocks.harvest_use_typeFactory({}, {
- harvest_use_type_id: 2,
- harvest_use_type_name: 'test',
- });
- await mocks.harvest_useFactory({
+ const { user_id, farm_id, management_plan_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ vita_rae: 90,
+ },
+ 1,
+ );
+ const harvestUseType = await mocks.harvest_use_typeFactory(
+ {},
+ {
+ harvest_use_type_id: 2,
+ harvest_use_type_name: 'test',
+ },
+ );
+ await mocks.harvest_useFactory(
+ {
promisedManagementPlan: [{ management_plan_id }],
promisedHarvestUseType: harvestUseType,
},
- { quantity_kg: 2 });
+ { quantity_kg: 2 },
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBeGreaterThan(0);
@@ -235,29 +285,55 @@ xdescribe('insights test', () => {
});
test('Should get average of 9 meals with 3 kg sales of crops that generate 9 meals themselves', async (done) => {
- const { user_id, farm_id } = await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- energy: 250,
- }, 3);
- await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- protein: 5.2,
- }, 3, [{ user_id, farm_id }]);
- await generateSaleData({ ...mocks.fakeCrop(), percentrefuse: 0, ...emptyNutrients, lipid: 75 }, 3, [{
- user_id,
- farm_id,
- }]);
- await generateSaleData({ ...mocks.fakeCrop(), percentrefuse: 0, ...emptyNutrients, vitc: 9 }, 3, [{
- user_id,
- farm_id,
- }]);
- await generateSaleData({
- ...mocks.fakeCrop(),
- percentrefuse: 0, ...emptyNutrients,
- vita_rae: 90,
- }, 3, [{ user_id, farm_id }]);
+ const { user_id, farm_id } = await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ energy: 250,
+ },
+ 3,
+ );
+ await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ protein: 5.2,
+ },
+ 3,
+ [{ user_id, farm_id }],
+ );
+ await generateSaleData(
+ { ...mocks.fakeCrop(), percentrefuse: 0, ...emptyNutrients, lipid: 75 },
+ 3,
+ [
+ {
+ user_id,
+ farm_id,
+ },
+ ],
+ );
+ await generateSaleData(
+ { ...mocks.fakeCrop(), percentrefuse: 0, ...emptyNutrients, vitc: 9 },
+ 3,
+ [
+ {
+ user_id,
+ farm_id,
+ },
+ ],
+ );
+ await generateSaleData(
+ {
+ ...mocks.fakeCrop(),
+ percentrefuse: 0,
+ ...emptyNutrients,
+ vita_rae: 90,
+ },
+ 3,
+ [{ user_id, farm_id }],
+ );
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
expect(res.status).toBe(200);
expect(res.body.preview).toBe(9);
@@ -265,7 +341,6 @@ xdescribe('insights test', () => {
});
});
-
test('Should get no meals in preview from a crop with no sales and no harvests', async (done) => {
const [{ user_id, farm_id }] = await createUserFarm(1);
getInsight(farm_id, user_id, 'people_fed', (err, res) => {
@@ -274,10 +349,7 @@ xdescribe('insights test', () => {
done();
});
});
-
});
-
-
});
describe('Soil Om', () => {
@@ -358,8 +430,12 @@ xdescribe('insights test', () => {
describe('prices distance', () => {
describe('Unit tests', () => {
test('Distance between two coordinate test', async (done) => {
- expect(insightHelpers.distance(62.990967, -71.463767, 52.990967, -91.463767) - 1612.09).toBeLessThan(0.5);
- expect(insightHelpers.distance(-62.990967, 171.463767, -52.990967, 191.463767) - 1612.09).toBeLessThan(0.5);
+ expect(
+ insightHelpers.distance(62.990967, -71.463767, 52.990967, -91.463767) - 1612.09,
+ ).toBeLessThan(0.5);
+ expect(
+ insightHelpers.distance(-62.990967, 171.463767, -52.990967, 191.463767) - 1612.09,
+ ).toBeLessThan(0.5);
expect(insightHelpers.distance(62.990967, -71.463767, 62.990967, -71.463767)).toBe(0);
done();
});
@@ -367,63 +443,63 @@ xdescribe('insights test', () => {
test('FormatPricesNearByData Test', async (done) => {
const salesByCropsFarmIdMonth = [
{
- 'year_month': '2020-12',
- 'crop_common_name': 'quaerat rerum fugiat',
- 'crop_translation_key': 'quaerat rerum fugiat',
- 'sale_quant': 793,
- 'sale_value': 98,
- 'farm_id': '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
- 'grid_points': {
- 'lat': 62.990967,
- 'lng': -71.463767,
+ year_month: '2020-12',
+ crop_common_name: 'quaerat rerum fugiat',
+ crop_translation_key: 'quaerat rerum fugiat',
+ sale_quant: 793,
+ sale_value: 98,
+ farm_id: '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
+ grid_points: {
+ lat: 62.990967,
+ lng: -71.463767,
},
},
{
- 'year_month': '2020-12',
- 'crop_common_name': 'quaerat rerum fugiat',
- 'crop_translation_key': 'quaerat rerum fugiat',
- 'sale_quant': 73,
- 'sale_value': 98,
- 'farm_id': '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
- 'grid_points': {
- 'lat': 62.990967,
- 'lng': -71.463767,
+ year_month: '2020-12',
+ crop_common_name: 'quaerat rerum fugiat',
+ crop_translation_key: 'quaerat rerum fugiat',
+ sale_quant: 73,
+ sale_value: 98,
+ farm_id: '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
+ grid_points: {
+ lat: 62.990967,
+ lng: -71.463767,
},
},
{
- 'year_month': '2020-12',
- 'crop_common_name': 'quaerat rerum fugiat',
- 'crop_translation_key': 'quaerat rerum fugiat',
- 'sale_quant': 182,
- 'sale_value': 607,
- 'farm_id': '8788ef8b-5c36-11eb-b3aa-9f566fe0899e',
- 'grid_points': {
- 'lat': 62.990967,
- 'lng': -71.553767,
+ year_month: '2020-12',
+ crop_common_name: 'quaerat rerum fugiat',
+ crop_translation_key: 'quaerat rerum fugiat',
+ sale_quant: 182,
+ sale_value: 607,
+ farm_id: '8788ef8b-5c36-11eb-b3aa-9f566fe0899e',
+ grid_points: {
+ lat: 62.990967,
+ lng: -71.553767,
},
},
{
- 'year_month': '2020-12',
- 'crop_common_name': 'ullam molestiae doloribus',
- 'crop_translation_key': 'ullam molestiae doloribus',
- 'sale_quant': 618,
- 'sale_value': 600,
- 'farm_id': '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
- 'grid_points': {
- 'lat': 62.990967,
- 'lng': -71.463767,
+ year_month: '2020-12',
+ crop_common_name: 'ullam molestiae doloribus',
+ crop_translation_key: 'ullam molestiae doloribus',
+ sale_quant: 618,
+ sale_value: 600,
+ farm_id: '87827ed7-5c36-11eb-b3aa-9f566fe0899e',
+ grid_points: {
+ lat: 62.990967,
+ lng: -71.463767,
},
},
{
- 'year_month': '2021-01',
- 'crop_common_name': 'quaerat rerum fugiat',
- 'crop_translation_key': 'quaerat rerum fugiat',
- 'sale_quant': 1258,
- 'sale_value': 770,
- 'farm_id': '8788ef8b-5c36-11eb-b3aa-9f566fe0899e',
- 'grid_points': {
- 'lat': 62.990967,
- 'lng': -71.553767,
+ year_month: '2021-01',
+ crop_common_name: 'quaerat rerum fugiat',
+ crop_translation_key: 'quaerat rerum fugiat',
+ sale_quant: 1258,
+ sale_value: 770,
+ farm_id: '8788ef8b-5c36-11eb-b3aa-9f566fe0899e',
+ grid_points: {
+ lat: 62.990967,
+ lng: -71.553767,
},
},
];
@@ -433,33 +509,33 @@ xdescribe('insights test', () => {
const formatted1 = insightHelpers.formatPricesNearbyData(farm1_id, salesByCropsFarmIdMonth);
const expected1 = {
- 'preview': 65,
- 'data': [
+ preview: 65,
+ data: [
{
'quaerat rerum fugiat': [
{
- 'crop_date': '2020-12',
- 'crop_price': 0.22632794457274827,
- 'network_price': 0.7662213740458015,
+ crop_date: '2020-12',
+ crop_price: 0.22632794457274827,
+ network_price: 0.7662213740458015,
},
{
- 'crop_date': '2021-01',
- 'crop_price': 0,
- 'network_price': 0.6120826709062003,
+ crop_date: '2021-01',
+ crop_price: 0,
+ network_price: 0.6120826709062003,
},
],
},
{
'ullam molestiae doloribus': [
{
- 'crop_date': '2020-12',
- 'crop_price': 0.970873786407767,
- 'network_price': 0.970873786407767,
+ crop_date: '2020-12',
+ crop_price: 0.970873786407767,
+ network_price: 0.970873786407767,
},
],
},
],
- 'amountOfFarms': 1,
+ amountOfFarms: 1,
};
expect(formatted1).toEqual(expected1);
@@ -467,33 +543,33 @@ xdescribe('insights test', () => {
const formatted2 = insightHelpers.formatPricesNearbyData(farm2_id, salesByCropsFarmIdMonth);
const expected2 = {
- 'preview': 268,
- 'data': [
+ preview: 268,
+ data: [
{
'quaerat rerum fugiat': [
{
- 'crop_date': '2020-12',
- 'crop_price': 3.335164835164835,
- 'network_price': 0.7662213740458015,
+ crop_date: '2020-12',
+ crop_price: 3.335164835164835,
+ network_price: 0.7662213740458015,
},
{
- 'crop_date': '2021-01',
- 'crop_price': 0.6120826709062003,
- 'network_price': 0.6120826709062003,
+ crop_date: '2021-01',
+ crop_price: 0.6120826709062003,
+ network_price: 0.6120826709062003,
},
],
},
{
'ullam molestiae doloribus': [
{
- 'crop_date': '2020-12',
- 'crop_price': 0,
- 'network_price': 0.970873786407767,
+ crop_date: '2020-12',
+ crop_price: 0,
+ network_price: 0.970873786407767,
},
],
},
],
- 'amountOfFarms': 1,
+ amountOfFarms: 1,
};
expect(formatted2).toEqual(expected2);
@@ -511,7 +587,16 @@ xdescribe('insights test', () => {
const gridPoint30West = { lat: 62.990967, lng: -72.053767 };
const gridPoint5East = { lat: 62.990967, lng: -71.373767 };
- const gridPoints = [gridPoint0, gridPoint5West, gridPoint10West, gridPoint15West, gridPoint20West, gridPoint25West, gridPoint30West, gridPoint5East];
+ const gridPoints = [
+ gridPoint0,
+ gridPoint5West,
+ gridPoint10West,
+ gridPoint15West,
+ gridPoint20West,
+ gridPoint25West,
+ gridPoint30West,
+ gridPoint5East,
+ ];
const crops = [];
for (let i = 0; i < 3; i++) {
const [crop] = await mocks.cropFactory();
@@ -534,10 +619,13 @@ xdescribe('insights test', () => {
});
const [cropSale] = await mocks.cropSaleFactory({
promisedManagementPlan: [managementPlan],
- promisedSale: mocks.saleFactory({ promisedFarm: [farm] }, {
- ...mocks.fakeSale(),
- sale_date: moment('2020-12-01').format(),
- }),
+ promisedSale: mocks.saleFactory(
+ { promisedFarm: [farm] },
+ {
+ ...mocks.fakeSale(),
+ sale_date: moment('2020-12-01').format(),
+ },
+ ),
});
fields.push(field);
farms.push(farm);
@@ -559,10 +647,13 @@ xdescribe('insights test', () => {
});
const [crop12Sale] = await mocks.cropSaleFactory({
promisedManagementPlan: [managementPlan1],
- promisedSale: mocks.saleFactory({ promisedFarm: [farms[i]] }, {
- ...mocks.fakeSale(),
- sale_date: moment('2020-12-01').format(),
- }),
+ promisedSale: mocks.saleFactory(
+ { promisedFarm: [farms[i]] },
+ {
+ ...mocks.fakeSale(),
+ sale_date: moment('2020-12-01').format(),
+ },
+ ),
});
crop12020Sales.push(crop12Sale);
@@ -578,17 +669,24 @@ xdescribe('insights test', () => {
});
crop2Sales.push(crop2Sale);
}
- const [{
- user_id,
- farm_id,
- }] = await mocks.userFarmFactory({ promisedFarm: [farms[0]] }, { ...mocks.fakeUserFarm(), role_id: 1 });
-
- const { rows: salesOfAFarm2020 } = await insigntController.queryCropSalesNearByStartDateAndFarmId(startdate, farm_id);
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [farms[0]] },
+ { ...mocks.fakeUserFarm(), role_id: 1 },
+ );
+
+ const {
+ rows: salesOfAFarm2020,
+ } = await insigntController.queryCropSalesNearByStartDateAndFarmId(startdate, farm_id);
expect(salesOfAFarm2020.length).toBe(14);
- const { rows: salesOfAFarmCurrentYear } = await insigntController.queryCropSalesNearByStartDateAndFarmId(moment().format('YYYY-MM-DD'), farm_id);
+ const {
+ rows: salesOfAFarmCurrentYear,
+ } = await insigntController.queryCropSalesNearByStartDateAndFarmId(
+ moment().format('YYYY-MM-DD'),
+ farm_id,
+ );
expect(salesOfAFarmCurrentYear.length).toBe(2);
const getQuery = (distance) => ({
- distance: distance,
+ distance,
lat: gridPoint0.lat,
long: gridPoint0.lng,
startdate,
@@ -597,44 +695,93 @@ xdescribe('insights test', () => {
getInsightWithQuery(farm_id, user_id, 'prices/distance', getQuery(5), (err, res) => {
expect(res.status).toBe(200);
const crop0CommonName = crops[0].crop_common_name;
- const crop0TotalPrice = crop0Sales[0].sale_value + crop0Sales[1].sale_value + crop0Sales[7].sale_value;
- const crop0TotalQuantity = crop0Sales[0].quantity_kg + crop0Sales[1].quantity_kg + crop0Sales[7].quantity_kg;
+ const crop0TotalPrice =
+ crop0Sales[0].sale_value + crop0Sales[1].sale_value + crop0Sales[7].sale_value;
+ const crop0TotalQuantity =
+ crop0Sales[0].quantity_kg + crop0Sales[1].quantity_kg + crop0Sales[7].quantity_kg;
const crop1CommonName = crops[1].crop_common_name;
- const crop1TotalPrice = crop1Sales[0].sale_value + crop1Sales[1].sale_value + crop1Sales[2].sale_value + crop1Sales[3].sale_value;
- const crop1TotalQuantity = crop1Sales[0].quantity_kg + crop1Sales[1].quantity_kg + crop1Sales[2].quantity_kg + crop1Sales[3].quantity_kg;
+ const crop1TotalPrice =
+ crop1Sales[0].sale_value +
+ crop1Sales[1].sale_value +
+ crop1Sales[2].sale_value +
+ crop1Sales[3].sale_value;
+ const crop1TotalQuantity =
+ crop1Sales[0].quantity_kg +
+ crop1Sales[1].quantity_kg +
+ crop1Sales[2].quantity_kg +
+ crop1Sales[3].quantity_kg;
const crop12020CommonName = crops[1].crop_common_name;
const crop12020TotalPrice = crop12020Sales[0].sale_value + crop12020Sales[1].sale_value;
- const crop12020TotalQuantity = crop12020Sales[0].quantity_kg + crop12020Sales[1].quantity_kg;
+ const crop12020TotalQuantity =
+ crop12020Sales[0].quantity_kg + crop12020Sales[1].quantity_kg;
const data = res.body.data;
for (const cropSaleRes of data) {
if (cropSaleRes[crop0CommonName]) {
- expect(cropSaleRes[crop0CommonName][0].crop_date).toBe(moment('2020-12-01').format('YYYY-MM'));
- expect(cropSaleRes[crop0CommonName][0].crop_price - crop0Sales[0].sale_value / crop0Sales[0].quantity_kg).toBeLessThan(0.01);
- expect(cropSaleRes[crop0CommonName][0].network_price - crop0TotalPrice / crop0TotalQuantity).toBeLessThan(0.01);
+ expect(cropSaleRes[crop0CommonName][0].crop_date).toBe(
+ moment('2020-12-01').format('YYYY-MM'),
+ );
+ expect(
+ cropSaleRes[crop0CommonName][0].crop_price -
+ crop0Sales[0].sale_value / crop0Sales[0].quantity_kg,
+ ).toBeLessThan(0.01);
+ expect(
+ cropSaleRes[crop0CommonName][0].network_price -
+ crop0TotalPrice / crop0TotalQuantity,
+ ).toBeLessThan(0.01);
} else if (cropSaleRes[crop1CommonName]) {
- expect(cropSaleRes[crop1CommonName][0].crop_date).toBe(moment('2020-12-01').format('YYYY-MM'));
- expect(cropSaleRes[crop1CommonName][0].crop_price - crop12020Sales[0].sale_value / crop12020Sales[0].quantity_kg).toBeLessThan(0.01);
- expect(cropSaleRes[crop1CommonName][0].network_price - crop12020TotalPrice / crop12020TotalQuantity).toBeLessThan(0.01);
+ expect(cropSaleRes[crop1CommonName][0].crop_date).toBe(
+ moment('2020-12-01').format('YYYY-MM'),
+ );
+ expect(
+ cropSaleRes[crop1CommonName][0].crop_price -
+ crop12020Sales[0].sale_value / crop12020Sales[0].quantity_kg,
+ ).toBeLessThan(0.01);
+ expect(
+ cropSaleRes[crop1CommonName][0].network_price -
+ crop12020TotalPrice / crop12020TotalQuantity,
+ ).toBeLessThan(0.01);
expect(cropSaleRes[crop1CommonName][1].crop_date).toBe(moment().format('YYYY-MM'));
- expect(cropSaleRes[crop1CommonName][1].crop_price - (crop1Sales[0].sale_value + crop1Sales[1].sale_value) / (crop1Sales[0].quantity_kg + crop1Sales[1].quantity_kg)).toBeLessThan(0.01);
- expect(cropSaleRes[crop1CommonName][1].network_price - crop1TotalPrice / crop1TotalQuantity).toBeLessThan(0.01);
+ expect(
+ cropSaleRes[crop1CommonName][1].crop_price -
+ (crop1Sales[0].sale_value + crop1Sales[1].sale_value) /
+ (crop1Sales[0].quantity_kg + crop1Sales[1].quantity_kg),
+ ).toBeLessThan(0.01);
+ expect(
+ cropSaleRes[crop1CommonName][1].network_price -
+ crop1TotalPrice / crop1TotalQuantity,
+ ).toBeLessThan(0.01);
}
-
}
getInsightWithQuery(farm_id, user_id, 'prices/distance', getQuery(10), (err, res) => {
expect(res.status).toBe(200);
const crop0CommonName = crops[0].crop_common_name;
- const crop0TotalPrice = crop0Sales[0].sale_value + crop0Sales[1].sale_value + crop0Sales[2].sale_value + crop0Sales[7].sale_value;
- const crop0TotalQuantity = crop0Sales[0].quantity_kg + crop0Sales[1].quantity_kg + crop0Sales[2].quantity_kg + crop0Sales[7].quantity_kg;
+ const crop0TotalPrice =
+ crop0Sales[0].sale_value +
+ crop0Sales[1].sale_value +
+ crop0Sales[2].sale_value +
+ crop0Sales[7].sale_value;
+ const crop0TotalQuantity =
+ crop0Sales[0].quantity_kg +
+ crop0Sales[1].quantity_kg +
+ crop0Sales[2].quantity_kg +
+ crop0Sales[7].quantity_kg;
const data = res.body.data;
for (const cropSaleRes of data) {
if (cropSaleRes[crop0CommonName]) {
- expect(cropSaleRes[crop0CommonName][0].crop_date).toBe(moment('2020-12-01').format('YYYY-MM'));
- expect(cropSaleRes[crop0CommonName][0].crop_price - crop0Sales[0].sale_value / crop0Sales[0].quantity_kg).toBeLessThan(0.01);
- expect(cropSaleRes[crop0CommonName][0].network_price - crop0TotalPrice / crop0TotalQuantity).toBeLessThan(0.01);
+ expect(cropSaleRes[crop0CommonName][0].crop_date).toBe(
+ moment('2020-12-01').format('YYYY-MM'),
+ );
+ expect(
+ cropSaleRes[crop0CommonName][0].crop_price -
+ crop0Sales[0].sale_value / crop0Sales[0].quantity_kg,
+ ).toBeLessThan(0.01);
+ expect(
+ cropSaleRes[crop0CommonName][0].network_price -
+ crop0TotalPrice / crop0TotalQuantity,
+ ).toBeLessThan(0.01);
}
}
done();
@@ -643,7 +790,6 @@ xdescribe('insights test', () => {
});
});
-
test('Should get prices distance if Im on my farm as an owner', async (done) => {
const [{ user_id, farm_id }] = await createUserFarm(1);
const query = mocks.fakePriceInsightForTests();
@@ -702,7 +848,9 @@ xdescribe('insights test', () => {
test('should create a water balance if Im on my farm as an owner', async (done) => {
const [{ user_id, farm_id }] = await createUserFarm(1);
const [field] = await mocks.fieldFactory({ promisedFarm: [{ farm_id }] });
- const [{ crop_id, location_id }] = await mocks.management_planFactory({ promisedField: [field] });
+ const [{ crop_id, location_id }] = await mocks.management_planFactory({
+ promisedField: [field],
+ });
const waterBalance = { ...mocks.fakeWaterBalance(), crop_id, location_id };
postWaterBalance(waterBalance, { farm_id, user_id }, (err, res) => {
expect(res.status).toBe(201);
@@ -713,7 +861,9 @@ xdescribe('insights test', () => {
test('should create a water balance if Im on my farm as a manager', async (done) => {
const [{ user_id, farm_id }] = await createUserFarm(2);
const [field] = await mocks.fieldFactory({ promisedFarm: [{ farm_id }] });
- const [{ crop_id, location_id }] = await mocks.management_planFactory({ promisedField: [field] });
+ const [{ crop_id, location_id }] = await mocks.management_planFactory({
+ promisedField: [field],
+ });
const waterBalance = { ...mocks.fakeWaterBalance(), crop_id, location_id };
postWaterBalance(waterBalance, { farm_id, user_id }, (err, res) => {
expect(res.status).toBe(201);
@@ -724,15 +874,15 @@ xdescribe('insights test', () => {
test('should fail to create a water balance if Im on my farm as a Worker', async (done) => {
const [{ user_id, farm_id }] = await createUserFarm(3);
const [field] = await mocks.fieldFactory({ promisedFarm: [{ farm_id }] });
- const [{ crop_id, location_id }] = await mocks.management_planFactory({ promisedField: [field] });
+ const [{ crop_id, location_id }] = await mocks.management_planFactory({
+ promisedField: [field],
+ });
const waterBalance = { ...mocks.fakeWaterBalance(), crop_id, location_id };
postWaterBalance(waterBalance, { farm_id, user_id }, (err, res) => {
expect(res.status).toBe(403);
done();
});
});
-
-
});
});
@@ -787,7 +937,6 @@ xdescribe('insights test', () => {
done();
});
});
-
});
});
@@ -870,8 +1019,6 @@ xdescribe('insights test', () => {
done();
});
});
-
-
});
describe('DELETE', () => {
@@ -903,32 +1050,44 @@ xdescribe('insights test', () => {
});
});
});
-
});
function createUserFarm(role) {
- return mocks.userFarmFactory({
- promisedFarm: mocks.farmFactory(),
- promisedUser: mocks.usersFactory(),
- }, { role_id: role, status: 'Active' });
+ return mocks.userFarmFactory(
+ {
+ promisedFarm: mocks.farmFactory(),
+ promisedUser: mocks.usersFactory(),
+ },
+ { role_id: role, status: 'Active' },
+ );
}
function getInsight(farmId, userId, route, callback) {
- chai.request(server).get(`/insight/${route}/${farmId}`)
+ chai
+ .request(server)
+ .get(`/insight/${route}/${farmId}`)
.set('farm_id', farmId)
.set('user_id', userId)
.end(callback);
}
function getInsightWithQuery(farmId, userId, route, query, callback) {
- chai.request(server).get(`/insight/${route}/${farmId}?distance=${query.distance}&lat=${query.lat}&long=${query.long}&startdate=${query.startdate || '2020-1-1'}`)
+ chai
+ .request(server)
+ .get(
+ `/insight/${route}/${farmId}?distance=${query.distance}&lat=${query.lat}&long=${
+ query.long
+ }&startdate=${query.startdate || '2020-1-1'}`,
+ )
.set('farm_id', farmId)
.set('user_id', userId)
.end(callback);
}
function postWaterBalance(data, { farm_id, user_id }, callback) {
- chai.request(server).post(`/insight/waterbalance`)
+ chai
+ .request(server)
+ .post(`/insight/waterbalance`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
@@ -936,7 +1095,9 @@ function postWaterBalance(data, { farm_id, user_id }, callback) {
}
function postNitrogenSchedule(data, { farm_id, user_id }, callback) {
- chai.request(server).post('/insight/nitrogenbalance/schedule')
+ chai
+ .request(server)
+ .post('/insight/nitrogenbalance/schedule')
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
@@ -944,7 +1105,9 @@ function postNitrogenSchedule(data, { farm_id, user_id }, callback) {
}
function postWaterBalanceSchedule({ farm_id, user_id }, callback) {
- chai.request(server).post(`/insight/waterbalance/schedule`)
+ chai
+ .request(server)
+ .post(`/insight/waterbalance/schedule`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send({ farm_id })
@@ -952,7 +1115,9 @@ function postWaterBalanceSchedule({ farm_id, user_id }, callback) {
}
function deleteNitrogenSchedule({ farm_id, user_id }, nitrogenId, callback) {
- chai.request(server).delete(`/insight/nitrogenbalance/schedule/${nitrogenId}`)
+ chai
+ .request(server)
+ .delete(`/insight/nitrogenbalance/schedule/${nitrogenId}`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.end(callback);
diff --git a/packages/api/tests/jwt.test.js b/packages/api/tests/jwt.test.js
index 77e3405168..e31f5bb984 100644
--- a/packages/api/tests/jwt.test.js
+++ b/packages/api/tests/jwt.test.js
@@ -19,11 +19,11 @@ chai.use(chaiHttp);
const jsonwebtoken = require('jsonwebtoken');
const { sign } = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
-let faker = require('faker');
+const { faker } = require('@faker-js/faker');
const server = require('./../src/server');
const knex = require('../src/util/knex');
const { tableCleanup } = require('./testEnvironment');
-let { usersFactory, farmFactory, userFarmFactory } = require('./mock.factories');
+const { usersFactory, farmFactory, userFarmFactory } = require('./mock.factories');
const mocks = require('./mock.factories');
const { createToken, tokenType } = require('../src/util/jwt');
const checkGoogleJwt = require('../src/middleware/acl/checkGoogleJwt.js');
@@ -44,7 +44,9 @@ describe('JWT Tests', () => {
async function deleteFarmRequest(data, user_id, callback) {
const token = await getAuthorizationHeader(user_id);
- chai.request(server).delete(`/farm/${data.farm_id}`)
+ chai
+ .request(server)
+ .delete(`/farm/${data.farm_id}`)
.set('farm_id', data.farm_id)
.set('user_id', user_id)
.set('Authorization', token)
@@ -52,7 +54,9 @@ describe('JWT Tests', () => {
}
function deleteFarmRequestWithoutToken(data, user, callback) {
- chai.request(server).delete(`/farm/${data.farm_id}`)
+ chai
+ .request(server)
+ .delete(`/farm/${data.farm_id}`)
.set('farm_id', data.farm_id)
.set('user_id', user)
.set('Authorization', 'token')
@@ -60,35 +64,44 @@ describe('JWT Tests', () => {
}
function postResetPasswordRequest(email, callback) {
- chai.request(server).post(`/password_reset/send_email`)
- .send({ email })
- .end(callback);
+ chai.request(server).post(`/password_reset/send_email`).send({ email }).end(callback);
}
function getValidateRequest(resetPasswordToken, user_id, callback) {
- chai.request(server).get(`/password_reset/validate`)
+ chai
+ .request(server)
+ .get(`/password_reset/validate`)
.set('user_id', user_id)
.set('Authorization', `Bearer ${resetPasswordToken}`)
.end(callback);
}
function putPasswordRequest(resetPasswordToken, user, callback) {
- chai.request(server).put(`/password_reset`)
+ chai
+ .request(server)
+ .put(`/password_reset`)
.set('user_id', user.user_id)
.set('Authorization', `Bearer ${resetPasswordToken}`)
.send(user)
.end(callback);
}
- async function insertPasswordRow({ password = 'password', reset_token_version, created_at = new Date(), user_id }) {
+ async function insertPasswordRow({
+ password = 'password',
+ reset_token_version,
+ created_at = new Date(),
+ user_id,
+ }) {
const salt = await bcrypt.genSalt(10);
const password_hash = await bcrypt.hash(password, salt);
- const rows = await knex('password').insert({
- password_hash,
- reset_token_version,
- created_at,
- user_id,
- }).returning('*');
+ const rows = await knex('password')
+ .insert({
+ password_hash,
+ reset_token_version,
+ created_at,
+ user_id,
+ })
+ .returning('*');
return rows[0];
}
@@ -99,22 +112,22 @@ describe('JWT Tests', () => {
function validate(expected, res, status, received = undefined) {
expect(res.status).toBe(status);
- received = received ? received : (res.body[0] || res.body);
+ received = received ? received : res.body[0] || res.body;
expect(Object.keys(received).length).toBeGreaterThan(0);
for (const key of Object.keys(received)) {
- if (expected[key] && typeof expected[key] === 'string' || typeof expected[key] === 'number') {
+ if (
+ (expected[key] && typeof expected[key] === 'string') ||
+ typeof expected[key] === 'number'
+ ) {
expect([key, received[key]]).toStrictEqual([key, expected[key]]);
}
}
}
-;
-
-
beforeEach(async () => {
- let { createToken } = require('../src/util/jwt');
+ const { createToken } = require('../src/util/jwt');
createToken.mockImplementation(async (type, user) => {
- let localAccessToken = sign(user, tokenType[type], {
+ const localAccessToken = sign(user, tokenType[type], {
expiresIn: '7d',
algorithm: 'HS256',
});
@@ -133,7 +146,10 @@ describe('JWT Tests', () => {
describe('Access jwt test', () => {
test('should succeed on deleting a farm with valid token', async (done) => {
const [farm] = await farmFactory();
- await userFarmFactory({ promisedUser: [newUser], promisedFarm: [farm] }, { role_id: 1, status: 'Active' });
+ await userFarmFactory(
+ { promisedUser: [newUser], promisedFarm: [farm] },
+ { role_id: 1, status: 'Active' },
+ );
deleteFarmRequest(farm, newUser.user_id, async (err, res) => {
expect(res.status).toBe(200);
const [farmQuery] = await knex.select().from('farm').where({ farm_id: farm.farm_id });
@@ -144,7 +160,10 @@ describe('JWT Tests', () => {
test('should fail on deleting a farm without valid token', async (done) => {
const [farm] = await farmFactory();
- await userFarmFactory({ promisedUser: [newUser], promisedFarm: [farm] }, { role_id: 1, status: 'Active' });
+ await userFarmFactory(
+ { promisedUser: [newUser], promisedFarm: [farm] },
+ { role_id: 1, status: 'Active' },
+ );
deleteFarmRequestWithoutToken(farm, newUser.user_id, async (err, res) => {
expect(res.status).toBe(401);
const [farmQuery] = await knex.select().from('farm').where({ farm_id: farm.farm_id });
@@ -158,12 +177,12 @@ describe('JWT Tests', () => {
let resetPasswordToken;
beforeEach(async (done) => {
- let { createToken } = require('../src/util/jwt');
+ const { createToken } = require('../src/util/jwt');
createToken.mockImplementation(async (type, user) => {
if (user.reset_token_version === undefined) {
user.reset_token_version = 4;
}
- let localResetPasswordToken = sign(user, tokenType[type], {
+ const localResetPasswordToken = sign(user, tokenType[type], {
expiresIn: '1d',
algorithm: 'HS256',
});
@@ -188,7 +207,9 @@ describe('JWT Tests', () => {
expect(res.status).toBe(200);
const user = jsonwebtoken.verify(resetPasswordToken, process.env.JWT_RESET_SECRET);
expect(user.reset_token_version).toBe(0);
- const { reset_token_version, created_at } = await knex('password').where({ user_id: newUser.user_id }).first();
+ const { reset_token_version, created_at } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
expect(reset_token_version).toBe(1);
expect(created_at.getTime()).toBeGreaterThanOrEqual(oldRow.created_at.getTime());
getValidateRequest(resetPasswordToken, newUser.user_id, async (err, res) => {
@@ -205,7 +226,9 @@ describe('JWT Tests', () => {
expect(res.status).toBe(200);
const user = jsonwebtoken.verify(resetPasswordToken, process.env.JWT_RESET_SECRET);
expect(user.reset_token_version).toBe(1);
- const { reset_token_version, created_at } = await knex('password').where({ user_id: newUser.user_id }).first();
+ const { reset_token_version, created_at } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
expect(reset_token_version).toBe(2);
expect(created_at.getTime()).toBe(oldRow.created_at.getTime());
getValidateRequest(resetPasswordToken, newUser.user_id, async (err, res) => {
@@ -222,7 +245,9 @@ describe('JWT Tests', () => {
expect(res.status).toBe(200);
const user = jsonwebtoken.verify(resetPasswordToken, process.env.JWT_RESET_SECRET);
expect(user.reset_token_version).toBe(2);
- const { reset_token_version, created_at } = await knex('password').where({ user_id: newUser.user_id }).first();
+ const { reset_token_version, created_at } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
expect(reset_token_version).toBe(3);
expect(created_at.getTime()).toBe(oldRow.created_at.getTime());
getValidateRequest(resetPasswordToken, newUser.user_id, async (err, res) => {
@@ -241,12 +266,14 @@ describe('JWT Tests', () => {
reset_token_version: 0,
created_at: new Date().getTime(),
};
- let localResetPasswordToken = await createToken('passwordReset', tokenPayload);
+ const localResetPasswordToken = await createToken('passwordReset', tokenPayload);
resetPasswordToken = undefined;
postResetPasswordRequest(newUser.email, async (err, res) => {
expect(res.status).toBe(400);
expect(resetPasswordToken).toBe(undefined);
- const { reset_token_version, created_at } = await knex('password').where({ user_id: newUser.user_id }).first();
+ const { reset_token_version, created_at } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
expect(reset_token_version).toBe(oldRow.reset_token_version);
expect(created_at.getTime()).toBe(oldRow.created_at.getTime());
getValidateRequest(localResetPasswordToken, newUser.user_id, async (err, res) => {
@@ -260,12 +287,18 @@ describe('JWT Tests', () => {
test('Should reset reset_token_version and created_at when created_at is one day before current date', async (done) => {
const oneDay = 1000 * 3600 * 24;
const oldDate = new Date(new Date().getTime() - oneDay - 1);
- const oldRow = await insertPasswordRow({ reset_token_version: 1, user_id: newUser.user_id, created_at: oldDate });
+ const oldRow = await insertPasswordRow({
+ reset_token_version: 1,
+ user_id: newUser.user_id,
+ created_at: oldDate,
+ });
postResetPasswordRequest(newUser.email, async (err, res) => {
expect(res.status).toBe(200);
const user = jsonwebtoken.verify(resetPasswordToken, process.env.JWT_RESET_SECRET);
expect(user.reset_token_version).toBe(0);
- const { reset_token_version, created_at } = await knex('password').where({ user_id: newUser.user_id }).first();
+ const { reset_token_version, created_at } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
expect(reset_token_version).toBe(1);
expect(created_at.getTime()).toBeGreaterThan(oldRow.created_at.getTime());
getValidateRequest(resetPasswordToken, newUser.user_id, async (err, res) => {
@@ -276,40 +309,45 @@ describe('JWT Tests', () => {
});
});
-
test('Should reset reset_token_version and created_at when reset token is used', async (done) => {
const newPassword = 'newPassword';
const oldRow = await insertPasswordRow({ reset_token_version: 2, user_id: newUser.user_id });
postResetPasswordRequest(newUser.email, async (err, res) => {
const verified = jsonwebtoken.verify(resetPasswordToken, process.env.JWT_RESET_SECRET);
expect(verified.user_id).toBe(newUser.user_id);
- putPasswordRequest(resetPasswordToken, {
- password: newPassword,
- user_id: newUser.user_id,
- }, async (err, res) => {
- expect(res.status).toBe(200);
- const {
- reset_token_version,
- created_at,
- password_hash,
- } = await knex('password').where({ user_id: newUser.user_id }).first();
- const isMatch = await bcrypt.compare(newPassword, password_hash);
- expect(isMatch).toBeTruthy();
- expect(reset_token_version).toBe(0);
- expect(created_at.getTime()).toBeGreaterThan(oldRow.created_at.getTime());
- putPasswordRequest(resetPasswordToken, {
+ putPasswordRequest(
+ resetPasswordToken,
+ {
password: newPassword,
user_id: newUser.user_id,
- }, async (err, res) => {
- expect(res.status).toBe(401);
- done();
- });
- });
+ },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const { reset_token_version, created_at, password_hash } = await knex('password')
+ .where({ user_id: newUser.user_id })
+ .first();
+ const isMatch = await bcrypt.compare(newPassword, password_hash);
+ expect(isMatch).toBeTruthy();
+ expect(reset_token_version).toBe(0);
+ expect(created_at.getTime()).toBeGreaterThan(oldRow.created_at.getTime());
+ putPasswordRequest(
+ resetPasswordToken,
+ {
+ password: newPassword,
+ user_id: newUser.user_id,
+ },
+ async (err, res) => {
+ expect(res.status).toBe(401);
+ done();
+ },
+ );
+ },
+ );
});
});
test('Should reject when an invited user tries to get reset password token', async (done) => {
- const [invitedUser] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 2});
+ const [invitedUser] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
postResetPasswordRequest(invitedUser.email, async (err, res) => {
expect(res.status).toBe(400);
done();
@@ -317,7 +355,11 @@ describe('JWT Tests', () => {
});
test('Should reject when a pseudo user tries to get reset password token', async (done) => {
- const [pseudoUser] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 1, email: `${faker.random.uuid()}@pseudo.com`});
+ const [pseudoUser] = await mocks.usersFactory({
+ ...mocks.fakeUser(),
+ status_id: 1,
+ email: `${faker.datatype.uuid()}@pseudo.com`,
+ });
postResetPasswordRequest(pseudoUser.email, async (err, res) => {
expect(res.status).toBe(400);
done();
@@ -325,13 +367,12 @@ describe('JWT Tests', () => {
});
test('Should reject when an auth0 legacy user tries to get reset password token', async (done) => {
- const [invitedUser] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 3});
+ const [invitedUser] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 3 });
postResetPasswordRequest(newUser.email, async (err, res) => {
expect(res.status).toBe(400);
done();
});
});
-
});
describe('Accept invitation jwt test', () => {
@@ -340,7 +381,9 @@ describe('JWT Tests', () => {
let googleUser;
function postAcceptInvitationWithPasswordRequest(invitationToken, callback) {
- chai.request(server).post(`/user/accept_invitation`)
+ chai
+ .request(server)
+ .post(`/user/accept_invitation`)
.set('Authorization', `Bearer ${invitationToken}`)
.send(reqBody)
.end(callback);
@@ -348,22 +391,23 @@ describe('JWT Tests', () => {
function putAcceptInvitationWithGoogleAccountRequest(invitationToken, callback) {
delete reqBody.password;
- chai.request(server).put(`/user/accept_invitation`)
+ chai
+ .request(server)
+ .put(`/user/accept_invitation`)
.send({ ...reqBody, invite_token: invitationToken })
.end(callback);
}
function getRequest({ email = user.email }, callback) {
- chai.request(server)
- .get(`/login/user/${email}`)
- .set('email', email)
- .end(callback);
+ chai.request(server).get(`/login/user/${email}`).set('email', email).end(callback);
}
function fakeGoogleTokenContent() {
const user = mocks.fakeUser();
return {
- sub: faker.datatype.number({ min: 100000000000000000000, max: 199999999999999999999 }).toString(),
+ sub: faker.datatype
+ .number({ min: 100000000000000000000, max: 199999999999999999999 })
+ .toString(),
email: faker.internet.email(user.first_name, user.last_name, 'gmail.com').toLowerCase(),
};
}
@@ -371,15 +415,19 @@ describe('JWT Tests', () => {
function fakeReqBody() {
const { first_name, last_name, gender, birth_year, language_preference } = mocks.fakeUser();
return {
- first_name, last_name, gender, birth_year, language_preference,
+ first_name,
+ last_name,
+ gender,
+ birth_year,
+ language_preference,
password: faker.internet.password(),
};
}
beforeEach(async (done) => {
- let { createToken } = require('../src/util/jwt');
+ const { createToken } = require('../src/util/jwt');
createToken.mockImplementation(async (type, user) => {
- let localInvitationToken = sign(user, tokenType[type], {
+ const localInvitationToken = sign(user, tokenType[type], {
expiresIn: '7d',
algorithm: 'HS256',
});
@@ -405,10 +453,13 @@ describe('JWT Tests', () => {
test('Should create password and spotlight when user status is invited', async (done) => {
const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
const { user_id, farm_id } = userFarm;
getRequest(user, async (err, res) => {
const verified = jsonwebtoken.verify(invitationToken, tokenType.invite);
@@ -416,9 +467,7 @@ describe('JWT Tests', () => {
postAcceptInvitationWithPasswordRequest(invitationToken, async (err, res) => {
const [resUser] = await userModel.query().where({ user_id: user.user_id });
validate({ ...user, ...reqBody, status_id: 1 }, res, 201, resUser);
- const {
- password_hash,
- } = await knex('password').where({ user_id: user.user_id }).first();
+ const { password_hash } = await knex('password').where({ user_id: user.user_id }).first();
const isMatch = await bcrypt.compare(reqBody.password, password_hash);
expect(isMatch).toBeTruthy();
const [resUserFarm] = await knex('userFarm').where({ user_id, farm_id });
@@ -435,10 +484,13 @@ describe('JWT Tests', () => {
test('User should accept invitation when birth year is undefined', async (done) => {
const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
getRequest(user, async (err, res) => {
delete reqBody.birth_year;
postAcceptInvitationWithPasswordRequest(invitationToken, async (err, res) => {
@@ -451,14 +503,17 @@ describe('JWT Tests', () => {
test('Should return 401 when userFarm status Inactive', async (done) => {
const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
getRequest(user, async (err, res) => {
- const {farm_id, user_id} = userFarm;
+ const { farm_id, user_id } = userFarm;
delete reqBody.birth_year;
- await userFarmModel.query().findById([user_id,farm_id]).patch({status: 'Inactive'});
+ await userFarmModel.query().findById([user_id, farm_id]).patch({ status: 'Inactive' });
postAcceptInvitationWithPasswordRequest(invitationToken, async (err, res) => {
expect(res.status).toBe(401);
done();
@@ -468,14 +523,17 @@ describe('JWT Tests', () => {
test('Should return 401 when userFarm status Active', async (done) => {
const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
getRequest(user, async (err, res) => {
- const {farm_id, user_id} = userFarm;
+ const { farm_id, user_id } = userFarm;
delete reqBody.birth_year;
- await userFarmModel.query().findById([user_id,farm_id]).patch({status: 'Active'});
+ await userFarmModel.query().findById([user_id, farm_id]).patch({ status: 'Active' });
postAcceptInvitationWithPasswordRequest(invitationToken, async (err, res) => {
expect(res.status).toBe(401);
done();
@@ -484,34 +542,59 @@ describe('JWT Tests', () => {
});
test('Should modify user_id and insert spotlight when login with google and user status is invited', async (done) => {
- const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2, email: googleUser.email });
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
- const [userFarm1] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
+ const [user] = await mocks.usersFactory({
+ ...mocks.fakeUser(),
+ status_id: 2,
+ email: googleUser.email,
});
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
+ const [userFarm1] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
const { user_id, farm_id } = userFarm;
getRequest(user, async (err, res) => {
const verified = await jsonwebtoken.verify(invitationToken, tokenType.invite);
expect(verified.user_id).toBe(user.user_id);
- const getUserFarmStatus = (farm_id) => verified.farm_id === farm_id ? 'Active': 'Invited';
+ const getUserFarmStatus = (farm_id) =>
+ verified.farm_id === farm_id ? 'Active' : 'Invited';
putAcceptInvitationWithGoogleAccountRequest(invitationToken, async (err, res) => {
const oldUserRows = await userModel.query().where({ user_id: user.user_id });
expect(oldUserRows.length).toBe(0);
const [resUser] = await userModel.query().where({ user_id: googleUser.sub });
- validate({ ...user, ...reqBody, email: googleUser.email, user_id: googleUser.user_id, status_id: 1 }, res, 200, resUser);
- const oldUserFarms = await knex('userFarm').where({user_id});
+ validate(
+ {
+ ...user,
+ ...reqBody,
+ email: googleUser.email,
+ user_id: googleUser.user_id,
+ status_id: 1,
+ },
+ res,
+ 200,
+ resUser,
+ );
+ const oldUserFarms = await knex('userFarm').where({ user_id });
expect(oldUserFarms.length).toBe(0);
- const [resUserFarm] = await knex('userFarm').where({user_id: googleUser.sub, farm_id});
+ const [resUserFarm] = await knex('userFarm').where({ user_id: googleUser.sub, farm_id });
expect(resUserFarm.status).toBe(getUserFarmStatus(farm_id));
- const [resUserFarm1] = await knex('userFarm').where({user_id: googleUser.sub, farm_id: userFarm1.farm_id});
+ const [resUserFarm1] = await knex('userFarm').where({
+ user_id: googleUser.sub,
+ farm_id: userFarm1.farm_id,
+ });
expect(resUserFarm1.status).toBe(getUserFarmStatus(userFarm1.farm_id));
- const emailTokens = await knex('emailToken').where({user_id: googleUser.sub});
+ const emailTokens = await knex('emailToken').where({ user_id: googleUser.sub });
expect(emailTokens.length).toBe(2);
- const oldEmailTokens = await knex('emailToken').where({user_id});
+ const oldEmailTokens = await knex('emailToken').where({ user_id });
expect(oldEmailTokens.length).toBe(0);
expect(resUserFarm1.status).toBe(getUserFarmStatus(userFarm1.farm_id));
@@ -524,32 +607,55 @@ describe('JWT Tests', () => {
});
test('Should modify user_id when pseudo user accept invitation with google account', async (done) => {
- const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2, email: googleUser.email});
- const [userFarm] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
- });
- const [userFarm1] = await mocks.userFarmFactory({ promisedUser: [user] }, {
- ...mocks.fakeUserFarm(),
- status: 'Invited',
+ const [user] = await mocks.usersFactory({
+ ...mocks.fakeUser(),
+ status_id: 2,
+ email: googleUser.email,
});
- const [shift] = await mocks.shiftFactory({promisedUserFarm: [userFarm]});
- const [shift1] = await mocks.shiftFactory({promisedUserFarm: [userFarm1]});
- await knex('shift').where({created_by_user_id: user.user_id}).update({created_by_user_id: newUser.user_id});
- const {user_id, farm_id} = userFarm1;
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
+ const [userFarm1] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ {
+ ...mocks.fakeUserFarm(),
+ status: 'Invited',
+ },
+ );
+ const [shift] = await mocks.shiftFactory({ promisedUserFarm: [userFarm] });
+ const [shift1] = await mocks.shiftFactory({ promisedUserFarm: [userFarm1] });
+ await knex('shift')
+ .where({ created_by_user_id: user.user_id })
+ .update({ created_by_user_id: newUser.user_id });
+ const { user_id, farm_id } = userFarm1;
getRequest(user, async (err, res) => {
const verified = await jsonwebtoken.verify(invitationToken, tokenType.invite);
expect(verified.user_id).toBe(user.user_id);
- const userFarm1= await userFarmModel.query().where({user_id, farm_id}).first();
+ const userFarm1 = await userFarmModel.query().where({ user_id, farm_id }).first();
expect(userFarm1.status).toBe('Invited');
putAcceptInvitationWithGoogleAccountRequest(invitationToken, async (err, res) => {
const oldUserRows = await userModel.query().where({ user_id: user.user_id });
expect(oldUserRows.length).toBe(0);
const [resUser] = await userModel.query().where({ user_id: googleUser.sub });
- validate({ ...user, ...reqBody, email: googleUser.email, user_id: googleUser.user_id, status_id: 1 }, res, 200, resUser);
- const oldShift = await knex('shift').where({user_id});
+ validate(
+ {
+ ...user,
+ ...reqBody,
+ email: googleUser.email,
+ user_id: googleUser.user_id,
+ status_id: 1,
+ },
+ res,
+ 200,
+ resUser,
+ );
+ const oldShift = await knex('shift').where({ user_id });
expect(oldShift.length).toBe(0);
- const resShifts = await knex('shift').where({user_id: googleUser.sub});
+ const resShifts = await knex('shift').where({ user_id: googleUser.sub });
expect(resShifts.length).toBe(2);
putAcceptInvitationWithGoogleAccountRequest(invitationToken, async (err, res) => {
@@ -559,8 +665,5 @@ describe('JWT Tests', () => {
});
});
});
-
});
});
-
-
diff --git a/packages/api/tests/location.test.js b/packages/api/tests/location.test.js
index b3eb8ea427..4d8348eabe 100644
--- a/packages/api/tests/location.test.js
+++ b/packages/api/tests/location.test.js
@@ -8,7 +8,7 @@ jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
const mocks = require('./mock.factories');
const { figureMapping, promiseMapper } = require('./../src/middleware/validation/location');
-const faker = require('faker');
+const { faker } = require('@faker-js/faker');
const locations = {
BARN: 'barn',
@@ -94,6 +94,7 @@ describe('Location tests', () => {
.send(data)
.end(callback);
}
+
function postLocation(data, asset, { user_id, farm_id }, callback) {
chai
.request(server)
@@ -146,7 +147,7 @@ describe('Location tests', () => {
describe('GET /location by farm', () => {
let user, farm;
beforeEach(async () => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
@@ -209,8 +210,73 @@ describe('Location tests', () => {
});
describe('DELETE /location ', () => {
+ const createTask = async (user_id, options) => {
+ const fakeTask = mocks.fakeTask({
+ owner_user_id: user_id,
+ assignee_user_id: user_id,
+ due_date: faker.date.future(),
+ ...options,
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ },
+ fakeTask,
+ );
+
+ return task_id;
+ };
+ const createManagementTask = async (user_id, planting_management_plan_id, options) => {
+ const newTaskId = await createTask(user_id, options);
+ await mocks.management_tasksFactory({
+ promisedTask: [{ task_id: newTaskId }],
+ promisedPlantingManagementPlan: [{ planting_management_plan_id }],
+ });
+ };
+
+ const createLocationTask = async (user_id, location_id, options) => {
+ const newTaskId = await createTask(user_id, options);
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id: newTaskId }],
+ promisedField: [{ location_id }],
+ });
+ };
+
+ const createTransplantTask = async (
+ user_id,
+ farm_id,
+ location_id,
+ transplantTaskManagementPlanId,
+ options,
+ ) => {
+ const [transplantMgtPlan] = await knex('planting_management_plan')
+ .insert({
+ ...mocks.fakePlantingManagementPlan({
+ location_id,
+ management_plan_id: transplantTaskManagementPlanId,
+ }),
+ })
+ .returning('*');
+ const task_id = await createTask(user_id, options);
+ await mocks.transplant_taskFactory(
+ { promisedTask: [{ task_id }] },
+ { planting_management_plan_id: transplantMgtPlan.planting_management_plan_id },
+ );
+ const { management_plan_id } = transplantMgtPlan;
+ return { management_plan_id };
+ };
+
+ const createPlantTask = async (user_id, planting_management_plan_id, options) => {
+ const task_id = await createTask(user_id, options);
+ await mocks.plant_taskFactory(
+ { promisedTask: [{ task_id }] },
+ { planting_management_plan_id },
+ );
+ };
+
test('should delete field', async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
@@ -219,85 +285,238 @@ describe('Location tests', () => {
expect(res.status).toBe(200);
const location = await knex('location').where({ location_id: field1.location_id }).first();
const location2 = await knex('location').where({ location_id: field2.location_id }).first();
- console.log(location);
expect(location.deleted).toBeTruthy();
expect(location2.deleted).toBeFalsy();
done();
});
});
- test('Delete should return 400 when field is referenced by managementPlan', async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ test('Delete should return 400 when field is referenced by managementPlan (incomplete plant task)', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
- await mocks.crop_management_planFactory({ promisedField: [field1] });
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
+ promisedField: [field1],
+ });
+ await createPlantTask(user_id, planting_management_plan_id);
+
deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
expect(res.status).toBe(400);
done();
});
});
- test('should delete field when field is referenced by expired managementPlans', async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ test('Delete should return 400 when field is referenced by managementPlan (wild crop location)', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
- const expiredManagementPlan = mocks.fakeManagementPlan();
- expiredManagementPlan.complete_date = faker.date.past();
- await mocks.crop_management_planFactory({
- promisedManagementPlan: mocks.management_planFactory({}, expiredManagementPlan),
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
promisedField: [field1],
});
+
+ deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('Delete should return 400 when field is referenced by managementPlan (completed transplant task)', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field2],
+ promisedField: [field2],
+ });
+ await createPlantTask(user_id, planting_management_plan_id, { complete_date: '2022-02-22' });
+ await createTransplantTask(user_id, farm_id, field2.location_id, management_plan_id, {
+ complete_date: '2022-02-23',
+ });
+ await createTransplantTask(user_id, farm_id, field2.location_id, management_plan_id);
+
+ await createTransplantTask(user_id, farm_id, field1.location_id, management_plan_id, {
+ complete_date: '2022-02-24',
+ });
+
+ deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('should delete field when crop is transplanted to different field', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
+ promisedField: [field1],
+ });
+ await createPlantTask(user_id, planting_management_plan_id, { complete_date: '2022-02-22' });
+ await createTransplantTask(user_id, farm_id, field1.location_id, management_plan_id, {
+ complete_date: '2022-02-23',
+ });
+
+ await createTransplantTask(user_id, farm_id, field2.location_id, management_plan_id, {
+ complete_date: '2022-02-24',
+ });
+
deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
expect(res.status).toBe(200);
done();
});
});
- test('Delete should return 400 when field is referenced by task', async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ test('should delete field when all tasks are completed or abandoned and crop is transplanted to different field', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
- await mocks.location_tasksFactory({
- promisedActivityLog: mocks.taskFactory({ user_id }),
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
promisedField: [field1],
});
+ await createPlantTask(user_id, planting_management_plan_id, { complete_date: '2022-02-22' });
+ await createTransplantTask(user_id, farm_id, field1.location_id, management_plan_id, {
+ complete_date: '2022-02-23',
+ });
+
+ await createTransplantTask(user_id, farm_id, field2.location_id, management_plan_id, {
+ complete_date: '2022-02-24',
+ });
+
+ await createManagementTask(user_id, planting_management_plan_id, {
+ abandon_date: '2022-02-22',
+ });
+ await createLocationTask(user_id, field1.location_id, { complete_date: '2022-02-22' });
+
+ deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ done();
+ });
+ });
+
+ test('should return 400 when field is referenced by incomplete plant task', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
+ promisedField: [field1],
+ });
+ await createPlantTask(user_id, planting_management_plan_id);
+
deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
expect(res.status).toBe(400);
done();
});
});
- test('should return 400 when expired managementPlan is referenced in task', async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ test('should return 400 when field is referenced by incomplete transplant task', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
- const fakeManagementPlan = mocks.fakeManagementPlan();
- const [managementPlan1] = await mocks.crop_management_planFactory({
- promisedManagementPlan: mocks.management_planFactory(
- {},
- {
- ...fakeManagementPlan,
- },
- ),
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field2],
+ promisedField: [field2],
+ });
+ await createPlantTask(user_id, planting_management_plan_id);
+ await createTransplantTask(user_id, farm_id, field1.location_id, management_plan_id);
+
+ deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('should return 400 when field is referenced by incomplete location task', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field2],
+ promisedField: [field2],
+ });
+ await createPlantTask(user_id, planting_management_plan_id, { complete_date: '2022-02-23' });
+
+ await createLocationTask(user_id, field1.location_id);
+
+ deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('should return 400 when field is referenced by incomplete management task', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ {},
+ { status: 'Active', role_id: 1 },
+ );
+ const [[field1], [field2]] = await appendFieldToFarm(farm_id, 2);
+
+ const [
+ { planting_management_plan_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [field1],
promisedField: [field1],
});
- const taskData = mocks.fakeTask();
- const today = new Date();
- today.setDate(today.getDate() + 1);
- taskData.due_date = today;
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, taskData);
- await mocks.management_tasksFactory({
- promisedManagementPlan: [managementPlan1],
- promisedTask: [{ task_id: task.task_id }],
+ await createPlantTask(user_id, planting_management_plan_id, { complete_date: '2022-02-22' });
+ await createTransplantTask(user_id, farm_id, field2.location_id, management_plan_id, {
+ complete_date: '2022-02-23',
});
+
+ await createManagementTask(user_id, planting_management_plan_id);
+
deleteLocation({ user_id, farm_id }, field1.location_id, async (err, res) => {
expect(res.status).toBe(400);
done();
@@ -309,7 +528,7 @@ describe('Location tests', () => {
let user, farm;
beforeEach(async () => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
@@ -338,7 +557,7 @@ describe('Location tests', () => {
describe('Authorization', () => {
Object.keys(figureMapping).map((asset) => {
test(`should allow owner to create a ${asset}`, async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
@@ -353,7 +572,7 @@ describe('Location tests', () => {
});
test(`should allow manager to create a ${asset}`, async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 2 },
);
@@ -368,7 +587,7 @@ describe('Location tests', () => {
});
test(`should allow EO to create a ${asset}`, async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 5 },
);
@@ -383,7 +602,7 @@ describe('Location tests', () => {
});
test(`should NOT allow worker to create a ${asset}`, async (done) => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 3 },
);
@@ -586,7 +805,7 @@ describe('Location tests', () => {
let user, farm;
beforeEach(async () => {
- let [{ user_id, farm_id }] = await mocks.userFarmFactory(
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory(
{},
{ status: 'Active', role_id: 1 },
);
@@ -621,7 +840,7 @@ describe('Location tests', () => {
...locationData,
name: 'Test Name323',
figure: {
- location_id: location_id,
+ location_id,
figure_id: figure[0].figure_id,
[typeOfFigure]: {
...newFigureData,
@@ -667,7 +886,7 @@ describe('Location tests', () => {
name: 'Test Name323',
figure: {
type: locations.FIELD,
- location_id: location_id,
+ location_id,
figure_id: area[0].figure_id,
area: area[0],
},
@@ -711,7 +930,7 @@ describe('Location tests', () => {
name: 'Test Name323',
figure: {
type: locations.GARDEN,
- location_id: location_id,
+ location_id,
figure_id: area[0].figure_id,
area: area[0],
},
diff --git a/packages/api/tests/login.test.js b/packages/api/tests/login.test.js
index a5d276d670..76fbbea99b 100644
--- a/packages/api/tests/login.test.js
+++ b/packages/api/tests/login.test.js
@@ -25,13 +25,12 @@ jest.mock('../src/middleware/acl/checkJwt');
jest.mock('../src/jobs/station_sync/mapping');
jest.mock('../src/templates/sendEmailTemplate');
const mocks = require('./mock.factories');
-let faker = require('faker');
-
+const { faker } = require('@faker-js/faker');
describe('Sign Up Tests', () => {
let middleware;
- let emailMiddleware
- let mockEmail = jest.fn();
+ let emailMiddleware;
+ const mockEmail = jest.fn();
let farm;
let newOwner;
@@ -40,19 +39,14 @@ describe('Sign Up Tests', () => {
token = global.token;
});
-;
-
beforeEach(() => {
emailMiddleware.sendEmail.mockClear();
- })
+ });
// FUNCTIONS
function getRequest({ email = newOwner.email }, callback) {
- chai.request(server)
- .get(`/login/user/${email}`)
- .set('email', email)
- .end(callback);
+ chai.request(server).get(`/login/user/${email}`).set('email', email).end(callback);
}
beforeEach(async () => {
@@ -78,18 +72,17 @@ describe('Sign Up Tests', () => {
describe('Sign up tests', () => {
test('Get status of user from email address should return 200 and SSO false', async (done) => {
- const [user] = await mocks.usersFactory();
- const name = user.first_name;
- getRequest({ email: user.email}, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.exists).toBe(true);
- expect(res.body.sso).toBe(false);
- expect(res.body.first_name).toBe(name);
- expect(res.body.language).toBe('en'); // Default language
- done();
- });
- });
-
+ const [user] = await mocks.usersFactory();
+ const name = user.first_name;
+ getRequest({ email: user.email }, (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.exists).toBe(true);
+ expect(res.body.sso).toBe(false);
+ expect(res.body.first_name).toBe(name);
+ expect(res.body.language).toBe('en'); // Default language
+ done();
+ });
+ });
test('Get status of user from email address should return 200 and SSO true', async (done) => {
const [user] = await mocks.usersFactory(mocks.fakeSSOUser());
@@ -123,96 +116,115 @@ describe('Sign Up Tests', () => {
describe('Exists', () => {
test('should send missing invitation to user if checks existance and has no farms', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 2});
- const [userFarm] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- getRequest({email: user.email}, (err, res) => {
+ const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ getRequest({ email: user.email }, (err, res) => {
expect(res.status).toBe(200);
expect(res.body.exists).toBe(false);
expect(res.body.invited).toBe(true);
expect(emailMiddleware.sendEmail).toHaveBeenCalled();
done();
- })
- })
+ });
+ });
test('should send missing invitation(s) to user if checks existance and has no farms but many invites', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 2});
- const [userFarm1] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- const [userFarm2] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- const [userFarm3] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- const [userFarm4] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- getRequest({email: user.email}, (err, res) => {
+ const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
+ const [userFarm1] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ const [userFarm2] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ const [userFarm3] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ const [userFarm4] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ getRequest({ email: user.email }, (err, res) => {
expect(res.status).toBe(200);
expect(res.body.exists).toBe(false);
expect(res.body.invited).toBe(true);
expect(emailMiddleware.sendEmail).toHaveBeenCalledTimes(4);
done();
- })
- })
+ });
+ });
test('should send a password reset email to user if he was legacy ', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 3});
- const [userFarm1] = await mocks.userFarmFactory({promisedUser: [user]});
- getRequest({email: user.email}, (err, res) => {
+ const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 3 });
+ const [userFarm1] = await mocks.userFarmFactory({ promisedUser: [user] });
+ getRequest({ email: user.email }, (err, res) => {
expect(res.status).toBe(200);
expect(res.body.exists).toBe(false);
expect(res.body.expired).toBe(true);
expect(emailMiddleware.sendEmail).toHaveBeenCalledTimes(1);
done();
- })
- })
+ });
+ });
test('should resend a password reset email to user if he was legacy ', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 3});
- const [userFarm1] = await mocks.userFarmFactory({promisedUser: [user]});
- getRequest({email: user.email}, (err, res) => {
- getRequest({email: user.email}, (err2, res2) => {
+ const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 3 });
+ const [userFarm1] = await mocks.userFarmFactory({ promisedUser: [user] });
+ getRequest({ email: user.email }, (err, res) => {
+ getRequest({ email: user.email }, (err2, res2) => {
expect(res2.status).toBe(200);
expect(res2.body.exists).toBe(false);
expect(res2.body.expired).toBe(true);
expect(emailMiddleware.sendEmail).toHaveBeenCalledTimes(2);
done();
- })
- })
- })
-
+ });
+ });
+ });
test('should reject when a pseudo user tries to login', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 1, email: `${faker.random.uuid()}@pseudo.com`});
- const [userFarm1] = await mocks.userFarmFactory({promisedUser: [user]});
- getRequest({email: user.email}, (err, res) => {
+ const [user] = await mocks.usersFactory({
+ ...mocks.fakeUser(),
+ status_id: 1,
+ email: `${faker.datatype.uuid()}@pseudo.com`,
+ });
+ const [userFarm1] = await mocks.userFarmFactory({ promisedUser: [user] });
+ getRequest({ email: user.email }, (err, res) => {
expect(res.status).toBe(400);
expect(emailMiddleware.sendEmail).toHaveBeenCalledTimes(0);
done();
- })
- })
+ });
+ });
test('should fail at the 4th request of a user who had a pending invitation', async (done) => {
- const [user] = await mocks.usersFactory({...mocks.fakeUser(), status_id: 2});
- const [userFarm] = await mocks.userFarmFactory({promisedUser: [user]}, {status: 'Invited'});
- const {user_id, farm_id} = userFarm;
- getRequest({email: user.email}, async() => {
+ const [user] = await mocks.usersFactory({ ...mocks.fakeUser(), status_id: 2 });
+ const [userFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user] },
+ { status: 'Invited' },
+ );
+ const { user_id, farm_id } = userFarm;
+ getRequest({ email: user.email }, async () => {
const [emailTokenRow] = await knex('emailToken').where({ user_id, farm_id });
expect(emailTokenRow.times_sent).toBe(1);
- getRequest({email: user.email}, async() => {
- const [emailTokenRow] = await knex('emailToken').where({user_id, farm_id});
+ getRequest({ email: user.email }, async () => {
+ const [emailTokenRow] = await knex('emailToken').where({ user_id, farm_id });
expect(emailTokenRow.times_sent).toBe(2);
- getRequest({email: user.email}, async() => {
- const [emailTokenRow] = await knex('emailToken').where({user_id, farm_id});
+ getRequest({ email: user.email }, async () => {
+ const [emailTokenRow] = await knex('emailToken').where({ user_id, farm_id });
expect(emailTokenRow.times_sent).toBe(3);
- getRequest({email: user.email}, async(err, res) => {
+ getRequest({ email: user.email }, async (err, res) => {
expect(res.status).toBe(200);
- const [emailTokenRow] = await knex('emailToken').where({user_id, farm_id});
+ const [emailTokenRow] = await knex('emailToken').where({ user_id, farm_id });
expect(emailTokenRow.times_sent).toBe(3);
expect(res.body.exists).toBe(false);
expect(res.body.invited).toBe(true);
expect(emailMiddleware.sendEmail).toHaveBeenCalledTimes(3);
done();
- })
- })
- })
- })
- })
-
- })
-
+ });
+ });
+ });
+ });
+ });
+ });
});
diff --git a/packages/api/tests/managementPlan.test.js b/packages/api/tests/managementPlan.test.js
index 8d7bd5b074..dc94aa8834 100644
--- a/packages/api/tests/managementPlan.test.js
+++ b/packages/api/tests/managementPlan.test.js
@@ -23,15 +23,13 @@ const { tableCleanup } = require('./testEnvironment');
jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
const mocks = require('./mock.factories');
-const faker = require('faker');
+const { faker } = require('@faker-js/faker');
const lodash = require('lodash');
-
const managementPlanModel = require('../src/models/managementPlanModel');
const locationModel = require('../src/models/locationModel');
const cropManagementPlanModel = require('../src/models/cropManagementPlanModel');
-
describe('ManagementPlan Tests', () => {
let middleware;
let owner;
@@ -47,9 +45,14 @@ describe('ManagementPlan Tests', () => {
await mocks.populateTaskTypes();
});
-
- function postManagementPlanRequest(data, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).post(`/management_plan`)
+ function postManagementPlanRequest(
+ data,
+ { user_id = owner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
+ chai
+ .request(server)
+ .post(`/management_plan`)
.set('Content-Type', 'application/json')
.set('user_id', user_id)
.set('farm_id', farm_id)
@@ -58,15 +61,18 @@ describe('ManagementPlan Tests', () => {
}
function getRequest(url, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).get(url)
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .end(callback);
+ chai.request(server).get(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
}
- function patchManagementPlanRequest(data, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
+ function patchManagementPlanRequest(
+ data,
+ { user_id = owner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
const { management_plan_id } = data;
- chai.request(server).patch(`/management_plan/${management_plan_id}`)
+ chai
+ .request(server)
+ .patch(`/management_plan/${management_plan_id}`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
@@ -74,24 +80,33 @@ describe('ManagementPlan Tests', () => {
}
function deleteRequest(url, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
- chai.request(server).delete(url)
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .end(callback);
+ chai.request(server).delete(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
}
- function completeManagementPlanRequest(data, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
+ function completeManagementPlanRequest(
+ data,
+ { user_id = owner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
const { management_plan_id } = data;
- chai.request(server).patch(`/management_plan/${management_plan_id}/complete`)
+ chai
+ .request(server)
+ .patch(`/management_plan/${management_plan_id}/complete`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
.end(callback);
}
- function abandonManagementPlanRequest(data, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
+ function abandonManagementPlanRequest(
+ data,
+ { user_id = owner.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
const { management_plan_id } = data;
- chai.request(server).patch(`/management_plan/${management_plan_id}/abandon`)
+ chai
+ .request(server)
+ .patch(`/management_plan/${management_plan_id}/abandon`)
.set('farm_id', farm_id)
.set('user_id', user_id)
.send(data)
@@ -99,22 +114,28 @@ describe('ManagementPlan Tests', () => {
}
function fakeUserFarm(role = 1) {
- return ({ ...mocks.fakeUserFarm(), role_id: role });
+ return { ...mocks.fakeUserFarm(), role_id: role };
}
beforeEach(async () => {
[owner] = await mocks.usersFactory();
[farm] = await mocks.farmFactory();
- const [ownerFarm] = await mocks.userFarmFactory({
- promisedUser: [owner],
- promisedFarm: [farm],
- }, fakeUserFarm(1));
+ const [ownerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [owner],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(1),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [farm] });
await mocks.fieldFactory({
promisedLocation: [location],
});
- field = await locationModel.query().context({ showHidden: true }).whereNotDeleted().findById(location.location_id)
- .withGraphFetched(`[
+ field = await locationModel
+ .query()
+ .context({ showHidden: true })
+ .whereNotDeleted()
+ .findById(location.location_id).withGraphFetched(`[
figure.[area], field]`);
middleware = require('../src/middleware/acl/checkJwt');
@@ -140,80 +161,120 @@ describe('ManagementPlan Tests', () => {
let cropVariety;
let unAuthorizedUser;
beforeEach(async () => {
- [crop] = await mocks.cropFactory({ promisedFarm: [farm] }, {
- ...mocks.fakeCrop(),
- crop_common_name: 'crop',
- user_added: true,
- });
- [cropVariety] = await mocks.crop_varietyFactory({ promisedFarm: [farm], promisedCrop: [crop] });
- [transplantManagementPlan] = await mocks.crop_management_planFactory({
- promisedField: [field],
- promisedCropVariety: [cropVariety],
- }, {
- cropManagementPlan: {
- ...mocks.fakeCropManagementPlan(),
- needs_transplant: true,
+ [crop] = await mocks.cropFactory(
+ { promisedFarm: [farm] },
+ {
+ ...mocks.fakeCrop(),
+ crop_common_name: 'crop',
+ user_added: true,
},
+ );
+ [cropVariety] = await mocks.crop_varietyFactory({
+ promisedFarm: [farm],
+ promisedCrop: [crop],
});
- [seedManagementPlan] = await mocks.crop_management_planFactory({
- promisedField: [field],
- promisedCropVariety: [cropVariety],
- }, {
- cropManagementPlan: {
- ...mocks.fakeCropManagementPlan(),
- needs_transplant: false,
+ [transplantManagementPlan] = await mocks.crop_management_planFactory(
+ {
+ promisedField: [field],
+ promisedCropVariety: [cropVariety],
},
- });
+ {
+ cropManagementPlan: {
+ ...mocks.fakeCropManagementPlan(),
+ needs_transplant: true,
+ },
+ },
+ );
+ [seedManagementPlan] = await mocks.crop_management_planFactory(
+ {
+ promisedField: [field],
+ promisedCropVariety: [cropVariety],
+ },
+ {
+ cropManagementPlan: {
+ ...mocks.fakeCropManagementPlan(),
+ needs_transplant: false,
+ },
+ },
+ );
[worker] = await mocks.usersFactory();
- [workerFarm] = await mocks.userFarmFactory({ promisedUser: [worker], promisedFarm: [farm] }, fakeUserFarm(3));
+ [workerFarm] = await mocks.userFarmFactory(
+ { promisedUser: [worker], promisedFarm: [farm] },
+ fakeUserFarm(3),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
-
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
-
describe('Get managementPlan', () => {
const assetManagementPlans = (res, count) => {
for (const management_plan of res.body) {
expect(res.body.length).toBe(count);
- expect(['BROADCAST_METHOD', 'CONTAINER_METHOD', 'BED_METHOD', 'ROW_METHOD']).toContain(management_plan.crop_management_plan.planting_management_plans[0].planting_method);
+ expect(['BROADCAST_METHOD', 'CONTAINER_METHOD', 'BED_METHOD', 'ROW_METHOD']).toContain(
+ management_plan.crop_management_plan.planting_management_plans[0].planting_method,
+ );
if (management_plan.crop_management_plan.planting_method === 'BROADCAST_METHOD') {
- expect(management_plan.crop_management_plan.planting_management_plans[0].management_plan_id).toBe(seedManagementPlan.management_plan_id);
- expect(management_plan.crop_management_plan.planting_management_plans[1]).toBeUndefined();
+ expect(
+ management_plan.crop_management_plan.planting_management_plans[0].management_plan_id,
+ ).toBe(seedManagementPlan.management_plan_id);
+ expect(
+ management_plan.crop_management_plan.planting_management_plans[1],
+ ).toBeUndefined();
} else if (management_plan.crop_management_plan.planting_type === 'CONTAINER_METHOD') {
- expect(management_plan.crop_management_plan.planting_management_plans[0].management_plan_id).toBe(seedManagementPlan.management_plan_id);
- expect(management_plan.crop_management_plan.planting_management_plans[1]?.management_plan_id).toBe(seedManagementPlan.management_plan_id);
+ expect(
+ management_plan.crop_management_plan.planting_management_plans[0].management_plan_id,
+ ).toBe(seedManagementPlan.management_plan_id);
+ expect(
+ management_plan.crop_management_plan.planting_management_plans[1]?.management_plan_id,
+ ).toBe(seedManagementPlan.management_plan_id);
}
}
};
test('Workers should get managementPlan by farm id', async (done) => {
- getRequest(`/management_plan/farm/${farm.farm_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- assetManagementPlans(res, 2);
- done();
- });
+ getRequest(
+ `/management_plan/farm/${farm.farm_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ assetManagementPlans(res, 2);
+ done();
+ },
+ );
});
test('Workers should get managementPlan by date', async (done) => {
- getRequest(`/management_plan/farm/date/${farm.farm_id}/${moment().format('YYYY-MM-DD')}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- assetManagementPlans(res, 2);
- done();
- });
+ getRequest(
+ `/management_plan/farm/date/${farm.farm_id}/${moment().format('YYYY-MM-DD')}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ assetManagementPlans(res, 2);
+ done();
+ },
+ );
});
test('Workers should get managementPlan by id', async (done) => {
- getRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.crop_management_plan.planting_management_plans[1].management_plan_id).toBe(transplantManagementPlan.management_plan_id);
- done();
- });
+ getRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(
+ res.body.crop_management_plan.planting_management_plans[1].management_plan_id,
+ ).toBe(transplantManagementPlan.management_plan_id);
+ done();
+ },
+ );
});
describe('Get managementPlan authorization tests', () => {
@@ -224,65 +285,85 @@ describe('ManagementPlan Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
test('Owner should get managementPlan by farm id', async (done) => {
- getRequest(`/management_plan/farm/${farm.farm_id}`, { user_id: owner.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- assetManagementPlans(res, 2);
- done();
- });
+ getRequest(
+ `/management_plan/farm/${farm.farm_id}`,
+ { user_id: owner.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ assetManagementPlans(res, 2);
+ done();
+ },
+ );
});
test('Manager should get managementPlan by farm id', async (done) => {
- getRequest(`/management_plan/farm/${farm.farm_id}`, { user_id: manager.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- assetManagementPlans(res, 2);
- done();
- });
+ getRequest(
+ `/management_plan/farm/${farm.farm_id}`,
+ { user_id: manager.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ assetManagementPlans(res, 2);
+ done();
+ },
+ );
});
test('Should get status 403 if an unauthorizedUser tries to get managementPlan by farm id', async (done) => {
- getRequest(`/management_plan/farm/${farm.farm_id}`, { user_id: unAuthorizedUser.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ getRequest(
+ `/management_plan/farm/${farm.farm_id}`,
+ { user_id: unAuthorizedUser.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Circumvent authorization by modifying farm_id', async (done) => {
- getRequest(`/management_plan/farm/${farm.farm_id}`, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ getRequest(
+ `/management_plan/farm/${farm.farm_id}`,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
-
-
});
});
-
- describe('Delete managementPlan', function() {
-
+ describe('Delete managementPlan', function () {
let worker;
let manager;
let extensionOfficer;
@@ -291,82 +372,126 @@ describe('ManagementPlan Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[extensionOfficer] = await mocks.usersFactory();
- const [extensionOfficerFarm] = await mocks.userFarmFactory({
- promisedUser: [extensionOfficer],
- promisedFarm: [farm],
- }, fakeUserFarm(5));
-
+ const [extensionOfficerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [extensionOfficer],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(5),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
test('should delete a managementPlan by owner', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, {}, async (err, res) => {
- expect(res.status).toBe(200);
- const managementPlanRes = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id);
- expect(managementPlanRes.length).toBe(1);
- expect(managementPlanRes[0].deleted).toBe(true);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ {},
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const managementPlanRes = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id);
+ expect(managementPlanRes.length).toBe(1);
+ expect(managementPlanRes[0].deleted).toBe(true);
+ done();
+ },
+ );
});
test('should delete a managementPlan by manager', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, { user_id: manager.user_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const managementPlanRes = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id);
- expect(managementPlanRes.length).toBe(1);
- expect(managementPlanRes[0].deleted).toBe(true);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ { user_id: manager.user_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const managementPlanRes = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id);
+ expect(managementPlanRes.length).toBe(1);
+ expect(managementPlanRes[0].deleted).toBe(true);
+ done();
+ },
+ );
});
test('should delete a managementPlan by extension officer', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, { user_id: extensionOfficer.user_id }, async (err, res) => {
- expect(res.status).toBe(200);
- const managementPlanRes = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id);
- expect(managementPlanRes.length).toBe(1);
- expect(managementPlanRes[0].deleted).toBe(true);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ { user_id: extensionOfficer.user_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const managementPlanRes = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id);
+ expect(managementPlanRes.length).toBe(1);
+ expect(managementPlanRes[0].deleted).toBe(true);
+ done();
+ },
+ );
});
test('should return 403 if an unauthorized user tries to delete a managementPlan', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, { user_id: unAuthorizedUser.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ { user_id: unAuthorizedUser.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('should return 403 if a worker tries to delete a managementPlan', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, { user_id: worker.user_id }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ { user_id: worker.user_id },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Circumvent authorization by modifying farm_id', async (done) => {
- deleteRequest(`/management_plan/${transplantManagementPlan.management_plan_id}`, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ deleteRequest(
+ `/management_plan/${transplantManagementPlan.management_plan_id}`,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
@@ -375,17 +500,30 @@ describe('ManagementPlan Tests', () => {
return {
name: faker.lorem.words(),
notes: faker.lorem.words(),
- crop_management_plan: { estimated_yield: faker.datatype.number(10000), harvest_date: 'shouldBeDiscarded' },
+ crop_management_plan: {
+ estimated_yield: faker.datatype.number(10000),
+ harvest_date: 'shouldBeDiscarded',
+ },
management_plan_id: transplantManagementPlan.management_plan_id,
};
}
async function expectManagementPlanPatched(res, expected) {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).findById(expected.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .findById(expected.management_plan_id)
+ .first();
expect(newManagementPlan.name).toBe(expected.name);
- const newCropManagementPlan = await cropManagementPlanModel.query().context({ showHidden: true }).findById(expected.management_plan_id).first();
- expect(newCropManagementPlan.estimated_yield).toBe(expected.crop_management_plan.estimated_yield);
+ const newCropManagementPlan = await cropManagementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .findById(expected.management_plan_id)
+ .first();
+ expect(newCropManagementPlan.estimated_yield).toBe(
+ expected.crop_management_plan.estimated_yield,
+ );
}
xtest('should be able to edit management plan', async (done) => {
@@ -404,23 +542,31 @@ describe('ManagementPlan Tests', () => {
beforeEach(async () => {
[worker] = await mocks.usersFactory();
- const [workerFarm] = await mocks.userFarmFactory({
- promisedUser: [worker],
- promisedFarm: [farm],
- }, fakeUserFarm(3));
+ const [workerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [worker],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(3),
+ );
[manager] = await mocks.usersFactory();
- const [managerFarm] = await mocks.userFarmFactory({
- promisedUser: [manager],
- promisedFarm: [farm],
- }, fakeUserFarm(2));
-
+ const [managerFarm] = await mocks.userFarmFactory(
+ {
+ promisedUser: [manager],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(2),
+ );
[unAuthorizedUser] = await mocks.usersFactory();
[farmunAuthorizedUser] = await mocks.farmFactory();
- const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory({
- promisedUser: [unAuthorizedUser],
- promisedFarm: [farmunAuthorizedUser],
- }, fakeUserFarm(1));
+ const [ownerFarmunAuthorizedUser] = await mocks.userFarmFactory(
+ {
+ promisedUser: [unAuthorizedUser],
+ promisedFarm: [farmunAuthorizedUser],
+ },
+ fakeUserFarm(1),
+ );
});
//TODO: Owner test
test('should edit and the area_used field by manager', async (done) => {
@@ -449,25 +595,27 @@ describe('ManagementPlan Tests', () => {
test('Circumvent authorization by modifying farm_id', async (done) => {
const reqBody = getFakeManagementPlan();
- patchManagementPlanRequest(reqBody, {
- user_id: unAuthorizedUser.user_id,
- farm_id: farmunAuthorizedUser.farm_id,
- }, (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ patchManagementPlanRequest(
+ reqBody,
+ {
+ user_id: unAuthorizedUser.user_id,
+ farm_id: farmunAuthorizedUser.farm_id,
+ },
+ (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
-
});
});
-
describe('Complete/abandon management plan', () => {
function getCompleteReqBody(isAbandonReq, props = {}) {
return {
[isAbandonReq ? 'abandon_date' : 'complete_date']: '2021-01-01',
complete_notes: faker.lorem.words(),
- rating: faker.random.arrayElement([1, 2, 3, 4, 5, 0, null, undefined]),
+ rating: faker.helpers.arrayElement([1, 2, 3, 4, 5, 0, null, undefined]),
abandon_reason: isAbandonReq ? faker.lorem.words() : undefined,
management_plan_id: transplantManagementPlan.management_plan_id,
...props,
@@ -485,7 +633,11 @@ describe('ManagementPlan Tests', () => {
const reqBody = getCompleteReqBody(true);
abandonManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
expect(newManagementPlan.abandon_reason).toBe(reqBody.abandon_reason);
done();
@@ -496,7 +648,11 @@ describe('ManagementPlan Tests', () => {
const reqBody = getCompleteReqBody();
completeManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
done();
});
@@ -506,49 +662,76 @@ describe('ManagementPlan Tests', () => {
const reqBody = getCompleteReqBody();
const abandonedTask = await mocks.management_tasksFactory({
promisedManagementPlan: [transplantManagementPlan],
- promisedTask: mocks.taskFactory({ promisedUser: [owner] }, { ...mocks.fakeTask({ abandoned_time: faker.date.past() }) }),
+ promisedTask: mocks.taskFactory(
+ { promisedUser: [owner] },
+ { ...mocks.fakeTask({ abandon_date: faker.date.past() }) },
+ ),
});
const completedTask = await mocks.management_tasksFactory({
promisedManagementPlan: [transplantManagementPlan],
- promisedTask: mocks.taskFactory({ promisedUser: [owner] }, { ...mocks.fakeTask({ abandoned_time: faker.date.past() }) }),
+ promisedTask: mocks.taskFactory(
+ { promisedUser: [owner] },
+ { ...mocks.fakeTask({ abandon_date: faker.date.past() }) },
+ ),
});
completeManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
done();
});
});
- const getDateInputFormat = (date) => moment(date).utc().format('YYYY-MM-DD');
-
+ const getDateInputFormat = (date) => moment(date).format('YYYY-MM-DD');
test('Abandon management plan with one pending task that reference this management plan and another management_plan', async (done) => {
const reqBody = getCompleteReqBody();
- const [plantingManagementPlan] = await getFinalPlantingManagementPlan(transplantManagementPlan);
+ const [plantingManagementPlan] = await getFinalPlantingManagementPlan(
+ transplantManagementPlan,
+ );
const [managementTaskToBeDeleted] = await mocks.management_tasksFactory({
promisedPlantingManagementPlan: [plantingManagementPlan],
promisedTask: mocks.taskFactory({ promisedUser: [owner] }, { ...mocks.fakeTask() }),
});
const [managementTaskToKeep] = await mocks.management_tasksFactory({
- promisedPlantingManagementPlan: mocks.planting_management_planFactory({ promisedFarm: [farm] }),
+ promisedPlantingManagementPlan: mocks.planting_management_planFactory({
+ promisedFarm: [farm],
+ }),
promisedTask: [managementTaskToBeDeleted],
});
const [anotherManagementTask] = await mocks.management_tasksFactory({
- promisedPlantingManagementPlan: mocks.planting_management_planFactory({ promisedFarm: [farm] }),
+ promisedPlantingManagementPlan: mocks.planting_management_planFactory({
+ promisedFarm: [farm],
+ }),
});
abandonManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
- const deletedManagementPlan = await knex('management_tasks').where(lodash.pick(managementTaskToBeDeleted, ['planting_management_plan_id', 'task_id'])).first();
+ const deletedManagementPlan = await knex('management_tasks')
+ .where(
+ lodash.pick(managementTaskToBeDeleted, ['planting_management_plan_id', 'task_id']),
+ )
+ .first();
expect(deletedManagementPlan).toBeUndefined();
- const keptManagementTask0 = await knex('management_tasks').where(lodash.pick(managementTaskToKeep, ['planting_management_plan_id', 'task_id'])).first();
+ const keptManagementTask0 = await knex('management_tasks')
+ .where(lodash.pick(managementTaskToKeep, ['planting_management_plan_id', 'task_id']))
+ .first();
expect(keptManagementTask0).toBeDefined();
- const keptManagementTask1 = await knex('management_tasks').where(lodash.pick(anotherManagementTask, ['planting_management_plan_id', 'task_id'])).first();
+ const keptManagementTask1 = await knex('management_tasks')
+ .where(lodash.pick(anotherManagementTask, ['planting_management_plan_id', 'task_id']))
+ .first();
expect(keptManagementTask1).toBeDefined();
done();
});
@@ -556,7 +739,9 @@ describe('ManagementPlan Tests', () => {
test('Abandon management plan with two pending task that reference this management plan and another management_plan', async (done) => {
const reqBody = getCompleteReqBody(true);
- const [plantingManagementPlan] = await getFinalPlantingManagementPlan(transplantManagementPlan);
+ const [plantingManagementPlan] = await getFinalPlantingManagementPlan(
+ transplantManagementPlan,
+ );
const [managementTaskToBeDeleted] = await mocks.management_tasksFactory({
promisedPlantingManagementPlan: [plantingManagementPlan],
promisedTask: mocks.taskFactory({ promisedUser: [owner] }, { ...mocks.fakeTask() }),
@@ -578,35 +763,57 @@ describe('ManagementPlan Tests', () => {
abandonManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
- const deletedManagementPlan = await knex('management_tasks').where(lodash.pick(managementTaskToBeDeleted, ['planting_management_plan_id', 'task_id'])).first();
+ const deletedManagementPlan = await knex('management_tasks')
+ .where(
+ lodash.pick(managementTaskToBeDeleted, ['planting_management_plan_id', 'task_id']),
+ )
+ .first();
expect(deletedManagementPlan).toBeUndefined();
- const keptManagementTask0 = await knex('management_tasks').where(lodash.pick(managementTaskToKeep, ['planting_management_plan_id', 'task_id'])).first();
+ const keptManagementTask0 = await knex('management_tasks')
+ .where(lodash.pick(managementTaskToKeep, ['planting_management_plan_id', 'task_id']))
+ .first();
expect(keptManagementTask0).toBeDefined();
- const keptManagementTask1 = await knex('management_tasks').where(lodash.pick(anotherManagementTask, ['planting_management_plan_id', 'task_id'])).first();
+ const keptManagementTask1 = await knex('management_tasks')
+ .where(lodash.pick(anotherManagementTask, ['planting_management_plan_id', 'task_id']))
+ .first();
expect(keptManagementTask1).toBeDefined();
- const keptManagementTask2 = await knex('management_tasks').where(lodash.pick(taskToAbandon, ['planting_management_plan_id', 'task_id'])).first();
+ const keptManagementTask2 = await knex('management_tasks')
+ .where(lodash.pick(taskToAbandon, ['planting_management_plan_id', 'task_id']))
+ .first();
expect(keptManagementTask2).toBeDefined();
- const abandonedTask = await knex('task').where(lodash.pick(taskToAbandon, ['task_id'])).first();
- expect(getDateInputFormat(abandonedTask.abandoned_time)).toBe(reqBody.abandon_date);
+ const abandonedTask = await knex('task')
+ .where(lodash.pick(taskToAbandon, ['task_id']))
+ .first();
+ expect(getDateInputFormat(abandonedTask.abandon_date)).toBe(reqBody.abandon_date);
done();
});
});
test('Abandon management plan with one pending task that reference this management plan and no location', async (done) => {
const reqBody = getCompleteReqBody(true);
- const [plantingManagementPlan] = await getFinalPlantingManagementPlan(transplantManagementPlan);
+ const [plantingManagementPlan] = await getFinalPlantingManagementPlan(
+ transplantManagementPlan,
+ );
const [task] = await mocks.management_tasksFactory({
promisedPlantingManagementPlan: [plantingManagementPlan],
promisedTask: mocks.taskFactory({ promisedUser: [owner] }, { ...mocks.fakeTask() }),
});
abandonManagementPlanRequest(reqBody, {}, async (err, res) => {
expect(res.status).toBe(200);
- const newManagementPlan = await managementPlanModel.query().context({ showHidden: true }).where('management_plan_id', transplantManagementPlan.management_plan_id).first();
+ const newManagementPlan = await managementPlanModel
+ .query()
+ .context({ showHidden: true })
+ .where('management_plan_id', transplantManagementPlan.management_plan_id)
+ .first();
expect(newManagementPlan.complete_notes).toBe(reqBody.complete_notes);
const newTask = await knex('task').where('task_id', task.task_id).first();
- expect(getDateInputFormat(newTask.abandoned_time)).toBe(reqBody.abandon_date);
+ expect(getDateInputFormat(newTask.abandon_date)).toBe(reqBody.abandon_date);
// expect(newTask.abandon_reason).toBe('Crop management plan abandoned');
done();
});
@@ -614,7 +821,9 @@ describe('ManagementPlan Tests', () => {
test('Should return 400 when complete management plan with pending tasks', async (done) => {
const reqBody = getCompleteReqBody();
- const [plantingManagementPlan] = await getFinalPlantingManagementPlan(transplantManagementPlan);
+ const [plantingManagementPlan] = await getFinalPlantingManagementPlan(
+ transplantManagementPlan,
+ );
const pendingTask = await mocks.management_tasksFactory({
promisedPlantingManagementPlan: [plantingManagementPlan],
});
@@ -624,10 +833,7 @@ describe('ManagementPlan Tests', () => {
done();
});
});
-
-
});
-
});
describe('POST management plan', () => {
@@ -647,10 +853,17 @@ describe('ManagementPlan Tests', () => {
[userFarm] = await mocks.userFarmFactory({}, { role_id: 1, status: 'Active' });
[field] = await mocks.fieldFactory({ promisedFarm: [userFarm] });
[crop] = await mocks.cropFactory({ promisedFarm: [userFarm] });
- [cropVariety] = await mocks.crop_varietyFactory({ promisedFarm: [userFarm], promisedCrop: [crop] });
+ [cropVariety] = await mocks.crop_varietyFactory({
+ promisedFarm: [userFarm],
+ promisedCrop: [crop],
+ });
});
- function getBody(finalMethod = 'broadcast_method', initialMethod, { already_in_ground = false } = {}) {
+ function getBody(
+ finalMethod = 'broadcast_method',
+ initialMethod,
+ { already_in_ground = false } = {},
+ ) {
return {
crop_variety_id: cropVariety.crop_variety_id,
...mocks.fakeManagementPlan(),
@@ -658,16 +871,25 @@ describe('ManagementPlan Tests', () => {
...mocks.fakeCropManagementPlan(),
needs_transplant: !!initialMethod,
already_in_ground,
- planting_management_plans: [finalMethod, initialMethod].reduce((planting_methods, method, index) => {
- return method ? [...planting_methods, {
- ...mocks.fakePlantingManagementPlan(),
- location_id: field.location_id,
- is_final_planting_management_plan: index === 0,
- planting_task_type: initialMethod && index === 1 ? 'TRANSPLANT_TASK' : 'PLANT_TASK',
- planting_method: method.toUpperCase(),
- [method]: fakeMethodMap[method](),
- }] : planting_methods;
- }, []),
+ planting_management_plans: [finalMethod, initialMethod].reduce(
+ (planting_methods, method, index) => {
+ return method
+ ? [
+ ...planting_methods,
+ {
+ ...mocks.fakePlantingManagementPlan(),
+ location_id: field.location_id,
+ is_final_planting_management_plan: index === 0,
+ planting_task_type:
+ initialMethod && index === 1 ? 'TRANSPLANT_TASK' : 'PLANT_TASK',
+ planting_method: method.toUpperCase(),
+ [method]: fakeMethodMap[method](),
+ },
+ ]
+ : planting_methods;
+ },
+ [],
+ ),
},
};
}
@@ -675,39 +897,61 @@ describe('ManagementPlan Tests', () => {
async function expectPlantingMethodPosted(res, final_planting_method, initial_planting_method) {
expect(res.status).toBe(201);
const { management_plan_id } = res.body.management_plan;
- const { already_in_ground, for_cover, needs_transplant } = res.body.management_plan.crop_management_plan;
+ const {
+ already_in_ground,
+ for_cover,
+ needs_transplant,
+ } = res.body.management_plan.crop_management_plan;
if (!already_in_ground) {
- const { planting_management_plan_id } = await knex('planting_management_plan').where({
- management_plan_id: res.body.management_plan.management_plan_id,
- planting_task_type: 'PLANT_TASK',
- }).first();
- const plantingMethod = await knex(final_planting_method).where({ planting_management_plan_id }).first();
+ const { planting_management_plan_id } = await knex('planting_management_plan')
+ .where({
+ management_plan_id: res.body.management_plan.management_plan_id,
+ planting_task_type: 'PLANT_TASK',
+ })
+ .first();
+ const plantingMethod = await knex(final_planting_method)
+ .where({ planting_management_plan_id })
+ .first();
expect(plantingMethod).toBeDefined();
const plant_task = await knex('plant_task').where({ planting_management_plan_id }).first();
expect(plant_task).toBeDefined();
}
if (initial_planting_method) {
- const { planting_management_plan_id } = await knex('planting_management_plan').where({
- management_plan_id: res.body.management_plan.management_plan_id,
- planting_task_type: 'TRANSPLANT_TASK',
- }).first();
- const plantingMethod = await knex(initial_planting_method).where({ planting_management_plan_id }).first();
+ const { planting_management_plan_id } = await knex('planting_management_plan')
+ .where({
+ management_plan_id: res.body.management_plan.management_plan_id,
+ planting_task_type: 'TRANSPLANT_TASK',
+ })
+ .first();
+ const plantingMethod = await knex(initial_planting_method)
+ .where({ planting_management_plan_id })
+ .first();
expect(plantingMethod).toBeDefined();
- const transplant_task = await knex('transplant_task').where({ planting_management_plan_id }).first();
+ const transplant_task = await knex('transplant_task')
+ .where({ planting_management_plan_id })
+ .first();
expect(transplant_task).toBeDefined();
}
- const { planting_management_plan_id } = await knex('planting_management_plan').where({
- management_plan_id: res.body.management_plan.management_plan_id,
- planting_task_type: needs_transplant ? 'TRANSPLANT_TASK' : 'PLANT_TASK',
- }).first();
+ const { planting_management_plan_id } = await knex('planting_management_plan')
+ .where({
+ management_plan_id: res.body.management_plan.management_plan_id,
+ planting_task_type: needs_transplant ? 'TRANSPLANT_TASK' : 'PLANT_TASK',
+ })
+ .first();
if (for_cover) {
- const fieldWorkTask = await knex('management_tasks').join('field_work_task', 'field_work_task.task_id', 'management_tasks.task_id').where({ planting_management_plan_id }).first();
+ const fieldWorkTask = await knex('management_tasks')
+ .join('field_work_task', 'field_work_task.task_id', 'management_tasks.task_id')
+ .where({ planting_management_plan_id })
+ .first();
expect(fieldWorkTask).toBeDefined();
} else {
- const harvestTask = await knex('management_tasks').join('harvest_task', 'harvest_task.task_id', 'management_tasks.task_id').where({ planting_management_plan_id }).first();
+ const harvestTask = await knex('management_tasks')
+ .join('harvest_task', 'harvest_task.task_id', 'management_tasks.task_id')
+ .where({ planting_management_plan_id })
+ .first();
expect(harvestTask).toBeDefined();
}
}
@@ -721,7 +965,11 @@ describe('ManagementPlan Tests', () => {
test('should create a broadcast management plan with 100% planted', async (done) => {
const broadcastData = getBody('broadcast_method');
- const { total_area } = await knex('location').join('figure', 'figure.location_id', 'location.location_id').join('area', 'figure.figure_id', 'area.figure_id').where('location.location_id', field.location_id).first();
+ const { total_area } = await knex('location')
+ .join('figure', 'figure.location_id', 'location.location_id')
+ .join('area', 'figure.figure_id', 'area.figure_id')
+ .where('location.location_id', field.location_id)
+ .first();
broadcastData.crop_management_plan.planting_management_plans[0].broadcast_method.percentage_planted = 100;
broadcastData.crop_management_plan.planting_management_plans[0].broadcast_method.area_used = total_area;
postManagementPlanRequest(broadcastData, userFarm, async (err, res) => {
@@ -731,10 +979,14 @@ describe('ManagementPlan Tests', () => {
});
test('should create a broadcast management plan with transplant', async (done) => {
- postManagementPlanRequest(getBody('broadcast_method', 'container_method'), userFarm, async (err, res) => {
- await expectPlantingMethodPosted(res, 'broadcast_method', 'container_method');
- done();
- });
+ postManagementPlanRequest(
+ getBody('broadcast_method', 'container_method'),
+ userFarm,
+ async (err, res) => {
+ await expectPlantingMethodPosted(res, 'broadcast_method', 'container_method');
+ done();
+ },
+ );
});
test('should create a container management plan with required data', async (done) => {
@@ -745,10 +997,14 @@ describe('ManagementPlan Tests', () => {
});
test('should create a container management plan with transplant', async (done) => {
- postManagementPlanRequest(getBody('container_method', 'container_method'), userFarm, async (err, res) => {
- await expectPlantingMethodPosted(res, 'container_method', 'container_method');
- done();
- });
+ postManagementPlanRequest(
+ getBody('container_method', 'container_method'),
+ userFarm,
+ async (err, res) => {
+ await expectPlantingMethodPosted(res, 'container_method', 'container_method');
+ done();
+ },
+ );
});
test('should create a rows management plan', async (done) => {
@@ -760,15 +1016,24 @@ describe('ManagementPlan Tests', () => {
//TODO: post management plan middle ware that checks there are maximum 1 plant_task and 1 transplant_task
xtest('should not allow multiple types of plantation', async (done) => {
- const managementPlantWith4plantingManagementPlan = getBody('broadcast_method', 'container_method');
- managementPlantWith4plantingManagementPlan.crop_management_plan.planting_management_plans = [...managementPlantWith4plantingManagementPlan.crop_management_plan.planting_management_plans, ...managementPlantWith4plantingManagementPlan.crop_management_plan.planting_management_plans];
- postManagementPlanRequest(managementPlantWith4plantingManagementPlan, userFarm, async (err, res) => {
- expect(res.status).toBe(400);
- done();
- });
+ const managementPlantWith4plantingManagementPlan = getBody(
+ 'broadcast_method',
+ 'container_method',
+ );
+ managementPlantWith4plantingManagementPlan.crop_management_plan.planting_management_plans = [
+ ...managementPlantWith4plantingManagementPlan.crop_management_plan
+ .planting_management_plans,
+ ...managementPlantWith4plantingManagementPlan.crop_management_plan
+ .planting_management_plans,
+ ];
+ postManagementPlanRequest(
+ managementPlantWith4plantingManagementPlan,
+ userFarm,
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
-
});
-
-
});
diff --git a/packages/api/tests/mock.factories.js b/packages/api/tests/mock.factories.js
index e14fe67f80..144bae18b7 100644
--- a/packages/api/tests/mock.factories.js
+++ b/packages/api/tests/mock.factories.js
@@ -1,4 +1,4 @@
-const faker = require('faker');
+const { faker } = require('@faker-js/faker');
const knex = require('../src/util/knex');
function weather_stationFactory(station = fakeStation()) {
@@ -28,7 +28,7 @@ function fakeUser(defaultData = {}) {
user_id: faker.datatype.uuid(),
status_id: 1,
phone_number: faker.phone.phoneNumber(),
- gender: faker.random.arrayElement(['OTHER', 'PREFER_NOT_TO_SAY', 'MALE', 'FEMALE']),
+ gender: faker.helpers.arrayElement(['OTHER', 'PREFER_NOT_TO_SAY', 'MALE', 'FEMALE']),
birth_year: faker.datatype.number({ min: 1900, max: new Date().getFullYear() }),
do_not_email: false,
...defaultData,
@@ -41,7 +41,7 @@ function fakeSSOUser(defaultData = {}) {
first_name: faker.name.findName(),
last_name: faker.name.lastName(),
email: email.toLowerCase(),
- user_id: faker.datatype.number(10),
+ user_id: faker.datatype.number({ min: 2, max: 10 }),
phone_number: faker.phone.phoneNumber(),
...defaultData,
};
@@ -82,7 +82,7 @@ async function userFarmFactory(
function fakeUserFarm(defaultData = {}) {
return {
- role_id: faker.random.arrayElement([1, 2, 3, 5]),
+ role_id: faker.helpers.arrayElement([1, 2, 3, 5]),
status: 'Active',
has_consent: true,
step_one: false,
@@ -122,7 +122,7 @@ async function locationFactory({ promisedFarm = farmFactory() } = {}, location =
function fakeLocation(defaultData = {}) {
return {
- name: faker.random.arrayElement(['Location1', 'Nice Location', 'Fence', 'AreaLocation']),
+ name: faker.helpers.arrayElement(['Location1', 'Nice Location', 'Fence', 'AreaLocation']),
notes: faker.lorem.word(3),
...defaultData,
};
@@ -163,8 +163,8 @@ function fakeArea(stringify = true, defaultData = {}) {
})),
],
perimeter: faker.datatype.number(),
- total_area_unit: faker.random.arrayElement(['m2', 'ha', 'ft2', 'ac']),
- perimeter_unit: faker.random.arrayElement(['m', 'km', 'ft', 'mi']),
+ total_area_unit: faker.helpers.arrayElement(['m2', 'ha', 'ft2', 'ac']),
+ perimeter_unit: faker.helpers.arrayElement(['m', 'km', 'ft', 'mi']),
...defaultData,
};
}
@@ -188,15 +188,14 @@ async function fieldFactory(
function fakeField(defaultData = {}) {
return {
- organic_status: faker.random.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
- transition_date: faker.date.future(),
+ organic_status: faker.helpers.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
+ transition_date: faker.date.future().toISOString().split('T')[0],
...defaultData,
};
}
async function organic_historyFactory(
{
- promisedStation = weather_stationFactory(),
promisedFarm = farmFactory(),
promisedLocation = locationFactory({ promisedFarm }),
promisedArea = areaFactory({ promisedLocation }, fakeArea(), 'field'),
@@ -214,8 +213,8 @@ async function organic_historyFactory(
function fakeOrganicHistory(defaultData = {}) {
return {
- organic_status: faker.random.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
- effective_date: faker.date.past(),
+ organic_status: faker.helpers.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
+ effective_date: faker.date.past().toISOString().split('T')[0],
...defaultData,
};
}
@@ -239,8 +238,8 @@ async function gardenFactory(
function fakeGarden(defaultData = {}) {
return {
- organic_status: faker.random.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
- transition_date: faker.date.future(),
+ organic_status: faker.helpers.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
+ transition_date: faker.date.future().toISOString().split('T')[0],
...defaultData,
};
}
@@ -260,7 +259,7 @@ function fakeFieldForTests(defaultData = {}) {
function fakePriceInsightForTests(defaultData = {}) {
return {
- distance: faker.random.arrayElement([5, 10, 25, 50]),
+ distance: faker.helpers.arrayElement([5, 10, 25, 50]),
lat: faker.address.latitude(),
long: faker.address.latitude(),
startdate: '2021-10-10',
@@ -386,7 +385,7 @@ function fakeCrop(defaultData = {}) {
crop_translation_key: faker.lorem.words(),
crop_genus: faker.lorem.words(),
crop_specie: faker.lorem.words(),
- crop_group: faker.random.arrayElement([
+ crop_group: faker.helpers.arrayElement([
'Fruit and nuts',
'Other crops',
'Stimulant, spice and aromatic crops',
@@ -399,7 +398,7 @@ function fakeCrop(defaultData = {}) {
'Potatoes and yams',
'Beverage and spice crops',
]),
- crop_subgroup: faker.random.arrayElement([
+ crop_subgroup: faker.helpers.arrayElement([
'Berries',
'Cereals',
'Citrus fruits',
@@ -478,14 +477,14 @@ function fakeCrop(defaultData = {}) {
yield_per_area: faker.datatype.number(10),
average_seed_weight: faker.datatype.number(10),
yield_per_plant: faker.datatype.number(10),
- seeding_type: faker.random.arrayElement(['SEED', 'SEEDLING_OR_PLANTING_STOCK']),
- lifecycle: faker.random.arrayElement(['ANNUAL', 'PERENNIAL']),
+ seeding_type: faker.helpers.arrayElement(['SEED', 'SEEDLING_OR_PLANTING_STOCK']),
+ lifecycle: faker.helpers.arrayElement(['ANNUAL', 'PERENNIAL']),
needs_transplant: faker.datatype.boolean(),
germination_days: faker.datatype.number({ min: 1, max: 10 }),
transplant_days: faker.datatype.number({ min: 11, max: 20 }),
harvest_days: faker.datatype.number({ min: 21, max: 30 }),
termination_days: faker.datatype.number({ min: 31, max: 40 }),
- planting_method: faker.random.arrayElement([
+ planting_method: faker.helpers.arrayElement([
'BROADCAST_METHOD',
'CONTAINER_METHOD',
'BED_METHOD',
@@ -549,7 +548,7 @@ function fakeManagementPlan(defaultData = {}) {
return {
name: faker.lorem.words(),
notes: faker.lorem.words(),
- start_date: faker.date.past(),
+ start_date: faker.date.past().toISOString().split('T')[0],
...defaultData,
};
}
@@ -648,12 +647,12 @@ function fakeCropManagementPlan(defaultData = {}) {
estimated_revenue: faker.datatype.number(10000),
estimated_yield: faker.datatype.number(10000),
estimated_price_per_mass: faker.datatype.number(10000),
- seed_date: faker.date.past(),
- plant_date: faker.date.past(),
- germination_date: faker.date.past(),
- transplant_date: faker.date.past(),
- harvest_date: faker.date.future(),
- termination_date: faker.date.future(),
+ seed_date: faker.date.past().toISOString().split('T')[0],
+ plant_date: faker.date.past().toISOString().split('T')[0],
+ germination_date: faker.date.past().toISOString().split('T')[0],
+ transplant_date: faker.date.past().toISOString().split('T')[0],
+ harvest_date: faker.date.future().toISOString().split('T')[0],
+ termination_date: faker.date.future().toISOString().split('T')[0],
already_in_ground: faker.datatype.boolean(),
is_seed: faker.datatype.boolean(),
needs_transplant: faker.datatype.boolean(),
@@ -728,7 +727,7 @@ async function planting_management_planFactory(
function fakePlantingManagementPlan(defaultData = {}) {
return {
is_final_planting_management_plan: faker.datatype.boolean(),
- planting_method: faker.random.arrayElement([
+ planting_method: faker.helpers.arrayElement([
'BROADCAST_METHOD',
'CONTAINER_METHOD',
'BED_METHOD',
@@ -1016,11 +1015,11 @@ function fakeCropVariety(defaultData = {}) {
return {
crop_variety_name: faker.lorem.word(),
supplier: faker.lorem.word(),
- seeding_type: faker.random.arrayElement(['SEED', 'SEEDLING_OR_PLANTING_STOCK']),
- lifecycle: faker.random.arrayElement(['ANNUAL', 'PERENNIAL']),
+ seeding_type: faker.helpers.arrayElement(['SEED', 'SEEDLING_OR_PLANTING_STOCK']),
+ lifecycle: faker.helpers.arrayElement(['ANNUAL', 'PERENNIAL']),
compliance_file_url: faker.internet.url(),
organic: faker.datatype.boolean(),
- treated: faker.random.arrayElement(['YES', 'NO', 'NOT_SURE']),
+ treated: faker.helpers.arrayElement(['YES', 'NO', 'NOT_SURE']),
genetically_engineered: faker.datatype.boolean(),
searched: faker.datatype.boolean(),
protein: faker.datatype.number(10),
@@ -1055,7 +1054,7 @@ function fakeCropVariety(defaultData = {}) {
transplant_days: faker.datatype.number({ min: 11, max: 20 }),
harvest_days: faker.datatype.number({ min: 21, max: 30 }),
termination_days: faker.datatype.number({ min: 31, max: 40 }),
- planting_method: faker.random.arrayElement([
+ planting_method: faker.helpers.arrayElement([
'BROADCAST_METHOD',
'CONTAINER_METHOD',
'BED_METHOD',
@@ -1108,9 +1107,9 @@ async function taskFactory(
function fakeTask(defaultData = {}) {
return {
- due_date: faker.date.future(),
+ due_date: faker.date.future().toISOString().split('T')[0],
notes: faker.lorem.words(),
- happiness: faker.random.arrayElement([0, 1, 2, 3, 4, 5]),
+ happiness: faker.helpers.arrayElement([0, 1, 2, 3, 4, 5]),
...defaultData,
};
}
@@ -1129,8 +1128,8 @@ function fakeProduct(defaultData = {}) {
return {
name: faker.lorem.words(2),
supplier: faker.lorem.words(3),
- on_permitted_substances_list: faker.random.arrayElement(['YES', 'NO', 'NOT_SURE']),
- type: faker.random.arrayElement(['soil_amendment_task', 'pest_control_task', 'cleaning_task']),
+ on_permitted_substances_list: faker.helpers.arrayElement(['YES', 'NO', 'NOT_SURE']),
+ type: faker.helpers.arrayElement(['soil_amendment_task', 'pest_control_task', 'cleaning_task']),
...defaultData,
};
}
@@ -1150,7 +1149,7 @@ async function soil_amendment_taskFactory(
function fakeSoilAmendmentTask(defaultData = {}) {
return {
product_quantity: faker.datatype.number(),
- purpose: faker.random.arrayElement([
+ purpose: faker.helpers.arrayElement([
'structure',
'moisture_retention',
'nutrient_availability',
@@ -1379,7 +1378,7 @@ function fakeDisease(defaultData = {}) {
return {
disease_scientific_name: faker.lorem.words(),
disease_common_name: faker.lorem.words(),
- disease_group: faker.random.arrayElement([
+ disease_group: faker.helpers.arrayElement([
'Fungus',
'Insect',
'Bacteria',
@@ -1413,7 +1412,7 @@ function fakePestControlTask(defaultData = {}) {
return {
product_quantity: faker.datatype.number(2000),
pest_target: faker.lorem.words(2),
- control_method: faker.random.arrayElement([
+ control_method: faker.helpers.arrayElement([
'systemicSpray',
'foliarSpray',
'handWeeding',
@@ -1493,13 +1492,26 @@ function fakePlantTask(defaultData = {}) {
}
async function transplant_taskFactory(
- { promisedTask = taskFactory() } = {},
+ {
+ promisedTask = taskFactory(),
+ promisedMgtPlan = planting_management_planFactory(),
+ promisedPrevMgtPlan = planting_management_planFactory(),
+ } = {},
transplant_task = fakePlantTask(),
) {
- const [activity] = await Promise.all([promisedTask]);
+ const [
+ activity,
+ [{ planting_management_plan_id }],
+ [{ planting_management_plan_id: prev_planting_management_plan_id }],
+ ] = await Promise.all([promisedTask, promisedMgtPlan, promisedPrevMgtPlan]);
const [{ task_id }] = activity;
return knex('transplant_task')
- .insert({ task_id, ...transplant_task })
+ .insert({
+ task_id,
+ planting_management_plan_id,
+ prev_planting_management_plan_id,
+ ...transplant_task,
+ })
.returning('*');
}
@@ -1522,7 +1534,7 @@ async function field_work_taskFactory(
function fakeFieldWorkTask(defaultData = {}) {
return {
- type: faker.random.arrayElement([
+ type: faker.helpers.arrayElement([
'COVERING_SOIL',
'FENCING',
'PREPARING_BEDS_OR_ROWS',
@@ -1547,7 +1559,7 @@ async function soil_taskFactory({ promisedTask = taskFactory() } = {}, soil_task
function fakeSoilTask(defaultData = {}) {
return {
- texture: faker.random.arrayElement([
+ texture: faker.helpers.arrayElement([
'sand',
'loamySand',
'sandyLoam',
@@ -1581,7 +1593,7 @@ function fakeSoilTask(defaultData = {}) {
c: faker.datatype.number(1000),
na: faker.datatype.number(1000),
total_carbon: faker.datatype.number(1000),
- depth_cm: faker.random.arrayElement(['5', '10', '20', '30', '50', '100']),
+ depth_cm: faker.helpers.arrayElement(['5', '10', '20', '30', '50', '100']),
...defaultData,
};
}
@@ -1599,7 +1611,7 @@ async function irrigation_taskFactory(
function fakeIrrigationTask(defaultData = {}) {
return {
- type: faker.random.arrayElement(['sprinkler', 'drip', 'subsurface', 'flood']),
+ type: faker.helpers.arrayElement(['sprinkler', 'drip', 'subsurface', 'flood']),
hours: faker.datatype.number(10),
'flow_rate_l/min': faker.datatype.number(10),
...defaultData,
@@ -1619,7 +1631,7 @@ async function scouting_taskFactory(
function fakeScoutingTask(defaultData = {}) {
return {
- type: faker.random.arrayElement(['harvest', 'pest', 'disease', 'weed', 'other']),
+ type: faker.helpers.arrayElement(['harvest', 'pest', 'disease', 'weed', 'other']),
...defaultData,
};
}
@@ -1635,8 +1647,8 @@ async function shiftFactory({ promisedUserFarm = userFarmFactory() } = {}, shift
function fakeShift(defaultData = {}) {
return {
- shift_date: new Date(),
- mood: faker.random.arrayElement(['happy', 'neutral', 'very happy', 'sad', 'very sad', 'na']),
+ shift_date: new Date().toISOString().split('T')[0],
+ mood: faker.helpers.arrayElement(['happy', 'neutral', 'very happy', 'sad', 'very sad', 'na']),
wage_at_moment: faker.datatype.number(20),
...defaultData,
};
@@ -1700,7 +1712,6 @@ function fakeSale(defaultData = {}) {
...defaultData,
};
}
-
function fakeExpenseType(defaultData = {}) {
return {
expense_name: faker.finance.transactionType(),
@@ -1717,16 +1728,16 @@ function fakeWaterBalance(defaultData = {}) {
};
}
-async function waterBalanceFactory(
- { promisedManagementPlan = management_planFactory() } = {},
- waterBalance = fakeWaterBalance(),
-) {
- const [managementPlan] = await Promise.all([promisedManagementPlan]);
- const [{ field_id, crop_id }] = managementPlan;
- return knex('waterBalance')
- .insert({ field_id, crop_id, ...waterBalance })
- .returning('*');
-}
+// async function waterBalanceFactory(
+// { promisedManagementPlan = management_planFactory() } = {},
+// waterBalance = fakeWaterBalance(),
+// ) {
+// const [managementPlan] = await Promise.all([promisedManagementPlan]);
+// const [{ field_id, crop_id }] = managementPlan;
+// return knex('waterBalance')
+// .insert({ field_id, crop_id, ...waterBalance })
+// .returning('*');
+// }
function fakeNitrogenSchedule(defaultData = {}) {
return {
@@ -1752,7 +1763,7 @@ function fakeCropVarietySale(defaultData = {}) {
return {
sale_value: faker.datatype.number(1000),
quantity: faker.datatype.number(1000),
- quantity_unit: faker.random.arrayElement(['kg', 'mt', 'lb', 't']),
+ quantity_unit: faker.helpers.arrayElement(['kg', 'mt', 'lb', 't']),
...defaultData,
};
}
@@ -1780,9 +1791,9 @@ function fakeSupportTicket(farm_id, defaultData = {}) {
}
return {
- support_type: faker.random.arrayElement(support_type),
- contact_method: faker.random.arrayElement(contact_method),
- status: faker.random.arrayElement(status),
+ support_type: faker.helpers.arrayElement(support_type),
+ contact_method: faker.helpers.arrayElement(contact_method),
+ status: faker.helpers.arrayElement(status),
message: faker.lorem.paragraphs(),
attachments,
email: faker.internet.email(),
@@ -1816,8 +1827,8 @@ function fakeOrganicCertifierSurvey(farm_id, defaultData = {}) {
const past = faker.date.past();
const now = new Date();
return {
- certifier_id: faker.random.arrayElement(certifierIDS),
- certification_id: faker.random.arrayElement(certificationIDS),
+ certifier_id: faker.helpers.arrayElement(certifierIDS),
+ certification_id: faker.helpers.arrayElement(certificationIDS),
created_at: past,
updated_at: faker.date.between(past, now),
interested: faker.datatype.boolean(),
@@ -1892,7 +1903,7 @@ async function greenhouseFactory(
function fakeGreenhouse(defaultData = {}) {
return {
- organic_status: faker.random.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
+ organic_status: faker.helpers.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
...defaultData,
};
}
@@ -1934,13 +1945,13 @@ async function water_valveFactory(
function fakeWaterValve(defaultData = {}) {
return {
- source: faker.random.arrayElement([
+ source: faker.helpers.arrayElement([
'Municipal water',
'Surface water',
'Groundwater',
'Rain water',
]),
- flow_rate_unit: faker.random.arrayElement(['l/min', 'l/h', 'gal/min', 'gal/h']),
+ flow_rate_unit: faker.helpers.arrayElement(['l/min', 'l/h', 'gal/min', 'gal/h']),
flow_rate: faker.datatype.number(1000),
...defaultData,
};
@@ -1990,7 +2001,7 @@ async function baseArea(
promisedArea = areaFactory({ promisedLocation }, fakeArea(), asset),
} = {},
) {
- const [location, area] = await Promise.all([promisedLocation, promisedArea]);
+ const [location] = await Promise.all([promisedLocation, promisedArea]);
const [{ location_id }] = location;
return knex(asset).insert({ location_id }).returning('*');
}
@@ -2070,9 +2081,9 @@ function fakeDocument(defaultData = {}) {
return {
name: faker.lorem.words(),
thumbnail_url: faker.image.imageUrl(),
- valid_until: faker.date.future(),
+ valid_until: faker.date.future().toISOString().split('T')[0],
notes: faker.lorem.words(),
- type: faker.random.arrayElement([
+ type: faker.helpers.arrayElement([
'CLEANING_PRODUCT',
'CROP_COMPLIANCE',
'FERTILIZING_PRODUCT',
@@ -2108,6 +2119,56 @@ function fakeFile(defaultData = {}) {
};
}
+async function notification_userFactory(
+ { promisedUserFarm = userFarmFactory() } = {},
+ notificationUser = fakeNotificationUser(),
+ notification = fakeNotification(),
+) {
+ const [userFarm] = await Promise.all([promisedUserFarm]);
+ const [{ user_id, farm_id }] = userFarm;
+ const [{ notification_id }] = await knex('notification')
+ .insert({ ...notification, farm_id })
+ .returning('*');
+
+ return await knex('notification_user')
+ .insert({
+ ...notificationUser,
+ notification_id,
+ user_id,
+ })
+ .returning('*');
+}
+
+function fakeNotificationUser(defaultData = {}) {
+ return {
+ notification_id: faker.datatype.uuid(),
+ user_id: faker.datatype.uuid(),
+ alert: true,
+ status: 'Unread',
+ created_at: faker.date.past(),
+ updated_at: faker.date.past(),
+ ...defaultData,
+ };
+}
+
+function fakeNotification(defaultData = {}) {
+ const notification_id = faker.datatype.uuid();
+ return {
+ notification_id,
+ title: { translation_key: `title_translation_key of notification ${notification_id}` },
+ body: { translation_key: `body_translation_key of notification ${notification_id}` },
+ variables: [],
+ ref: {
+ entity: { id: faker.datatype.uuid(), type: `entity_type of notification ${notification_id}` },
+ },
+ context: {},
+ farm_id: faker.datatype.uuid(),
+ created_at: faker.date.past(),
+ updated_at: faker.date.past(),
+ ...defaultData,
+ };
+}
+
module.exports = {
weather_stationFactory,
fakeStation,
@@ -2238,5 +2299,6 @@ module.exports = {
fileFactory,
fakeOrganicHistory,
organic_historyFactory,
+ notification_userFactory,
baseProperties,
};
diff --git a/packages/api/tests/notificationUser.test.js b/packages/api/tests/notificationUser.test.js
new file mode 100644
index 0000000000..aff8af19e3
--- /dev/null
+++ b/packages/api/tests/notificationUser.test.js
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const chai = require('chai');
+const chaiHttp = require('chai-http');
+chai.use(chaiHttp);
+const server = require('./../src/server');
+const knex = require('../src/util/knex');
+const { tableCleanup } = require('./testEnvironment');
+jest.mock('jsdom');
+jest.mock('../src/middleware/acl/checkJwt');
+const mocks = require('./mock.factories');
+
+describe('Notification tests', () => {
+ function getRequest(url, { user_id = user.user_id, farm_id = farm.farm_id }, callback) {
+ chai.request(server).get(url).set('user_id', user_id).set('farm_id', farm_id).end(callback);
+ }
+
+ let user;
+ let farm;
+ let userFarm;
+
+ beforeEach(async () => {
+ [user] = await mocks.usersFactory();
+ [farm] = await mocks.farmFactory();
+ [userFarm] = await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm] });
+
+ const middleware = require('../src/middleware/acl/checkJwt');
+ middleware.mockImplementation((req, res, next) => {
+ req.user = {};
+ req.user.user_id = req.get('user_id');
+ next();
+ });
+ });
+
+ afterAll(async (done) => {
+ await tableCleanup(knex);
+ await knex.destroy();
+ done();
+ });
+
+ describe('GET user notifications', () => {
+ test('Users should get their notifications scoped for all farms', async (done) => {
+ const [notification] = await mocks.notification_userFactory({
+ promisedUserFarm: [userFarm],
+ });
+ getRequest('/notification_user', {}, (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(1);
+ expect(res.body[0].user_id).toBe(user.user_id);
+ expect(res.body[0].notification_id).toBe(notification.notification_id);
+ done();
+ });
+ });
+
+ test('Users should get their notifications scoped for their current farm', async (done) => {
+ const [notification] = await mocks.notification_userFactory({
+ promisedUserFarm: [userFarm],
+ });
+ getRequest('/notification_user', {}, (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(1);
+ expect(res.body[0].user_id).toBe(user.user_id);
+ expect(res.body[0].notification_id).toBe(notification.notification_id);
+ done();
+ });
+ });
+
+ test('Users should not get their notifications scoped for farms other than their current farm', async (done) => {
+ const [otherFarm] = await mocks.farmFactory();
+ const [otherUserFarm] = await mocks.userFarmFactory({
+ promisedUser: [user],
+ promisedFarm: [otherFarm],
+ });
+ await mocks.notification_userFactory({
+ promisedUserFarm: [otherUserFarm],
+ });
+ getRequest('/notification_user', {}, (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Users are not authorized to get "their" notifications for farms where they are not active', async (done) => {
+ const [inactiveFarm] = await mocks.farmFactory();
+ const [inactiveUserFarm] = await mocks.userFarmFactory(
+ { promisedUser: [user], promisedFarm: [inactiveFarm] },
+ (userFarm = mocks.fakeUserFarm({ status: 'Inactive' })),
+ );
+ await mocks.notification_userFactory({
+ promisedUserFarm: [inactiveUserFarm],
+ });
+ getRequest('/notification_user', { farm_id: inactiveFarm.farm_id }, (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(403);
+ done();
+ });
+ });
+ });
+
+ describe('PATCH user notifications', () => {
+ function clearAlerts(
+ notificationIds,
+ { user_id = user.user_id, farm_id = farm.farm_id },
+ callback,
+ ) {
+ chai
+ .request(server)
+ .patch('/notification_user/clear_alerts')
+ .set('user_id', user_id)
+ .set('farm_id', farm_id)
+ .send(notificationIds)
+ .end(callback);
+ }
+
+ function setStatus(body, { user_id = user.user_id, farm_id = farm.farm_id }, callback) {
+ chai
+ .request(server)
+ .patch('/notification_user')
+ .set('user_id', user_id)
+ .set('farm_id', farm_id)
+ .send(body)
+ .end(callback);
+ }
+
+ test('Users can clear alert flag on a set of their notifications', async (done) => {
+ const [notification] = await mocks.notification_userFactory({
+ promisedUserFarm: [userFarm],
+ });
+ expect(notification.alert).toBe(true);
+ clearAlerts({ notification_ids: [notification.notification_id] }, {}, (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(200);
+ getRequest('/notification_user', {}, (_, res) => {
+ expect(res.body[0].alert).toBe(false);
+ done();
+ });
+ });
+ });
+
+ test('Users can modify the status for a set of their notifications', async (done) => {
+ const [notification] = await mocks.notification_userFactory({
+ promisedUserFarm: [userFarm],
+ });
+ expect(notification.status).toBe('Unread');
+ const newStatus = 'Read';
+ setStatus(
+ { notification_ids: [notification.notification_id], status: newStatus },
+ {},
+ (err, res) => {
+ expect(err).toBe(null);
+ expect(res.status).toBe(200);
+ getRequest('/notification_user', {}, (_, res) => {
+ expect(res.body[0].status).toBe(newStatus);
+ done();
+ });
+ },
+ );
+ });
+ });
+});
diff --git a/packages/api/tests/organicCertifierSurvey.test.js b/packages/api/tests/organicCertifierSurvey.test.js
index b5a2fd7575..1e3c31a914 100644
--- a/packages/api/tests/organicCertifierSurvey.test.js
+++ b/packages/api/tests/organicCertifierSurvey.test.js
@@ -16,7 +16,7 @@
const chai = require('chai');
const chaiHttp = require('chai-http');
const moment = require('moment');
-const faker = require('faker');
+const { faker } = require('@faker-js/faker');
chai.use(chaiHttp);
const server = require('./../src/server');
const knex = require('../src/util/knex');
@@ -843,7 +843,6 @@ describe('organic certification Tests', () => {
const fakeTask = mocks.fakeTask({
owner_user_id: user_id,
assignee_user_id: user_id,
- planned_time: faker.date.future(),
due_date: faker.date.future(),
...options,
});
@@ -910,7 +909,7 @@ describe('organic certification Tests', () => {
transplant_task: { plant_task: true, in_ground: true, transplant_task: true },
},
title: 'completed on report start date',
- options: { completed_time: `'${JUNE01}${START_OF_DAY}'` },
+ options: { complete_date: `'${JUNE01}${START_OF_DAY}'` },
},
{
include: {
@@ -920,7 +919,7 @@ describe('organic certification Tests', () => {
transplant_task: { plant_task: true, in_ground: true, transplant_task: true },
},
title: 'completed on report end date',
- options: { completed_time: `'${JUNE30}${END_OF_DAY}'` },
+ options: { complete_date: `'${JUNE30}${END_OF_DAY}'` },
},
{
include: {
@@ -950,7 +949,7 @@ describe('organic certification Tests', () => {
transplant_task: { plant_task: false, in_ground: false, transplant_task: true },
},
title: 'completed just before the report start date',
- options: { completed_time: `'${MAY31}${END_OF_DAY}'` },
+ options: { complete_date: `'${MAY31}${END_OF_DAY}'` },
},
{
include: {
@@ -960,7 +959,7 @@ describe('organic certification Tests', () => {
transplant_task: { plant_task: true, in_ground: true, transplant_task: false },
},
title: 'completed just after the report end date',
- options: { completed_time: `'${JULY01}${START_OF_DAY}'` },
+ options: { complete_date: `'${JULY01}${START_OF_DAY}'` },
},
{
include: {
@@ -1071,7 +1070,7 @@ describe('organic certification Tests', () => {
test(`Abandoned transplant tasks: should not include crops from abandoned transplant tasks ${scenario.title}`, async (done) => {
await createTransplantTask({
...scenario.options,
- abandoned_time: `'${JULY01}${START_OF_DAY}'`,
+ abandon_date: `'${JULY01}${START_OF_DAY}'`,
});
await createManagementTaskWithinReportingPeriod();
const recordA = await getRecordAWithManagementPlans(JUNE30, JUNE01, farm_id);
@@ -1135,7 +1134,7 @@ describe('organic certification Tests', () => {
test(`should not include crops from abandoned management tasks ${scenario.title}`, async (done) => {
await createManagementTask({
due_date: JUNE01,
- abandoned_time: `'${JULY01}${START_OF_DAY}'`,
+ abandon_date: `'${JULY01}${START_OF_DAY}'`,
});
const recordA = await getRecordAWithManagementPlans(JUNE30, JUNE01, farm_id);
expect(recordA).toHaveLength(1);
@@ -1178,7 +1177,7 @@ describe('organic certification Tests', () => {
});
test(`Task after reporting period: should not include crops from in ground management plan location`, async (done) => {
- await createTask({ completed_time: `'${JULY01}${START_OF_DAY}'` });
+ await createTask({ complete_date: `'${JULY01}${START_OF_DAY}'` });
const recordA = await getRecordAWithManagementPlans(JUNE30, JUNE01, farm_id);
expect(recordA).toHaveLength(1);
expect(recordA[0].crops).toHaveLength(0);
@@ -1186,7 +1185,7 @@ describe('organic certification Tests', () => {
});
test(`Reporting period between two tasks: should include crops from in ground management plan location`, async (done) => {
- await createManagementTask({ completed_time: `'${MAY31}${START_OF_DAY}'` });
+ await createManagementTask({ complete_date: `'${MAY31}${START_OF_DAY}'` });
await createManagementTask({ due_date: JULY01 });
const recordA = await getRecordAWithManagementPlans(JUNE30, JUNE01, farm_id);
expect(recordA).toHaveLength(1);
@@ -1234,7 +1233,7 @@ describe('organic certification Tests', () => {
test('should exclude plant location when there are transplant tasks before start date', async (done) => {
await createPlantTask({ due_date: JUNE01 });
await createTransplantTask({ due_date: MAY31 });
- await createTransplantTask({ completed_time: JUNE01 });
+ await createTransplantTask({ complete_date: JUNE01 });
await createTransplantTask({ due_date: JUNE15 });
const recordA = await getRecordAWithManagementPlans(JUNE30, JUNE01, farm_id);
expect(recordA).toHaveLength(4);
@@ -1286,7 +1285,7 @@ describe('organic certification Tests', () => {
);
await createTransplantTask(
- { completed_time: `'${JUNE30}${START_OF_DAY}` },
+ { complete_date: `'${JUNE30}${START_OF_DAY}` },
{ management_plan_id },
);
@@ -1296,7 +1295,7 @@ describe('organic certification Tests', () => {
.insert({ management_plan_id, location_id: location.location_id })
.returning('*');
- const task_id = await createTask({ completed_time: `'${JUNE01}${START_OF_DAY}` });
+ const task_id = await createTask({ complete_date: `'${JUNE01}${START_OF_DAY}` });
await mocks.plant_taskFactory(
{ promisedTask: [{ task_id }] },
{ planting_management_plan_id },
diff --git a/packages/api/tests/organicHistory.test.js b/packages/api/tests/organicHistory.test.js
index dab2ecd792..0db090adda 100644
--- a/packages/api/tests/organicHistory.test.js
+++ b/packages/api/tests/organicHistory.test.js
@@ -27,7 +27,9 @@ const locationModel = require('../src/models/locationModel');
describe('Location organic history tests', () => {
function postRequest(data, farm_id, user_id, callback) {
- chai.request(server).post(`/location/organic_history`)
+ chai
+ .request(server)
+ .post(`/location/organic_history`)
.set('Content-Type', 'application/json')
.set('farm_id', farm_id)
.set('user_id', user_id)
@@ -36,7 +38,7 @@ describe('Location organic history tests', () => {
}
function fakeUserFarm(role = 1) {
- return ({ ...mocks.fakeUserFarm(), role_id: role });
+ return { ...mocks.fakeUserFarm(), role_id: role };
}
let owner;
@@ -46,10 +48,13 @@ describe('Location organic history tests', () => {
beforeEach(async () => {
[owner] = await mocks.usersFactory();
[farm] = await mocks.farmFactory();
- await mocks.userFarmFactory({
- promisedUser: [owner],
- promisedFarm: [farm],
- }, fakeUserFarm(1));
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [owner],
+ promisedFarm: [farm],
+ },
+ fakeUserFarm(1),
+ );
[location] = await mocks.locationFactory({ promisedFarm: [farm] });
const middleware = require('../src/middleware/acl/checkJwt');
@@ -58,7 +63,7 @@ describe('Location organic history tests', () => {
req.user.user_id = req.get('user_id');
next();
});
- })
+ });
afterAll(async (done) => {
await tableCleanup(knex);
@@ -67,42 +72,38 @@ describe('Location organic history tests', () => {
});
describe('POST to create a new organic history entry', () => {
- ['field', 'garden', 'greenhouse'].map(type => {
+ ['field', 'garden', 'greenhouse'].map((type) => {
test(`works for ${type}`, async (done) => {
const something = await mocks[`${type}Factory`]({
promisedLocation: [location],
});
- const organicHistoryReqBody = mocks.fakeOrganicHistory({ location_id: location.location_id });
- postRequest(
- organicHistoryReqBody,
- farm.farm_id, owner.user_id,
- async (err, res) => {
- expect(res.status).toBe(201);
- const organicHistory = await knex('organic_history').where({ location_id: location.location_id }).first();
- expect(organicHistory.organic_status).toBe(organicHistoryReqBody.organic_status);
- done();
- });
+ const organicHistoryReqBody = mocks.fakeOrganicHistory({
+ location_id: location.location_id,
+ });
+ postRequest(organicHistoryReqBody, farm.farm_id, owner.user_id, async (err, res) => {
+ expect(res.status).toBe(201);
+ const organicHistory = await knex('organic_history')
+ .where({ location_id: location.location_id })
+ .first();
+ expect(organicHistory.organic_status).toBe(organicHistoryReqBody.organic_status);
+ done();
+ });
});
});
- ['buffer_zone', 'gate', 'barn'].map(type => {
+ ['buffer_zone', 'gate', 'barn'].map((type) => {
test(`works for ${type}`, async (done) => {
const something = await mocks[`${type}Factory`]({
promisedLocation: [location],
});
- const organicHistoryReqBody = mocks.fakeOrganicHistory({ location_id: location.location_id });
- postRequest(
- organicHistoryReqBody,
- farm.farm_id, owner.user_id,
- async (err, res) => {
- expect(res.status).toBe(400);
- done();
- });
+ const organicHistoryReqBody = mocks.fakeOrganicHistory({
+ location_id: location.location_id,
+ });
+ postRequest(organicHistoryReqBody, farm.farm_id, owner.user_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
});
});
-
-
});
});
-
-/* global jest describe test expect beforeEach afterAll */
diff --git a/packages/api/tests/task.test.js b/packages/api/tests/task.test.js
index 2addb8255d..fde9cd7557 100644
--- a/packages/api/tests/task.test.js
+++ b/packages/api/tests/task.test.js
@@ -7,9 +7,7 @@ jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
const mocks = require('./mock.factories');
const { tableCleanup } = require('./testEnvironment');
-const moment = require('moment');
-let faker = require('faker');
-
+const { faker } = require('@faker-js/faker');
describe('Task tests', () => {
let middleware;
@@ -22,8 +20,24 @@ describe('Task tests', () => {
});
});
+ /**
+ * Converts a given Date to the local date in ISO-8601 extended format (YYYY-MM-DD).
+ * Date.prototype.toISOString() returns the same format of the UTC (not local) date.
+ * @param {Date} date - The date to be converted.
+ * @returns {string} The input's local date in YYYY-MM-DD format.
+ */
+ function toLocal8601Extended(date) {
+ return (
+ `${date.getFullYear()}-` +
+ `${(date.getMonth() + 1).toString().padStart(2, '0')}-` +
+ `${date.getDate().toString().padStart(2, '0')}`
+ );
+ }
+
function assignTaskRequest({ user_id, farm_id }, data, task_id, callback) {
- chai.request(server).patch(`/task/assign/${task_id}`)
+ chai
+ .request(server)
+ .patch(`/task/assign/${task_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -31,7 +45,9 @@ describe('Task tests', () => {
}
function postTaskRequest({ user_id, farm_id }, type, data, callback) {
- chai.request(server).post(`/task/${type}`)
+ chai
+ .request(server)
+ .post(`/task/${type}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -39,7 +55,9 @@ describe('Task tests', () => {
}
function postHarvestTasksRequest({ user_id, farm_id }, data, callback) {
- chai.request(server).post(`/task/harvest_tasks`)
+ chai
+ .request(server)
+ .post('/task/harvest_tasks')
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -47,7 +65,9 @@ describe('Task tests', () => {
}
function postTransplantTaskRequest({ user_id, farm_id }, data, callback) {
- chai.request(server).post(`/task/transplant_task`)
+ chai
+ .request(server)
+ .post('/task/transplant_task')
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -55,21 +75,37 @@ describe('Task tests', () => {
}
function getTasksRequest({ user_id, farm_id }, callback) {
- chai.request(server).get(`/task/${farm_id}`)
+ chai
+ .request(server)
+ .get(`/task/${farm_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.end(callback);
}
function getHarvestUsesRequest({ user_id, farm_id }, callback) {
- chai.request(server).get(`/task/harvest_uses/farm/${farm_id}`)
+ chai
+ .request(server)
+ .get(`/task/harvest_uses/farm/${farm_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.end(callback);
}
function assignAllTasksOnDateRequest({ user_id, farm_id }, data, task_id, callback) {
- chai.request(server).patch(`/task/assign_all_tasks_on_date/${task_id}`)
+ chai
+ .request(server)
+ .patch(`/task/assign_all_tasks_on_date/${task_id}`)
+ .set('user_id', user_id)
+ .set('farm_id', farm_id)
+ .send(data)
+ .end(callback);
+ }
+
+ function patchTaskDateRequest({ user_id, farm_id }, data, task_id, callback) {
+ chai
+ .request(server)
+ .patch(`/task/patch_due_date/${task_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -77,7 +113,9 @@ describe('Task tests', () => {
}
function completeTaskRequest({ user_id, farm_id }, data, task_id, type, callback) {
- chai.request(server).patch(`/task/complete/${type}/${task_id}`)
+ chai
+ .request(server)
+ .patch(`/task/complete/${type}/${task_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -85,7 +123,9 @@ describe('Task tests', () => {
}
function abandonTaskRequest({ user_id, farm_id }, data, task_id, callback) {
- chai.request(server).patch(`/task/abandon/${task_id}`)
+ chai
+ .request(server)
+ .patch(`/task/abandon/${task_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
@@ -93,10 +133,9 @@ describe('Task tests', () => {
}
function fakeUserFarm(role = 1) {
- return ({ ...mocks.fakeUserFarm(), role_id: role });
+ return { ...mocks.fakeUserFarm(), role_id: role };
}
-
async function userFarmTaskGenerator(linkPlan = true) {
const userFarm = { ...fakeUserFarm(1), wage: { type: '', amount: 30 } };
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, userFarm);
@@ -104,20 +143,30 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [{ crop_variety_id }] = await mocks.crop_varietyFactory({ promisedFarm: [{ farm_id }] });
- const [{ management_plan_id }] = linkPlan ? await mocks.crop_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- crop_variety: [{ crop_variety_id }],
- }) : [{ management_plan_id: null }];
- const [{ planting_management_plan_id }] = linkPlan ? await knex('planting_management_plan').where({ management_plan_id }) : [{ planting_management_plan_id: null }];
- return { user_id, farm_id, location_id, management_plan_id, planting_management_plan_id, task_type_id };
+ const [{ management_plan_id }] = linkPlan
+ ? await mocks.crop_management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ crop_variety: [{ crop_variety_id }],
+ })
+ : [{ management_plan_id: null }];
+ const [{ planting_management_plan_id }] = linkPlan
+ ? await knex('planting_management_plan').where({ management_plan_id })
+ : [{ planting_management_plan_id: null }];
+ return {
+ user_id,
+ farm_id,
+ location_id,
+ management_plan_id,
+ planting_management_plan_id,
+ task_type_id,
+ };
}
async function getTask(task_id) {
return knex('task').where({ task_id }).first();
}
-
afterAll(async (done) => {
await tableCleanup(knex);
await knex.destroy();
@@ -130,12 +179,43 @@ describe('Task tests', () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, userFarm);
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task = await getTask(task_id);
- // expect(updated_task.wage_at_moment).toBe(30);
- expect(updated_task.assignee_user_id).toBe(user_id);
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ // expect(updated_task.wage_at_moment).toBe(30);
+ expect(updated_task.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
+ });
+
+ test('Should not be able to assign tasks to Inactive users', async (done) => {
+ const userFarm = { ...fakeUserFarm(1), wage: { type: '', amount: 30 } };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, userFarm);
+ const [{ user_id: assignee_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ {
+ ...userFarm,
+ status: 'Inactive',
+ },
+ );
+
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+ assignTaskRequest({ user_id, farm_id }, { assignee_user_id }, task_id, async (err, res) => {
+ expect(res.status).toBe(400);
done();
});
});
@@ -144,167 +224,299 @@ describe('Task tests', () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task = await getTask(task_id);
- expect(updated_task.assignee_user_id).toBe(user_id);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(updated_task.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('EO should be able to assign person to task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task = await getTask(task_id);
- expect(updated_task.assignee_user_id).toBe(user_id);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(updated_task.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('Worker should be able to assign self to task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task = await getTask(task_id);
- expect(updated_task.assignee_user_id).toBe(user_id);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(updated_task.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('Worker should not be able to assign another person to task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: other_user_id }, task_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: other_user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
+ });
+
+ test('Farm worker should not be able to re-assign a task assigned to another person', async (done) => {
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
+ const [{ user_id: admin_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(1),
+ );
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
+ const fakeTask = mocks.fakeTask({
+ owner_user_id: admin_user_id,
+ assignee_user_id: other_user_id,
+ });
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, fakeTask);
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Should not be able to re-assign completed tasks', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: another_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(2));
+ const [{ user_id: another_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(2),
+ );
const fakeTask = mocks.fakeTask({
assignee_user_id: user_id,
- completed_time: faker.date.future(),
+ complete_date: faker.date.future(),
});
- const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, task = fakeTask);
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, fakeTask);
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: another_id }, task_id, async (err, res) => {
- expect(res.status).toBe(406);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: another_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('Should not be able to re-assign abandoned tasks', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: another_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(2));
+ const [{ user_id: another_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(2),
+ );
const fakeTask = mocks.fakeTask({
assignee_user_id: user_id,
- abandoned_time: faker.date.future(),
+ abandon_date: faker.date.future(),
});
- const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, task = fakeTask);
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, fakeTask);
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: another_id }, task_id, async (err, res) => {
- expect(res.status).toBe(406);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
+ assignTaskRequest(
+ { user_id, farm_id },
+ { assignee_user_id: another_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('Owner should be able to assign person to multiple tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const task_1_id = task_1.task_id;
const task_2_id = task_2.task_id;
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: user_id,
- date: date,
- }, task_1_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task_1 = await getTask(task_1_id);
- const updated_task_2 = await getTask(task_2_id);
- expect(updated_task_1.assignee_user_id).toBe(user_id);
- expect(updated_task_2.assignee_user_id).toBe(user_id);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: user_id,
+ date,
+ },
+ task_1_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task_1 = await getTask(task_1_id);
+ const updated_task_2 = await getTask(task_2_id);
+ expect(updated_task_1.assignee_user_id).toBe(user_id);
+ expect(updated_task_2.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('Manager should be able to assign person to multiple tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const task_1_id = task_1.task_id;
const task_2_id = task_2.task_id;
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: user_id,
- date: date,
- }, task_1_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task_1 = await getTask(task_1_id);
- const updated_task_2 = await getTask(task_2_id);
- expect(updated_task_1.assignee_user_id).toBe(user_id);
- expect(updated_task_2.assignee_user_id).toBe(user_id);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: user_id,
+ date,
+ },
+ task_1_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task_1 = await getTask(task_1_id);
+ const updated_task_2 = await getTask(task_2_id);
+ expect(updated_task_1.assignee_user_id).toBe(user_id);
+ expect(updated_task_2.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('EO should be able to assign person to multiple tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const task_1_id = task_1.task_id;
const task_2_id = task_2.task_id;
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: user_id,
- date,
- }, task_1_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task_1 = await getTask(task_1_id);
- const updated_task_2 = await getTask(task_2_id);
- expect(updated_task_1.assignee_user_id).toBe(user_id);
- expect(updated_task_2.assignee_user_id).toBe(user_id);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: user_id,
+ date,
+ },
+ task_1_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task_1 = await getTask(task_1_id);
+ const updated_task_2 = await getTask(task_2_id);
+ expect(updated_task_1.assignee_user_id).toBe(user_id);
+ expect(updated_task_2.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('should be able to assign a person to multiple tasks without an assignee on a date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
- const [{ user_id: another_user }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] });
+ const [{ user_id: another_user }] = await mocks.userFarmFactory({
+ promisedFarm: [{ farm_id }],
+ });
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_3] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({
- due_date: date,
- assignee_user_id: another_user,
- }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_3] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({
+ due_date: date,
+ assignee_user_id: another_user,
+ }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const task_1_id = task_1.task_id;
@@ -313,102 +525,264 @@ describe('Task tests', () => {
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
await mocks.location_tasksFactory({ promisedTask: [task_3], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: user_id,
- date,
- }, task_1_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task_1 = await getTask(task_1_id);
- const updated_task_2 = await getTask(task_2_id);
- const updated_task_3 = await getTask(task_3_id);
- expect(updated_task_1.assignee_user_id).toBe(user_id);
- expect(updated_task_2.assignee_user_id).toBe(user_id);
- expect(updated_task_3.assignee_user_id).toBe(another_user);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: user_id,
+ date,
+ },
+ task_1_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task_1 = await getTask(task_1_id);
+ const updated_task_2 = await getTask(task_2_id);
+ const updated_task_3 = await getTask(task_3_id);
+ expect(updated_task_1.assignee_user_id).toBe(user_id);
+ expect(updated_task_2.assignee_user_id).toBe(user_id);
+ expect(updated_task_3.assignee_user_id).toBe(another_user);
+ done();
+ },
+ );
});
test('Worker should be able to assign self to multiple tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const task_1_id = task_1.task_id;
const task_2_id = task_2.task_id;
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: user_id,
- date: date,
- }, task_1_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updated_task_1 = await getTask(task_1_id);
- const updated_task_2 = await getTask(task_2_id);
- expect(updated_task_1.assignee_user_id).toBe(user_id);
- expect(updated_task_2.assignee_user_id).toBe(user_id);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: user_id,
+ date,
+ },
+ task_1_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task_1 = await getTask(task_1_id);
+ const updated_task_2 = await getTask(task_2_id);
+ expect(updated_task_1.assignee_user_id).toBe(user_id);
+ expect(updated_task_2.assignee_user_id).toBe(user_id);
+ done();
+ },
+ );
});
test('Worker should not be able to assign other person to multiple tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
const date = faker.date.future().toISOString().split('T')[0];
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: other_user_id,
- date: date,
- }, task_1.task_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: other_user_id,
+ date,
+ },
+ task_1.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Should only re-assign multiple non-completed or abandoned tasks on date', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: another_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(2));
+ const [{ user_id: another_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(2),
+ );
const date = faker.date.future().toISOString().split('T')[0];
const fakeTask_completed = mocks.fakeTask({
- completed_time: faker.date.future(),
+ complete_date: faker.date.future(),
due_date: date,
});
const fakeTask_abandoned = mocks.fakeTask({
- abandoned_time: faker.date.future(),
+ abandon_date: faker.date.future(),
due_date: date,
});
- const [task_1] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [task_2] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
- const [completed_task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, task = fakeTask_completed);
- const [abandoned_task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, task = fakeTask_abandoned);
+ const [task_1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [task_2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
+ const [completed_task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ fakeTask_completed,
+ );
+ const [abandoned_task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ fakeTask_abandoned,
+ );
const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const [location_2] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task_1], promisedField: [location_1] });
await mocks.location_tasksFactory({ promisedTask: [task_2], promisedField: [location_2] });
- await mocks.location_tasksFactory({ promisedTask: [completed_task], promisedField: [location_1] });
- await mocks.location_tasksFactory({ promisedTask: [abandoned_task], promisedField: [location_2] });
- assignAllTasksOnDateRequest({ user_id, farm_id }, {
- assignee_user_id: another_id,
- date: date,
- }, task_1.task_id, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(2);
- const updated_task_1 = await getTask(task_1.task_id);
- const updated_task_2 = await getTask(task_2.task_id);
- expect(updated_task_1.assignee_user_id).toBe(another_id);
- expect(updated_task_2.assignee_user_id).toBe(another_id);
- const updated_completed_task = await getTask(completed_task.task_id);
- expect(updated_completed_task.assignee_user_id).toBe(null);
- const updated_abandoned_task = await getTask(abandoned_task.task_id);
- expect(updated_abandoned_task.assignee_user_id).toBe(null);
- done();
+ await mocks.location_tasksFactory({
+ promisedTask: [completed_task],
+ promisedField: [location_1],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [abandoned_task],
+ promisedField: [location_2],
+ });
+ assignAllTasksOnDateRequest(
+ { user_id, farm_id },
+ {
+ assignee_user_id: another_id,
+ date,
+ },
+ task_1.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(2);
+ const updated_task_1 = await getTask(task_1.task_id);
+ const updated_task_2 = await getTask(task_2.task_id);
+ expect(updated_task_1.assignee_user_id).toBe(another_id);
+ expect(updated_task_2.assignee_user_id).toBe(another_id);
+ const updated_completed_task = await getTask(completed_task.task_id);
+ expect(updated_completed_task.assignee_user_id).toBe(null);
+ const updated_abandoned_task = await getTask(abandoned_task.task_id);
+ expect(updated_abandoned_task.assignee_user_id).toBe(null);
+ done();
+ },
+ );
+ });
+
+ test('Farm owner should be able to reassign a task and assign all tasks on date', async (done) => {
+ const [{ user_id: ownerUserId, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
+ const [{ user_id: anotherUserId }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(2),
+ );
+
+ const date = faker.date.future().toISOString().split('T')[0];
+
+ const [assignedTask] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: ownerUserId }),
+ );
+ const [unassignedTask1] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: null }),
+ );
+ const [unassignedTask2] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: null }),
+ );
+
+ const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [assignedTask],
+ promisedField: [location_1],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [unassignedTask1],
+ promisedField: [location_1],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [unassignedTask2],
+ promisedField: [location_1],
+ });
+
+ assignAllTasksOnDateRequest(
+ { user_id: ownerUserId, farm_id },
+ { assignee_user_id: anotherUserId, date },
+ assignedTask.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const reassignedTask = await getTask(assignedTask.task_id);
+ const updatedTask1 = await getTask(unassignedTask1.task_id);
+ const updatedTask2 = await getTask(unassignedTask2.task_id);
+ expect(reassignedTask.assignee_user_id).toBe(anotherUserId);
+ expect(updatedTask1.assignee_user_id).toBe(anotherUserId);
+ expect(updatedTask2.assignee_user_id).toBe(anotherUserId);
+ done();
+ },
+ );
+ });
+
+ test('Farm worker should not be able to reassign a task and assign all tasks on date', async (done) => {
+ const [{ user_id: ownerUserId, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
+ const [{ user_id: workerUserId }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
+
+ const date = faker.date.future().toISOString().split('T')[0];
+
+ const [assignedTaskBefore] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: ownerUserId }),
+ );
+ const [unassignedTask1Before] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: null }),
+ );
+ const [unassignedTask2Before] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: ownerUserId }] },
+ mocks.fakeTask({ due_date: date, assignee_user_id: null }),
+ );
+
+ const [location_1] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [assignedTaskBefore],
+ promisedField: [location_1],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [unassignedTask1Before],
+ promisedField: [location_1],
});
+ await mocks.location_tasksFactory({
+ promisedTask: [unassignedTask2Before],
+ promisedField: [location_1],
+ });
+
+ assignAllTasksOnDateRequest(
+ { user_id: workerUserId, farm_id },
+ { assignee_user_id: workerUserId, date },
+ assignedTaskBefore.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ const assignedTaskAfter = await getTask(assignedTaskBefore.task_id);
+ const unassignedTask1After = await getTask(unassignedTask1Before.task_id);
+ const unassignedTask2After = await getTask(unassignedTask2Before.task_id);
+ expect(assignedTaskAfter.assignee_user_id).toBe(ownerUserId);
+ expect(unassignedTask1After.assignee_user_id).toBe(null);
+ expect(unassignedTask2After.assignee_user_id).toBe(null);
+ done();
+ },
+ );
});
});
@@ -420,29 +794,44 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
});
- await Promise.all([...Array(3)].map(async () => {
- const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- await mocks.harvest_taskFactory({ promisedTask: [{ task_id }] });
- const promisedHarvestUseTypes = await Promise.all([...Array(3)].map(async () =>
- mocks.harvest_use_typeFactory({
- promisedFarm: { farm_id },
- })
- ));
- const harvest_types = promisedHarvestUseTypes.reduce((a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }), []);
- const harvest_uses = [];
- for (let i = 0; i < harvest_types.length; i++) {
- let [harvest_use] = await mocks.harvest_useFactory({
- promisedHarvestTask: [{ task_id }],
- promisedHarvestUseType: [{ harvest_use_type_id: harvest_types[i].harvest_use_type_id }]
+ await Promise.all(
+ [...Array(3)].map(async () => {
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
- harvest_uses.push(harvest_use);
- }
- }));
+ await mocks.harvest_taskFactory({ promisedTask: [{ task_id }] });
+ const promisedHarvestUseTypes = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.harvest_use_typeFactory({
+ promisedFarm: { farm_id },
+ }),
+ ),
+ );
+ const harvest_types = promisedHarvestUseTypes.reduce(
+ (a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }),
+ [],
+ );
+ const harvest_uses = [];
+ for (let i = 0; i < harvest_types.length; i++) {
+ const [harvest_use] = await mocks.harvest_useFactory({
+ promisedHarvestTask: [{ task_id }],
+ promisedHarvestUseType: [
+ { harvest_use_type_id: harvest_types[i].harvest_use_type_id },
+ ],
+ });
+ harvest_uses.push(harvest_use);
+ }
+ }),
+ );
getHarvestUsesRequest({ user_id, farm_id }, async (err, res) => {
expect(res.status).toBe(200);
expect(res.body.length).toBe(9);
@@ -454,64 +843,86 @@ describe('Task tests', () => {
const userFarm = { ...fakeUserFarm(1), wage: { type: '', amount: 30 } };
const [firstUserFarm] = await mocks.userFarmFactory({}, userFarm);
const [secondUserFarm] = await mocks.userFarmFactory({}, userFarm);
- await Promise.all([...Array(2)].map(async (_, i) => {
- const { user_id, farm_id } = i > 0 ? secondUserFarm : firstUserFarm;
- const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
- const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await Promise.all(
+ [...Array(2)].map(async (_, i) => {
+ const { user_id, farm_id } = i > 0 ? secondUserFarm : firstUserFarm;
+ const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
- owner_user_id: user_id,
- assignee_user_id: user_id,
- });
+ const fakeTask = mocks.fakeTask({
+ task_type_id,
+ owner_user_id: user_id,
+ assignee_user_id: user_id,
+ });
- const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- await mocks.harvest_taskFactory({ promisedTask: [{ task_id }] });
- const promisedHarvestUseTypes = await Promise.all([...Array(3)].map(async () =>
- mocks.harvest_use_typeFactory({
- promisedFarm: { farm_id },
- })
- ));
- const harvest_types = promisedHarvestUseTypes.reduce((a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }), []);
- const harvest_uses = [];
- for (let i = 0; i < harvest_types.length; i++) {
- let [harvest_use] = await mocks.harvest_useFactory({
- promisedHarvestTask: [{ task_id }],
- promisedHarvestUseType: [{ harvest_use_type_id: harvest_types[i].harvest_use_type_id }]
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
- harvest_uses.push(harvest_use);
- }
- }));
- getHarvestUsesRequest({ user_id: firstUserFarm.user_id, farm_id: firstUserFarm.farm_id }, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(3);
- done();
- });
+ await mocks.harvest_taskFactory({ promisedTask: [{ task_id }] });
+ const promisedHarvestUseTypes = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.harvest_use_typeFactory({
+ promisedFarm: { farm_id },
+ }),
+ ),
+ );
+ const harvest_types = promisedHarvestUseTypes.reduce(
+ (a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }),
+ [],
+ );
+ const harvest_uses = [];
+ for (let i = 0; i < harvest_types.length; i++) {
+ const [harvest_use] = await mocks.harvest_useFactory({
+ promisedHarvestTask: [{ task_id }],
+ promisedHarvestUseType: [
+ { harvest_use_type_id: harvest_types[i].harvest_use_type_id },
+ ],
+ });
+ harvest_uses.push(harvest_use);
+ }
+ }),
+ );
+ getHarvestUsesRequest(
+ { user_id: firstUserFarm.user_id, farm_id: firstUserFarm.farm_id },
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(3);
+ done();
+ },
+ );
});
- })
+ });
describe('GET tasks', () => {
-
test('should get all tasks for a farm ', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const tasks = await Promise.all([...Array(10)].map(async () => {
- const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
- const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- const [{ management_plan_id }] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- });
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- promisedTaskType: [{ task_type_id }],
- });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- await mocks.management_tasksFactory({
- promisedTask: [{ task_id }],
- promisedManagementPlan: [{ management_plan_id }],
- });
- }));
+ await Promise.all(
+ [...Array(10)].map(async () => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ const [{ management_plan_id }] = await mocks.management_planFactory({
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ });
+ const [{ task_id }] = await mocks.taskFactory({
+ promisedUser: [{ user_id }],
+ promisedTaskType: [{ task_type_id }],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+ await mocks.management_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedManagementPlan: [{ management_plan_id }],
+ });
+ }),
+ );
getTasksRequest({ farm_id, user_id }, (err, res) => {
expect(res.status).toBe(200);
expect(res.body.length).toBe(10);
@@ -519,47 +930,66 @@ describe('Task tests', () => {
});
});
- xtest('should get all tasks that are related to a farm, but not from different farms of that user', async (done) => {
+ xtest('should get all tasks related to a farm, but not from different farms of that user', async (done) => {
const [firstUserFarm] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [secondUserFarmWithSameUser] = await mocks.userFarmFactory({ promisedUser: [{ user_id: firstUserFarm.user_id }] }, fakeUserFarm(1));
- await Promise.all([...Array(20)].map(async (_, i) => {
- const innerFarmId = i > 9 ? firstUserFarm.farm_id : secondUserFarmWithSameUser.farm_id;
- const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id: innerFarmId }] });
- const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id: innerFarmId }] });
- const [{ management_plan_id }] = await mocks.management_planFactory({
- promisedFarm: [{ farm_id: innerFarmId }],
- promisedLocation: [{ location_id }],
- });
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id: firstUserFarm.user_id }],
- promisedTaskType: [{ task_type_id }],
- });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- await mocks.management_tasksFactory({
- promisedTask: [{ task_id }],
- promisedManagementPlan: [{ management_plan_id }],
- });
- }));
- getTasksRequest({ farm_id: firstUserFarm.farm_id, user_id: firstUserFarm.user_id }, (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(10);
- done();
- });
+ const [secondUserFarmWithSameUser] = await mocks.userFarmFactory(
+ { promisedUser: [{ user_id: firstUserFarm.user_id }] },
+ fakeUserFarm(1),
+ );
+ await Promise.all(
+ [...Array(20)].map(async (_, i) => {
+ const innerFarmId = i > 9 ? firstUserFarm.farm_id : secondUserFarmWithSameUser.farm_id;
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: innerFarmId }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: innerFarmId }],
+ });
+ const [{ management_plan_id }] = await mocks.management_planFactory({
+ promisedFarm: [{ farm_id: innerFarmId }],
+ promisedLocation: [{ location_id }],
+ });
+ const [{ task_id }] = await mocks.taskFactory({
+ promisedUser: [{ user_id: firstUserFarm.user_id }],
+ promisedTaskType: [{ task_type_id }],
+ });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+ await mocks.management_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedManagementPlan: [{ management_plan_id }],
+ });
+ }),
+ );
+ getTasksRequest(
+ { farm_id: firstUserFarm.farm_id, user_id: firstUserFarm.user_id },
+ (err, res) => {
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(10);
+ done();
+ },
+ );
});
});
describe('POST Task', () => {
-
describe('creating types of tasks', () => {
let product;
let productData;
beforeEach(async () => {
- [{ product_id: product }] = await mocks.productFactory({}, mocks.fakeProduct({ supplier: 'mock' }));
+ [{ product_id: product }] = await mocks.productFactory(
+ {},
+ mocks.fakeProduct({ supplier: 'mock' }),
+ );
productData = mocks.fakeProduct({ supplier: 'test' });
});
const fakeTaskData = {
- soil_amendment_task: () => mocks.fakeSoilAmendmentTask({ product_id: product, product: productData }),
- pest_control_task: () => mocks.fakePestControlTask({ product_id: product, product: productData }),
+ soil_amendment_task: () =>
+ mocks.fakeSoilAmendmentTask({ product_id: product, product: productData }),
+ pest_control_task: () =>
+ mocks.fakePestControlTask({ product_id: product, product: productData }),
irrigation_task: () => mocks.fakeIrrigationTask(),
scouting_task: () => mocks.fakeScoutingTask(),
soil_task: () => mocks.fakeSoilTask(),
@@ -572,25 +1002,34 @@ describe('Task tests', () => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, userFarm);
const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
const [{ location_id }] = await mocks.fieldFactory({ promisedFarm: [{ farm_id }] });
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.planting_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedField: [{ location_id }],
- }, { start_date: null }),
- ));
- const managementPlans = promisedManagement.map(([{ planting_management_plan_id }]) => ({ planting_management_plan_id }));
- const harvest_tasks = mocks.fakeHarvestTasks({ projected_quantity: 300 }, 3).map((harvest_task, i) => {
- return {
- harvest_task,
- due_date: faker.date.future(),
- task_type_id: task_type_id,
- owner_user_id: user_id,
- assignee_user_id: user_id,
- locations: [{ location_id }],
- managementPlans: [managementPlans[i]],
- notes: faker.lorem.words(),
- };
- });
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.planting_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedField: [{ location_id }],
+ },
+ { start_date: null },
+ ),
+ ),
+ );
+ const managementPlans = promisedManagement.map(([{ planting_management_plan_id }]) => ({
+ planting_management_plan_id,
+ }));
+ const harvest_tasks = mocks
+ .fakeHarvestTasks({ projected_quantity: 300 }, 3)
+ .map((harvest_task, i) => {
+ return {
+ harvest_task,
+ due_date: faker.date.future().toISOString().split('T')[0],
+ task_type_id,
+ owner_user_id: user_id,
+ assignee_user_id: user_id,
+ locations: [{ location_id }],
+ managementPlans: [managementPlans[i]],
+ notes: faker.lorem.words(),
+ };
+ });
postHarvestTasksRequest({ user_id, farm_id }, harvest_tasks, async (err, res) => {
expect(res.status).toBe(201);
@@ -599,10 +1038,14 @@ describe('Task tests', () => {
const created_task = await knex('task').where({ task_id: task_ids[i] }).first();
expect(created_task.task_type_id).toBe(task_type_id);
expect(created_task.wage_at_moment).toBe(30);
- const isTaskRelatedToLocation = await knex('location_tasks').where({ task_id: task_ids[i] }).first();
+ const isTaskRelatedToLocation = await knex('location_tasks')
+ .where({ task_id: task_ids[i] })
+ .first();
expect(isTaskRelatedToLocation.location_id).toBe(location_id);
expect(isTaskRelatedToLocation.task_id).toBe(Number(task_ids[i]));
- const isTaskRelatedToManagementPlans = await knex('management_tasks').where({ task_id: task_ids[i] });
+ const isTaskRelatedToManagementPlans = await knex('management_tasks').where({
+ task_id: task_ids[i],
+ });
expect(isTaskRelatedToManagementPlans.length).toBe(1);
const created_harvest_task = await knex('harvest_task').where({ task_id: task_ids[i] });
expect(created_harvest_task.length).toBe(1);
@@ -623,17 +1066,26 @@ describe('Task tests', () => {
async function getBody(planting_method = 'container_method') {
const [userFarm] = await mocks.userFarmFactory({}, { role_id: 1, status: 'Active' });
- const [transplantTaskType] = await mocks.task_typeFactory({
- promisedFarm: [{
- farm_id: null,
- user_id: '1',
- }],
- }, {
- 'task_translation_key': 'TRANSPLANT_TASK',
- 'task_name': 'Transplant',
- });
- const [{ location_id }] = await mocks.fieldFactory({ promisedFarm: [userFarm] });
- const [{ management_plan_id }] = await mocks.crop_management_planFactory({ promisedFarm: [userFarm] });
+ const [transplantTaskType] = await mocks.task_typeFactory(
+ {
+ promisedFarm: [
+ {
+ farm_id: null,
+ user_id: '1',
+ },
+ ],
+ },
+ {
+ task_translation_key: 'TRANSPLANT_TASK',
+ task_name: 'Transplant',
+ },
+ );
+ const [
+ { location_id, management_plan_id },
+ ] = await mocks.planting_management_planFactory({ promisedFarm: [userFarm] });
+ const [
+ { planting_management_plan_id: prev_planting_management_plan_id },
+ ] = await mocks.planting_management_planFactory({ promisedFarm: [userFarm] });
const transplant_task = {
...mocks.fakeTask(),
task_type_id: transplantTaskType.task_type_id,
@@ -646,6 +1098,7 @@ describe('Task tests', () => {
planting_method: planting_method.toUpperCase(),
[planting_method]: fakeMethodMap[planting_method](),
},
+ prev_planting_management_plan_id,
},
};
@@ -656,11 +1109,20 @@ describe('Task tests', () => {
expect(res.status).toBe(201);
const transplant_task = res.body;
transplant_task.name = transplantTaskReq.name;
- expect(transplant_task.transplant_task.planting_management_plan.planting_task_type).toBe('TRANSPLANT_TASK');
- expect(transplant_task.transplant_task.planting_management_plan.location_id).toBe(transplantTaskReq.transplant_task.planting_management_plan.location_id);
- const planting_method = transplant_task.transplant_task.planting_management_plan.planting_method;
- expect(planting_method).toBe(transplantTaskReq.transplant_task.planting_management_plan.planting_method);
- expect(transplant_task.transplant_task.planting_management_plan[planting_method.toLowerCase()]).toBeDefined();
+ expect(transplant_task.transplant_task.planting_management_plan.planting_task_type).toBe(
+ 'TRANSPLANT_TASK',
+ );
+ expect(transplant_task.transplant_task.planting_management_plan.location_id).toBe(
+ transplantTaskReq.transplant_task.planting_management_plan.location_id,
+ );
+ const planting_method =
+ transplant_task.transplant_task.planting_management_plan.planting_method;
+ expect(planting_method).toBe(
+ transplantTaskReq.transplant_task.planting_management_plan.planting_method,
+ );
+ expect(
+ transplant_task.transplant_task.planting_management_plan[planting_method.toLowerCase()],
+ ).toBeDefined();
}
['row_method', 'bed_method', 'container_method'].map((planting_method) => {
@@ -672,17 +1134,17 @@ describe('Task tests', () => {
});
});
});
-
});
-
Object.keys(fakeTaskData).map((type) => {
test(`should successfully create a ${type} without an associated management plan`, async (done) => {
- const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(false);
+ const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(
+ false,
+ );
const data = {
...mocks.fakeTask({
[type]: { ...fakeTaskData[type]() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
}),
@@ -703,7 +1165,9 @@ describe('Task tests', () => {
expect(specificTask.length).toBe(1);
expect(specificTask[0].task_id).toBe(task_id);
if (res.body[type].product_id) {
- const specificProduct = await knex('product').where({ product_id: res.body[type].product_id }).first();
+ const specificProduct = await knex('product')
+ .where({ product_id: res.body[type].product_id })
+ .first();
expect(specificProduct.supplier).toBe('test');
}
done();
@@ -717,14 +1181,13 @@ describe('Task tests', () => {
user_id,
farm_id,
location_id,
- management_plan_id,
planting_management_plan_id,
task_type_id,
} = await userFarmTaskGenerator();
const data = {
...mocks.fakeTask({
[type]: { ...fakeTaskData[type]() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
}),
locations: [{ location_id }],
@@ -739,7 +1202,9 @@ describe('Task tests', () => {
const isTaskRelatedToLocation = await knex('location_tasks').where({ task_id }).first();
expect(isTaskRelatedToLocation.location_id).toBe(location_id);
expect(isTaskRelatedToLocation.task_id).toBe(task_id);
- const isTaskRelatedToManagementPlans = await knex('management_tasks').where({ task_id });
+ const isTaskRelatedToManagementPlans = await knex('management_tasks').where({
+ task_id,
+ });
expect(isTaskRelatedToManagementPlans.length).toBe(1);
const specificTask = await knex(type).where({ task_id });
expect(specificTask.length).toBe(1);
@@ -750,24 +1215,36 @@ describe('Task tests', () => {
});
test('should create a task (i.e soilamendment) with multiple management plans', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.crop_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- promisedField: [{ location_id }],
- }, {
- cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
- }),
- ));
- const managementPlanIds = promisedManagement.map(([{ management_plan_id }]) => management_plan_id);
- const plantingManagementPlans = await knex('planting_management_plan').whereIn('management_plan_id', managementPlanIds);
- const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({ planting_management_plan_id }));
+ const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(true);
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.crop_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ promisedField: [{ location_id }],
+ },
+ {
+ cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
+ },
+ ),
+ ),
+ );
+ const managementPlanIds = promisedManagement.map(
+ ([{ management_plan_id }]) => management_plan_id,
+ );
+ const plantingManagementPlans = await knex('planting_management_plan').whereIn(
+ 'management_plan_id',
+ managementPlanIds,
+ );
+ const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({
+ planting_management_plan_id,
+ }));
const data = {
...mocks.fakeTask({
soil_amendment_task: { ...fakeTaskData.soil_amendment_task() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
}),
locations: [{ location_id }],
@@ -789,23 +1266,35 @@ describe('Task tests', () => {
});
test('should create a task (i.e soilamendment) and override wage', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.crop_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- promisedField: [{ location_id }],
- }, {
- cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
- }),
- ));
- const managementPlanIds = promisedManagement.map(([{ management_plan_id }]) => management_plan_id);
- const plantingManagementPlans = await knex('planting_management_plan').whereIn('management_plan_id', managementPlanIds);
- const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({ planting_management_plan_id }));
+ const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(true);
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.crop_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ promisedField: [{ location_id }],
+ },
+ {
+ cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
+ },
+ ),
+ ),
+ );
+ const managementPlanIds = promisedManagement.map(
+ ([{ management_plan_id }]) => management_plan_id,
+ );
+ const plantingManagementPlans = await knex('planting_management_plan').whereIn(
+ 'management_plan_id',
+ managementPlanIds,
+ );
+ const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({
+ planting_management_plan_id,
+ }));
const data = {
...mocks.fakeTask({
soil_amendment_task: { ...fakeTaskData.soil_amendment_task() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
wage_at_moment: 50,
}),
@@ -829,26 +1318,40 @@ describe('Task tests', () => {
});
test('should create a task (i.e soilamendment) and patch a product', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.crop_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- promisedField: [{ location_id }],
-
- }, {
- cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
- }),
- ));
- const managementPlanIds = promisedManagement.map(([{ management_plan_id }]) => management_plan_id);
- const plantingManagementPlans = await knex('planting_management_plan').whereIn('management_plan_id', managementPlanIds);
- const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({ planting_management_plan_id }));
+ const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(true);
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.crop_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ promisedField: [{ location_id }],
+ },
+ {
+ cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
+ },
+ ),
+ ),
+ );
+ const managementPlanIds = promisedManagement.map(
+ ([{ management_plan_id }]) => management_plan_id,
+ );
+ const plantingManagementPlans = await knex('planting_management_plan').whereIn(
+ 'management_plan_id',
+ managementPlanIds,
+ );
+ const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({
+ planting_management_plan_id,
+ }));
const soilAmendmentProduct = mocks.fakeProduct();
soilAmendmentProduct.name = 'soilProduct';
const data = {
...mocks.fakeTask({
- soil_amendment_task: { ...fakeTaskData.soil_amendment_task(), product: soilAmendmentProduct },
- task_type_id: task_type_id,
+ soil_amendment_task: {
+ ...fakeTaskData.soil_amendment_task(),
+ product: soilAmendmentProduct,
+ },
+ task_type_id,
owner_user_id: user_id,
wage_at_moment: 50,
}),
@@ -875,20 +1378,31 @@ describe('Task tests', () => {
});
test('should create a task (i.e soilamendment) and create a product', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.crop_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedLocation: [{ location_id }],
- promisedField: [{ location_id }],
-
- }, {
- cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
- }),
- ));
- const managementPlanIds = promisedManagement.map(([{ management_plan_id }]) => management_plan_id);
- const plantingManagementPlans = await knex('planting_management_plan').whereIn('management_plan_id', managementPlanIds);
- const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({ planting_management_plan_id }));
+ const { user_id, farm_id, location_id, task_type_id } = await userFarmTaskGenerator(true);
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.crop_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedLocation: [{ location_id }],
+ promisedField: [{ location_id }],
+ },
+ {
+ cropManagementPlan: { ...mocks.fakeCropManagementPlan(), needs_transplant: false },
+ },
+ ),
+ ),
+ );
+ const managementPlanIds = promisedManagement.map(
+ ([{ management_plan_id }]) => management_plan_id,
+ );
+ const plantingManagementPlans = await knex('planting_management_plan').whereIn(
+ 'management_plan_id',
+ managementPlanIds,
+ );
+ const managementPlans = plantingManagementPlans.map(({ planting_management_plan_id }) => ({
+ planting_management_plan_id,
+ }));
const soilAmendmentProduct = mocks.fakeProduct();
soilAmendmentProduct.name = 'soilProduct2';
soilAmendmentProduct.farm_id = farm_id;
@@ -899,7 +1413,7 @@ describe('Task tests', () => {
product: soilAmendmentProduct,
product_id: null,
},
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
wage_at_moment: 50,
}),
@@ -925,15 +1439,25 @@ describe('Task tests', () => {
});
});
-
test('should fail to create a task were a worker is trying to assign someone else', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const [{ user_id: worker_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
- const [{ user_id: another_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(2));
+ const {
+ farm_id,
+ location_id,
+ management_plan_id,
+ task_type_id,
+ } = await userFarmTaskGenerator(true);
+ const [{ user_id: worker_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
+ const [{ user_id: another_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(2),
+ );
const data = {
...mocks.fakeTask({
soil_amendment_task: { ...fakeTaskData.soil_amendment_task() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: worker_id,
assignee_user_id: another_id,
}),
@@ -941,19 +1465,32 @@ describe('Task tests', () => {
managementPlans: [{ management_plan_id }],
};
- postTaskRequest({ user_id: worker_id, farm_id }, 'soil_amendment_task', data, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ postTaskRequest(
+ { user_id: worker_id, farm_id },
+ 'soil_amendment_task',
+ data,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('should fail to create a task were a worker is trying to modify wage for himself ', async (done) => {
- const { user_id, farm_id, location_id, management_plan_id, task_type_id } = await userFarmTaskGenerator(true);
- const [{ user_id: worker_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
+ const {
+ farm_id,
+ location_id,
+ management_plan_id,
+ task_type_id,
+ } = await userFarmTaskGenerator(true);
+ const [{ user_id: worker_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
const data = {
...mocks.fakeTask({
soil_amendment_task: { ...fakeTaskData.soil_amendment_task() },
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: worker_id,
assignee_user_id: worker_id,
wage_at_moment: 3512222,
@@ -962,26 +1499,35 @@ describe('Task tests', () => {
managementPlans: [{ management_plan_id }],
};
- postTaskRequest({ user_id: worker_id, farm_id }, 'soil_amendment_task', data, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ postTaskRequest(
+ { user_id: worker_id, farm_id },
+ 'soil_amendment_task',
+ data,
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
- })
+ });
describe('Patch tasks completion tests', () => {
-
let product;
let productData;
beforeEach(async () => {
- [{ product_id: product }] = await mocks.productFactory({}, mocks.fakeProduct({ supplier: 'mock' }));
+ [{ product_id: product }] = await mocks.productFactory(
+ {},
+ mocks.fakeProduct({ supplier: 'mock' }),
+ );
productData = mocks.fakeProduct({ supplier: 'test' });
});
const fakeTaskData = {
- soil_amendment_task: () => mocks.fakeSoilAmendmentTask({ product_id: product, product: productData }),
- pest_control_task: () => mocks.fakePestControlTask({ product_id: product, product: productData }),
+ soil_amendment_task: () =>
+ mocks.fakeSoilAmendmentTask({ product_id: product, product: productData }),
+ pest_control_task: () =>
+ mocks.fakePestControlTask({ product_id: product, product: productData }),
irrigation_task: () => mocks.fakeIrrigationTask(),
scouting_task: () => mocks.fakeScoutingTask(),
soil_task: () => mocks.fakeSoilTask(),
@@ -990,33 +1536,45 @@ describe('Task tests', () => {
plant_task: () => mocks.fakePlantTask(),
};
- const completed_time = faker.date.future();
- const completed_date = completed_time.toISOString().split('T')[0];
+ const complete_date = '2222-01-01';
const duration = 15;
const happiness = 5;
const notes = faker.lorem.sentence();
const fakeCompletionData = {
- completed_time: completed_time,
- duration: duration,
- happiness: happiness,
+ complete_date,
+ duration,
+ happiness,
completion_notes: notes,
};
test('should return 403 if non-assignee tries to complete task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: another_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(1));
+ const [{ user_id: another_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(1),
+ );
const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
- assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async (err, res) => {
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
});
- completeTaskRequest({ user_id: another_id, farm_id }, {
- ...fakeCompletionData,
- soil_amendment_task: fakeTaskData.soil_amendment_task(),
- }, task_id, 'soil_amendment_task', async (err, res) => {
- expect(res.status).toBe(403);
- done();
+ assignTaskRequest({ user_id, farm_id }, { assignee_user_id: user_id }, task_id, async () => {
+ completeTaskRequest(
+ { user_id: another_id, farm_id },
+ {
+ ...fakeCompletionData,
+ soil_amendment_task: fakeTaskData.soil_amendment_task(),
+ assignee_user_id: user_id,
+ },
+ task_id,
+ 'soil_amendment_task',
+ async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
@@ -1027,34 +1585,50 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
});
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- promisedTaskType: [{ task_type_id }],
- }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
+ const [{ task_id }] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ promisedTaskType: [{ task_type_id }],
+ },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
await mocks.soil_amendment_taskFactory({ promisedTask: [{ task_id }] });
const new_soil_amendment_task = fakeTaskData.soil_amendment_task();
- completeTaskRequest({ user_id, farm_id }, {
- ...fakeCompletionData,
- soil_amendment_task: { task_id: task_id, ...new_soil_amendment_task },
- }, task_id, 'soil_amendment_task', async (err, res) => {
- expect(res.status).toBe(200);
- const completed_task = await knex('task').where({ task_id }).first();
- expect(completed_task.completed_time.toString()).toBe(completed_time.toString());
- expect(completed_task.duration).toBe(duration);
- expect(completed_task.happiness).toBe(happiness);
- expect(completed_task.completion_notes).toBe(notes);
- const patched_soil_amendment_task = await knex('soil_amendment_task').where({ task_id }).first();
- expect(patched_soil_amendment_task.product_quantity).toBe(new_soil_amendment_task.product_quantity);
- expect(patched_soil_amendment_task.purpose).toBe(new_soil_amendment_task.purpose);
- done();
- });
+ completeTaskRequest(
+ { user_id, farm_id },
+ {
+ ...fakeCompletionData,
+ soil_amendment_task: { task_id, ...new_soil_amendment_task },
+ },
+ task_id,
+ 'soil_amendment_task',
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const completed_task = await knex('task').where({ task_id }).first();
+ expect(toLocal8601Extended(completed_task.complete_date)).toBe(complete_date);
+ expect(completed_task.duration).toBe(duration);
+ expect(completed_task.happiness).toBe(happiness);
+ expect(completed_task.completion_notes).toBe(notes);
+ const patched_soil_amendment_task = await knex('soil_amendment_task')
+ .where({ task_id })
+ .first();
+ expect(patched_soil_amendment_task.product_quantity).toBe(
+ new_soil_amendment_task.product_quantity,
+ );
+ expect(patched_soil_amendment_task.purpose).toBe(new_soil_amendment_task.purpose);
+ done();
+ },
+ );
});
test('should be able to complete a pest control task', async (done) => {
@@ -1064,35 +1638,53 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
});
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- promisedTaskType: [{ task_type_id }],
- }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
+ const [{ task_id }] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ promisedTaskType: [{ task_type_id }],
+ },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
await mocks.pest_control_taskFactory({ promisedTask: [{ task_id }] });
const new_pest_control_task = fakeTaskData.pest_control_task();
- completeTaskRequest({ user_id, farm_id }, {
- ...fakeCompletionData,
- pest_control_task: { task_id: task_id, ...new_pest_control_task },
- }, task_id, 'pest_control_task', async (err, res) => {
- expect(res.status).toBe(200);
- const completed_task = await knex('task').where({ task_id }).first();
- expect(completed_task.completed_time.toString()).toBe(completed_time.toString());
- expect(completed_task.duration).toBe(duration);
- expect(completed_task.happiness).toBe(happiness);
- expect(completed_task.completion_notes).toBe(notes);
- const patched_pest_control_task = await knex('pest_control_task').where({ task_id }).first();
- expect(patched_pest_control_task.product_quantity).toBe(new_pest_control_task.product_quantity);
- expect(patched_pest_control_task.pest_target).toBe(new_pest_control_task.pest_target);
- expect(patched_pest_control_task.control_method).toBe(new_pest_control_task.control_method);
- done();
- });
+ completeTaskRequest(
+ { user_id, farm_id },
+ {
+ ...fakeCompletionData,
+ pest_control_task: { task_id, ...new_pest_control_task },
+ },
+ task_id,
+ 'pest_control_task',
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const completed_task = await knex('task').where({ task_id }).first();
+ expect(toLocal8601Extended(completed_task.complete_date)).toBe(complete_date);
+ expect(completed_task.duration).toBe(duration);
+ expect(completed_task.happiness).toBe(happiness);
+ expect(completed_task.completion_notes).toBe(notes);
+ const patched_pest_control_task = await knex('pest_control_task')
+ .where({ task_id })
+ .first();
+ expect(patched_pest_control_task.product_quantity).toBe(
+ new_pest_control_task.product_quantity,
+ );
+ expect(patched_pest_control_task.pest_target).toBe(new_pest_control_task.pest_target);
+ expect(patched_pest_control_task.control_method).toBe(
+ new_pest_control_task.control_method,
+ );
+ done();
+ },
+ );
});
test('should be able to complete a harvest task', async (done) => {
@@ -1102,46 +1694,66 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
- })
- const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
+ });
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }], promisedTaskType: [{ task_type_id }] },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
await mocks.harvest_taskFactory({ promisedTask: [{ task_id }] });
const harvest_uses = [];
- const promisedHarvestUseTypes = await Promise.all([...Array(3)].map(async () =>
- mocks.harvest_use_typeFactory({
- promisedFarm: [{ farm_id }],
- })
- ));
- const harvest_types = promisedHarvestUseTypes.reduce((a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }), []);
+ const promisedHarvestUseTypes = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.harvest_use_typeFactory({
+ promisedFarm: [{ farm_id }],
+ }),
+ ),
+ );
+ const harvest_types = promisedHarvestUseTypes.reduce(
+ (a, b) => a.concat({ harvest_use_type_id: b[0].harvest_use_type_id }),
+ [],
+ );
let actual_quantity = 0;
harvest_types.forEach(({ harvest_use_type_id }) => {
- let harvest_use = mocks.fakeHarvestUse({
- task_id: task_id,
+ const harvest_use = mocks.fakeHarvestUse({
+ task_id,
harvest_use_type_id,
});
harvest_uses.push(harvest_use);
actual_quantity += harvest_use.quantity;
});
- completeTaskRequest({ user_id, farm_id }, { task: { ...fakeCompletionData, harvest_task: { task_id, actual_quantity } }, harvest_uses: harvest_uses }, task_id, 'harvest_task', async (err, res) => {
- expect(res.status).toBe(200);
- const completed_task = await knex('task').where({ task_id }).first();
- expect(completed_task.completed_time.toString()).toBe(completed_time.toString());
- expect(completed_task.duration).toBe(duration);
- expect(completed_task.happiness).toBe(happiness);
- expect(completed_task.completion_notes).toBe(notes);
- const new_harvest_uses = await knex('harvest_use').where({ task_id });
- expect(new_harvest_uses.length).toBe(harvest_uses.length);
- const patched_harvest_task = await knex('harvest_task').where({ task_id }).first();
- expect(patched_harvest_task.actual_quantity).toBe(actual_quantity);
- let harvest_uses_quantity = 0;
- new_harvest_uses.forEach(({ quantity }) => harvest_uses_quantity += quantity);
- expect(harvest_uses_quantity).toBe(actual_quantity);
- done();
- });
+ completeTaskRequest(
+ { user_id, farm_id },
+ {
+ task: { ...fakeCompletionData, harvest_task: { task_id, actual_quantity } },
+ harvest_uses,
+ },
+ task_id,
+ 'harvest_task',
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const completed_task = await knex('task').where({ task_id }).first();
+ expect(toLocal8601Extended(completed_task.complete_date)).toBe(complete_date);
+ expect(completed_task.duration).toBe(duration);
+ expect(completed_task.happiness).toBe(happiness);
+ expect(completed_task.completion_notes).toBe(notes);
+ const new_harvest_uses = await knex('harvest_use').where({ task_id });
+ expect(new_harvest_uses.length).toBe(harvest_uses.length);
+ const patched_harvest_task = await knex('harvest_task').where({ task_id }).first();
+ expect(patched_harvest_task.actual_quantity).toBe(actual_quantity);
+ let harvest_uses_quantity = 0;
+ new_harvest_uses.forEach(({ quantity }) => (harvest_uses_quantity += quantity));
+ expect(harvest_uses_quantity).toBe(actual_quantity);
+ done();
+ },
+ );
});
//TODO: complete plant task test
@@ -1152,35 +1764,47 @@ describe('Task tests', () => {
const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
});
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- promisedTaskType: [{ task_type_id }],
- }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
+ const [{ task_id }] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ promisedTaskType: [{ task_type_id }],
+ },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
await mocks.plant_taskFactory({ promisedTask: [{ task_id }] });
const new_plant_task = fakeTaskData.plant_task();
- completeTaskRequest({ user_id, farm_id }, {
- ...fakeCompletionData,
- plant_task: { task_id: task_id, ...new_plant_task },
- }, task_id, 'plant_task', async (err, res) => {
- expect(res.status).toBe(200);
- const completed_task = await knex('task').where({ task_id }).first();
- expect(completed_task.completed_time.toString()).toBe(completed_time.toString());
- expect(completed_task.duration).toBe(duration);
- expect(completed_task.happiness).toBe(happiness);
- expect(completed_task.completion_notes).toBe(notes);
- const patched_plant_task = await knex('plant_task').where({ task_id }).first();
- expect(patched_plant_task.space_depth_cm).toBe(new_plant_task.space_depth_cm);
- expect(patched_plant_task.space_length_cm).toBe(new_plant_task.space_length_cm);
- expect(patched_plant_task.space_width_cm).toBe(new_plant_task.space_width_cm);
- done();
- });
+ completeTaskRequest(
+ { user_id, farm_id },
+ {
+ ...fakeCompletionData,
+ plant_task: { task_id, ...new_plant_task },
+ },
+ task_id,
+ 'plant_task',
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const completed_task = await knex('task').where({ task_id }).first();
+ expect(completed_task.complete_date.toString()).toBe(complete_date.toString());
+ expect(completed_task.duration).toBe(duration);
+ expect(completed_task.happiness).toBe(happiness);
+ expect(completed_task.completion_notes).toBe(notes);
+ const patched_plant_task = await knex('plant_task').where({ task_id }).first();
+ expect(patched_plant_task.space_depth_cm).toBe(new_plant_task.space_depth_cm);
+ expect(patched_plant_task.space_length_cm).toBe(new_plant_task.space_length_cm);
+ expect(patched_plant_task.space_width_cm).toBe(new_plant_task.space_width_cm);
+ done();
+ },
+ );
});
test('should complete a task (i.e soilamendment) with multiple management plans', async (done) => {
const userFarm = { ...fakeUserFarm(1), wage: { type: '', amount: 30 } };
@@ -1188,133 +1812,172 @@ describe('Task tests', () => {
const [{ task_type_id }] = await mocks.task_typeFactory({ promisedFarm: [{ farm_id }] });
const [{ location_id }] = await mocks.fieldFactory({ promisedFarm: [{ farm_id }] });
- const promisedManagement = await Promise.all([...Array(3)].map(async () =>
- mocks.planting_management_planFactory({
- promisedFarm: [{ farm_id }],
- promisedField: [{ location_id }],
- promisedManagementPlan: mocks.management_planFactory({ promisedFarm: [{ farm_id }] }, {
- ...mocks.fakeManagementPlan,
- start_date: null,
- }),
- }, { start_date: null }),
- ));
- const managementPlans = promisedManagement.map(([{ planting_management_plan_id }]) => ({ planting_management_plan_id }));
+ const promisedManagement = await Promise.all(
+ [...Array(3)].map(async () =>
+ mocks.planting_management_planFactory(
+ {
+ promisedFarm: [{ farm_id }],
+ promisedField: [{ location_id }],
+ promisedManagementPlan: mocks.management_planFactory(
+ { promisedFarm: [{ farm_id }] },
+ {
+ ...mocks.fakeManagementPlan,
+ start_date: null,
+ },
+ ),
+ },
+ { start_date: null },
+ ),
+ ),
+ );
+ const managementPlans = promisedManagement.map(([{ planting_management_plan_id }]) => ({
+ planting_management_plan_id,
+ }));
const fakeTask = mocks.fakeTask({
- task_type_id: task_type_id,
+ task_type_id,
owner_user_id: user_id,
assignee_user_id: user_id,
});
- const [{ task_id }] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- promisedTaskType: [{ task_type_id }],
- }, fakeTask);
- await mocks.location_tasksFactory({ promisedTask: [{ task_id }], promisedField: [{ location_id }] });
+ const [{ task_id }] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ promisedTaskType: [{ task_type_id }],
+ },
+ fakeTask,
+ );
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
await mocks.soil_amendment_taskFactory({ promisedTask: [{ task_id }] });
await mocks.management_tasksFactory({
- promisedTask: [{ task_id: task_id }],
+ promisedTask: [{ task_id }],
promisedPlantingManagementPlan: [managementPlans[0]],
});
await mocks.management_tasksFactory({
- promisedTask: [{ task_id: task_id }],
+ promisedTask: [{ task_id }],
promisedPlantingManagementPlan: [managementPlans[1]],
});
await mocks.management_tasksFactory({
- promisedTask: [{ task_id: task_id }],
+ promisedTask: [{ task_id }],
promisedPlantingManagementPlan: [managementPlans[2]],
});
const new_soil_amendment_task = fakeTaskData.soil_amendment_task();
- completeTaskRequest({ user_id, farm_id }, {
- ...fakeCompletionData,
- soil_amendment_task: { task_id: task_id, ...new_soil_amendment_task },
- }, task_id, 'soil_amendment_task', async (err, res) => {
- expect(res.status).toBe(200);
- const completed_task = await knex('task').where({ task_id }).first();
- expect(completed_task.completed_time.toString()).toBe(completed_time.toString());
- expect(completed_task.duration).toBe(duration);
- expect(completed_task.happiness).toBe(happiness);
- expect(completed_task.completion_notes).toBe(notes);
- const patched_soil_amendment_task = await knex('soil_amendment_task').where({ task_id }).first();
- expect(patched_soil_amendment_task.product_quantity).toBe(new_soil_amendment_task.product_quantity);
- expect(patched_soil_amendment_task.purpose).toBe(new_soil_amendment_task.purpose);
- const management_plan_1 = await knex('management_plan').where({ management_plan_id: promisedManagement[0][0].management_plan_id }).first();
- const management_plan_2 = await knex('management_plan').where({ management_plan_id: promisedManagement[1][0].management_plan_id }).first();
- const management_plan_3 = await knex('management_plan').where({ management_plan_id: promisedManagement[2][0].management_plan_id }).first();
- expect(management_plan_1.start_date.toISOString().split('T')[0]).toBe(completed_date);
- expect(management_plan_2.start_date.toISOString().split('T')[0]).toBe(completed_date);
- expect(management_plan_3.start_date.toISOString().split('T')[0]).toBe(completed_date);
- done();
- });
+ completeTaskRequest(
+ { user_id, farm_id },
+ {
+ ...fakeCompletionData,
+ soil_amendment_task: { task_id, ...new_soil_amendment_task },
+ },
+ task_id,
+ 'soil_amendment_task',
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const completed_task = await knex('task').where({ task_id }).first();
+ expect(toLocal8601Extended(completed_task.complete_date)).toBe(complete_date);
+ expect(completed_task.duration).toBe(duration);
+ expect(completed_task.happiness).toBe(happiness);
+ expect(completed_task.completion_notes).toBe(notes);
+ const patched_soil_amendment_task = await knex('soil_amendment_task')
+ .where({ task_id })
+ .first();
+ expect(patched_soil_amendment_task.product_quantity).toBe(
+ new_soil_amendment_task.product_quantity,
+ );
+ expect(patched_soil_amendment_task.purpose).toBe(new_soil_amendment_task.purpose);
+ const management_plan_1 = await knex('management_plan')
+ .where({ management_plan_id: promisedManagement[0][0].management_plan_id })
+ .first();
+ const management_plan_2 = await knex('management_plan')
+ .where({ management_plan_id: promisedManagement[1][0].management_plan_id })
+ .first();
+ const management_plan_3 = await knex('management_plan')
+ .where({ management_plan_id: promisedManagement[2][0].management_plan_id })
+ .first();
+ expect(toLocal8601Extended(management_plan_1.start_date)).toBe(complete_date);
+ expect(toLocal8601Extended(management_plan_2.start_date)).toBe(complete_date);
+ expect(toLocal8601Extended(management_plan_3.start_date)).toBe(complete_date);
+ done();
+ },
+ );
});
});
describe('PATCH abandon task tests', () => {
const CROP_FAILURE = 'CROP_FAILURE';
- const OTHER = 'OTHER';
- const sampleOtherReason = 'sample reason';
const sampleNote = 'This is a sample note';
const abandonTaskBody = {
abandonment_reason: CROP_FAILURE,
other_abandonment_reason: null,
abandonment_notes: sampleNote,
};
- const abandonTaskBodyOther = {
- abandonment_reason: OTHER,
- other_abandonment_reason: sampleOtherReason,
- abandonment_notes: sampleNote,
- };
-
- beforeEach(async () => {
- [{ product_id: product }] = await mocks.productFactory({}, mocks.fakeProduct({ supplier: 'mock' }));
- productData = mocks.fakeProduct({ supplier: 'test' });
- });
test('An unassigned task should not abandoned with a rating', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
const abandonTaskBodyWithRating = {
...abandonTaskBody,
happiness: faker.datatype.number({ min: 1, max: 5 }),
};
- abandonTaskRequest({ user_id, farm_id }, abandonTaskBodyWithRating, task.task_id, async (err, res) => {
- expect(res.status).toBe(406);
- done();
- });
+ abandonTaskRequest(
+ { user_id, farm_id },
+ abandonTaskBodyWithRating,
+ task.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('An unassigned task should not abandoned with a duration', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
const abandonTaskBodyWithDuration = {
...abandonTaskBody,
duration: faker.datatype.number(1000),
};
- abandonTaskRequest({ user_id, farm_id }, abandonTaskBodyWithDuration, task.task_id, async (err, res) => {
- expect(res.status).toBe(406);
- done();
- });
+ abandonTaskRequest(
+ { user_id, farm_id },
+ abandonTaskBodyWithDuration,
+ task.task_id,
+ async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
});
test('Owner should be able to abandon a task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- }, mocks.fakeTask({ due_date: date, assignee_user_id: user_id }));
+ const [task] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ },
+ mocks.fakeTask({ due_date: date, assignee_user_id: user_id }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1325,13 +1988,16 @@ describe('Task tests', () => {
test('Manager should be able to abandon a task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(2));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1342,13 +2008,16 @@ describe('Task tests', () => {
test('EO should be able to abandon a task', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1358,15 +2027,21 @@ describe('Task tests', () => {
test('Admin should be able to abandon a task they do not own', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({ promisedUser: [{ user_id: other_user_id }] }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: other_user_id }] },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1376,17 +2051,23 @@ describe('Task tests', () => {
test('Admin should be able to abandon a task they are not assigned to', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(3));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(3),
+ );
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({
- promisedUser: [{ user_id: other_user_id }],
- }, mocks.fakeTask({ due_date: date, assignee_user_id: other_user_id }));
+ const [task] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id: other_user_id }],
+ },
+ mocks.fakeTask({ due_date: date, assignee_user_id: other_user_id }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1397,15 +2078,18 @@ describe('Task tests', () => {
test('Worker should be able to abandon a task they own', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({
- promisedUser: [{ user_id }],
- }, mocks.fakeTask({ due_date: date }));
+ const [task] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id }],
+ },
+ mocks.fakeTask({ due_date: date }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1415,17 +2099,23 @@ describe('Task tests', () => {
test('Worker should be able to abandon a task they are assigned to', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(1));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(1),
+ );
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({
- promisedUser: [{ user_id: other_user_id }],
- }, mocks.fakeTask({ due_date: date, assignee_user_id: user_id }));
+ const [task] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id: other_user_id }],
+ },
+ mocks.fakeTask({ due_date: date, assignee_user_id: user_id }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
expect(res.status).toBe(200);
const updated_task = await getTask(task.task_id);
- expect(updated_task.abandoned_time).toBeDefined();
+ expect(updated_task.abandon_date).toBeDefined();
expect(updated_task.abandonment_reason).toBe(CROP_FAILURE);
expect(updated_task.other_abandonment_reason).toBe(null);
expect(updated_task.abandonment_notes).toBe(sampleNote);
@@ -1435,11 +2125,17 @@ describe('Task tests', () => {
test('Worker should not be able to abandon a task they neither own or are assigned', async (done) => {
const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
- const [{ user_id: other_user_id }] = await mocks.userFarmFactory({ promisedFarm: [{ farm_id }] }, fakeUserFarm(1));
+ const [{ user_id: other_user_id }] = await mocks.userFarmFactory(
+ { promisedFarm: [{ farm_id }] },
+ fakeUserFarm(1),
+ );
const date = faker.date.future().toISOString().split('T')[0];
- const [task] = await mocks.taskFactory({
- promisedUser: [{ user_id: other_user_id }],
- }, mocks.fakeTask({ due_date: date, assignee_user_id: other_user_id }));
+ const [task] = await mocks.taskFactory(
+ {
+ promisedUser: [{ user_id: other_user_id }],
+ },
+ mocks.fakeTask({ due_date: date, assignee_user_id: other_user_id }),
+ );
const [location] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
abandonTaskRequest({ user_id, farm_id }, abandonTaskBody, task.task_id, async (err, res) => {
@@ -1448,4 +2144,194 @@ describe('Task tests', () => {
});
});
});
+
+ describe('Patch task due date test', () => {
+ test('Farm owner must be able to patch task due date to today', async (done) => {
+ const today = new Date();
+ const due_date = today.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('Farm owner must be able to patch task due date to a future date', async (done) => {
+ const due_date = faker.date.future().toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('Farm owner must not be able to patch task due date to a date in the past', async (done) => {
+ const past = faker.date.past();
+ const due_date = past.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(1));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('EO must be able to patch task due date to today', async (done) => {
+ const today = new Date();
+ const due_date = today.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('EO must be able to patch task due date to a future date', async (done) => {
+ const due_date = faker.date.future().toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('EO must not be able to patch task due date to a date in the past', async (done) => {
+ const past = faker.date.past();
+ const due_date = past.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('Managers must be able to patch task due date to today', async (done) => {
+ const today = new Date();
+ const due_date = today.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('Managers must be able to patch task due date to a future date', async (done) => {
+ const due_date = faker.date.future().toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(200);
+ const updated_task = await getTask(task_id);
+ expect(toLocal8601Extended(updated_task.due_date)).toBe(due_date);
+ done();
+ });
+ });
+
+ test('Managers must not be able to patch task due date to a date in the past', async (done) => {
+ const past = faker.date.past();
+ const due_date = past.toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(5));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(400);
+ done();
+ });
+ });
+
+ test('Farm worker must not be able to patch task due date', async (done) => {
+ const due_date = faker.date.future().toISOString().split('T')[0];
+ const patchTaskDateBody = { due_date };
+ const [{ user_id, farm_id }] = await mocks.userFarmFactory({}, fakeUserFarm(3));
+ const [{ task_id }] = await mocks.taskFactory({ promisedUser: [{ user_id }] });
+ const [{ location_id }] = await mocks.locationFactory({ promisedFarm: [{ farm_id }] });
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchTaskDateRequest({ user_id, farm_id }, patchTaskDateBody, task_id, async (err, res) => {
+ expect(res.status).toBe(403);
+ done();
+ });
+ });
+ });
});
diff --git a/packages/api/tests/taskNotification.test.js b/packages/api/tests/taskNotification.test.js
new file mode 100644
index 0000000000..f31f28d1b7
--- /dev/null
+++ b/packages/api/tests/taskNotification.test.js
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const chai = require('chai');
+const chaiHttp = require('chai-http');
+chai.use(chaiHttp);
+const server = require('../src/server');
+const knex = require('../src/util/knex');
+jest.mock('jsdom');
+jest.mock('../src/middleware/acl/checkJwt');
+const mocks = require('./mock.factories');
+const { tableCleanup } = require('./testEnvironment');
+
+describe('Task Notification Tests', () => {
+ let farmOwner;
+ let farm;
+ let farmWorker;
+ let farmWorker2;
+
+ beforeEach(async () => {
+ const middleware = require('../src/middleware/acl/checkJwt');
+
+ middleware.mockImplementation((req, res, next) => {
+ req.user = {};
+ req.user.user_id = req.get('user_id');
+ next();
+ });
+
+ [farmOwner] = await mocks.usersFactory();
+ [farm] = await mocks.farmFactory();
+ [farmWorker] = await mocks.usersFactory();
+ [farmWorker2] = await mocks.usersFactory();
+
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmOwner],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 1 }),
+ );
+
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmWorker],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 3 }),
+ );
+
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmWorker2],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 3 }),
+ );
+ });
+
+ // Clean up after test finishes
+ afterAll(async (done) => {
+ await tableCleanup(knex);
+ await knex.destroy();
+ done();
+ });
+
+ afterEach(async (done) => {
+ await knex.raw(`
+ UPDATE task SET deleted = TRUE WHERE deleted = FALSE;
+ UPDATE notification SET deleted = TRUE WHERE deleted = FALSE;
+ UPDATE notification_user SET deleted = TRUE WHERE deleted = FALSE;
+ `);
+ done();
+ });
+
+ function patchAssignTaskRequest({ user_id, farm_id }, assignee_user_id, task_id, callback) {
+ chai
+ .request(server)
+ .patch(`/task/assign/${task_id}`)
+ .set('user_id', user_id)
+ .set('farm_id', farm_id)
+ .send(assignee_user_id)
+ .end(callback);
+ }
+
+ function patchAbandonTaskRequest({ user_id, farm_id }, data, task_id, callback) {
+ chai
+ .request(server)
+ .patch(`/task/abandon/${task_id}`)
+ .set('user_id', user_id)
+ .set('farm_id', farm_id)
+ .send(data)
+ .end(callback);
+ }
+
+ describe('Task Reassignment Notification Tests', () => {
+ test('Owner will receive a reassignment notification when task has been reassigned to them from a worker', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: farmWorker.user_id,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAssignTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ { assignee_user_id: farmOwner.user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe('NOTIFICATION.TASK_REASSIGNED.TITLE');
+ done();
+ },
+ );
+ });
+
+ test('Reassigned user should have a regular assignment notification', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: farmOwner.user_id,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAssignTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ { assignee_user_id: farmWorker.user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe('NOTIFICATION.TASK_ASSIGNED.TITLE');
+ done();
+ },
+ );
+ });
+
+ test('Other workers will not receive a reassignment notification of other tasks', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: farmOwner.user_id,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAssignTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ { assignee_user_id: farmWorker.user_id },
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker2.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ },
+ );
+ });
+ });
+
+ describe('Task Abandonment Notification Tests', () => {
+ const abandonTaskRequest = {
+ abandonment_reason: 'LABOUR_ISSUE',
+ abandonment_notes: '',
+ abandon_date: '2022-05-24',
+ };
+
+ test('A worker should receive an abandonment notification when their task has been abandoned by owner', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: farmWorker.user_id,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAbandonTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ abandonTaskRequest,
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe('NOTIFICATION.TASK_ABANDONED.TITLE');
+ done();
+ },
+ );
+ });
+
+ test('Other workers should not receive an abandonment notification when a worker task has been abandoned by owner', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: farmWorker.user_id,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAbandonTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ abandonTaskRequest,
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker2.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ },
+ );
+ });
+
+ test('No abandonment notification created when an unassigned task has been abandoned by owner', async (done) => {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [{ location_id }] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [{ task_id }] = await mocks.taskFactory(
+ { promisedUser: [{ user_id: farmOwner.user_id }], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask({
+ assignee_user_id: null,
+ }),
+ );
+
+ await mocks.location_tasksFactory({
+ promisedTask: [{ task_id }],
+ promisedField: [{ location_id }],
+ });
+
+ patchAbandonTaskRequest(
+ { user_id: farmOwner.user_id, farm_id: farm.farm_id },
+ abandonTaskRequest,
+ task_id,
+ async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ },
+ );
+ });
+ });
+});
diff --git a/packages/api/tests/testEnvironment.js b/packages/api/tests/testEnvironment.js
index 00779630b9..fbde714ca9 100644
--- a/packages/api/tests/testEnvironment.js
+++ b/packages/api/tests/testEnvironment.js
@@ -15,7 +15,6 @@
const NodeEnvironment = require('jest-environment-node');
-
class TestEnvironment extends NodeEnvironment {
constructor(config) {
super(config);
@@ -34,8 +33,12 @@ class TestEnvironment extends NodeEnvironment {
}
async function tableCleanup(knex) {
- await knex('farm').whereNotNull('default_initial_location_id').update({ default_initial_location_id: null });
+ await knex('farm')
+ .whereNotNull('default_initial_location_id')
+ .update({ default_initial_location_id: null });
return knex.raw(`
+ DELETE FROM "notification_user";
+ DELETE FROM "notification";
DELETE FROM "supportTicket";
DELETE FROM "organicCertifierSurvey";
DELETE FROM "password";
@@ -110,7 +113,7 @@ async function tableCleanup(knex) {
DELETE FROM "waterBalanceSchedule";
DELETE FROM "nitrogenSchedule";
DELETE FROM "farm";
- DELETE FROM "users";
+ DELETE FROM "users" WHERE user_id <> '1';
DELETE FROM "weatherHourly";
DELETE FROM "weather";
DELETE FROM "weather_station";
diff --git a/packages/api/tests/timeNotification.test.js b/packages/api/tests/timeNotification.test.js
new file mode 100644
index 0000000000..1d9c79e0d7
--- /dev/null
+++ b/packages/api/tests/timeNotification.test.js
@@ -0,0 +1,515 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+const chai = require('chai');
+const chaiHttp = require('chai-http');
+chai.use(chaiHttp);
+const mocks = require('./mock.factories');
+const server = require('./../src/server');
+const knex = require('../src/util/knex');
+const { tableCleanup } = require('./testEnvironment');
+const { faker } = require('@faker-js/faker');
+
+jest.mock('jsdom');
+jest.mock('../src/middleware/acl/checkSchedulerJwt.js');
+
+describe('Time Based Notification Tests', () => {
+ let farmOwner;
+ let farm;
+ let isDayLaterThanUtc;
+ let fakeToday;
+
+ beforeEach(async () => {
+ // Set up a farm with a farm owner
+ [farmOwner] = await mocks.usersFactory();
+ [farm] = await mocks.farmFactory();
+ isDayLaterThanUtc = faker.datatype.boolean();
+ fakeToday = new Date();
+ if (isDayLaterThanUtc) fakeToday.setDate(fakeToday.getDate() + 1);
+
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmOwner],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 1 }),
+ );
+
+ const middleware = require('../src/middleware/acl/checkSchedulerJwt');
+ middleware.mockImplementation((req, res, next) => {
+ req.auth = {};
+ req.auth.requestTimedNotifications = true;
+ next();
+ });
+ });
+
+ async function createFullTask(defaultTaskData = {}) {
+ const [{ task_type_id }] = await mocks.task_typeFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+
+ const [task] = await mocks.taskFactory(
+ { promisedUser: [farmOwner], promisedTaskType: [{ task_type_id }] },
+ mocks.fakeTask(defaultTaskData),
+ );
+
+ const taskFamily = faker.helpers.arrayElement([
+ 'location',
+ 'management',
+ 'plant',
+ 'transplant',
+ ]);
+
+ switch (taskFamily) {
+ case 'location': {
+ const [location] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
+ break;
+ }
+ case 'management': {
+ const [plantingManagementPlan] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ await mocks.management_tasksFactory({
+ promisedTask: [task],
+ promisedPlantingManagementPlan: [plantingManagementPlan],
+ });
+ break;
+ }
+ case 'plant': {
+ const [plantingManagementPlan] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ await mocks.plant_taskFactory(
+ { promisedTask: [task] },
+ mocks.fakePlantTask({
+ planting_management_plan_id: plantingManagementPlan.planting_management_plan_id,
+ }),
+ );
+ break;
+ }
+ case 'transplant': {
+ const [mgtPlan] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ const [prevMgtPlan] = await mocks.planting_management_planFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ await mocks.transplant_taskFactory({
+ promisedTask: [task],
+ promisedMgtPlan: [mgtPlan],
+ promisedPrevMgtPlan: [prevMgtPlan],
+ });
+ break;
+ }
+ default: {
+ const [location] = await mocks.locationFactory({
+ promisedFarm: [{ farm_id: farm.farm_id }],
+ });
+ await mocks.location_tasksFactory({ promisedTask: [task], promisedField: [location] });
+ break;
+ }
+ }
+ }
+
+ function postWeeklyUnassignedTasksRequest(data, callback) {
+ const { farm_id } = data;
+ chai
+ .request(server)
+ .post(`/time_notification/weekly_unassigned_tasks/${farm_id}`)
+ .send({ isDayLaterThanUtc })
+ .end(callback);
+ }
+
+ function postDailyDueTodayTasks(data, callback) {
+ const { farm_id } = data;
+ chai
+ .request(server)
+ .post(`/time_notification/daily_due_today_tasks/${farm_id}`)
+ .send({ isDayLaterThanUtc })
+ .end(callback);
+ }
+
+ // Clean up after test finishes
+ afterAll(async (done) => {
+ await tableCleanup(knex);
+ await knex.destroy();
+ done();
+ });
+
+ afterEach(async (done) => {
+ await knex.raw(`
+ UPDATE task SET deleted = TRUE WHERE deleted = FALSE;
+ UPDATE notification SET deleted = TRUE WHERE deleted = FALSE;
+ UPDATE notification_user SET deleted = TRUE WHERE deleted = FALSE;
+ `);
+ done();
+ });
+
+ describe('Unassigned Tasks Due This Week Notification Test', () => {
+ describe('Notification Sent To All Valid Recipients Tests', () => {
+ beforeEach(async () => {
+ // Set up such that there are unassigned tasks due within the next week
+ await createFullTask({
+ due_date: faker.date.soon(6, fakeToday).toISOString().split('T')[0],
+ assignee_user_id: null,
+ });
+ });
+
+ test('Farm Owners Should Receive Notification', async (done) => {
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmOwner.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.WEEKLY_UNASSIGNED_TASKS.TITLE',
+ );
+ done();
+ });
+ });
+
+ test('Farm Managers Should Receive Notification', async (done) => {
+ const [farmManager] = await mocks.usersFactory();
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmManager],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 2 }),
+ );
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmManager.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.WEEKLY_UNASSIGNED_TASKS.TITLE',
+ );
+ done();
+ });
+ });
+
+ test('Extension Officers Should Receive Notification', async (done) => {
+ const [extensionOfficer] = await mocks.usersFactory();
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [extensionOfficer],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 5 }),
+ );
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': extensionOfficer.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.WEEKLY_UNASSIGNED_TASKS.TITLE',
+ );
+ done();
+ });
+ });
+
+ test('Farm Worker Should Not Receive Notification', async (done) => {
+ const [farmWorker] = await mocks.usersFactory();
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmWorker],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 3 }),
+ );
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user').where({
+ user_id: farmWorker.user_id,
+ deleted: false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Farm Manager at a Different Farm Should Not Receive Notification', async (done) => {
+ const [otherFarmManager] = await mocks.usersFactory();
+ const [otherFarm] = await mocks.farmFactory();
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [otherFarmManager],
+ promisedFarm: [otherFarm],
+ },
+ mocks.fakeUserFarm({ role_id: 2 }),
+ );
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user').where({
+ user_id: otherFarmManager.user_id,
+ deleted: false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+ });
+ describe('Notification Only Sent Under Correct Conditions Tests', () => {
+ test('Not Sent When There Are No Unassigned Tasks', (done) => {
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification').where({ deleted: false });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Not Sent When The Only Unassigned Tasks Are Due Later Then 7 Days', async (done) => {
+ const laterThanOneWeekFromNow = fakeToday;
+ laterThanOneWeekFromNow.setDate(laterThanOneWeekFromNow.getDate() + 8);
+ const laterThanOneWeekFromNowStr = laterThanOneWeekFromNow.toISOString().split('T')[0];
+
+ await createFullTask({
+ due_date: laterThanOneWeekFromNowStr,
+ assignee_user_id: null,
+ });
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification').where({ deleted: false });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Not Sent When The Only Tasks Due This Week Are Assigned', async (done) => {
+ await createFullTask({
+ due_date: faker.date.soon(6, fakeToday).toISOString().split('T')[0],
+ assignee_user_id: farmOwner.user_id,
+ });
+
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification').where({ deleted: false });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Sent When There Are Unassigned Tasks Due Within The Next 7 days', async (done) => {
+ await createFullTask({
+ due_date: faker.date.soon(6, fakeToday).toISOString().split('T')[0],
+ assignee_user_id: null,
+ });
+ postWeeklyUnassignedTasksRequest({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification').where({ deleted: false });
+ expect(notifications.length).toBe(1);
+ done();
+ });
+ });
+ });
+ });
+
+ describe('Tasks Due Today Notification Test', () => {
+ let farmWorker;
+ beforeEach(async () => {
+ [farmWorker] = await mocks.usersFactory();
+
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmWorker],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 3 }),
+ );
+ });
+
+ describe('Notification sent tests', () => {
+ test('Farm worker should receive a due today notification', async (done) => {
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: farmWorker.user_id,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification').where({
+ 'notification.farm_id': farm.farm_id,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.DAILY_TASKS_DUE_TODAY.TITLE',
+ );
+ done();
+ });
+ });
+
+ test('Farm owner should receive a due today notification', async (done) => {
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: farmOwner.user_id,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification').where({
+ 'notification.farm_id': farm.farm_id,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(1);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.DAILY_TASKS_DUE_TODAY.TITLE',
+ );
+ done();
+ });
+ });
+
+ test('Multiple farm workers in the same farm should receive a due today notification', async (done) => {
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: farmOwner.user_id,
+ });
+
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: farmWorker.user_id,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification').where({
+ 'notification.farm_id': farm.farm_id,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(2);
+ expect(notifications[0].title.translation_key).toBe(
+ 'NOTIFICATION.DAILY_TASKS_DUE_TODAY.TITLE',
+ );
+ done();
+ });
+ });
+ });
+
+ describe('Notification not sent tests', () => {
+ test('Notification not sent if no active workers in a farm', async (done) => {
+ const [farm2] = await mocks.farmFactory();
+ await createFullTask({
+ due_date: faker.date.soon(2, fakeToday).toISOString().split('T')[0],
+ assignee_user_id: farmWorker.user_id,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm2.farm_id }, async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification').where({
+ 'notification.farm_id': farm2.farm_id,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Other farm worker should not receive a due today notification of another worker', async (done) => {
+ const [farmWorker2] = await mocks.usersFactory();
+ await mocks.userFarmFactory(
+ {
+ promisedUser: [farmWorker2],
+ promisedFarm: [farm],
+ },
+ mocks.fakeUserFarm({ role_id: 3 }),
+ );
+
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: farmWorker.user_id,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(201);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker2.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+
+ test('Farm workers should not receive a due today notification of unassigned tasks', async (done) => {
+ await createFullTask({
+ due_date: fakeToday.toISOString().split('T')[0],
+ assignee_user_id: null,
+ });
+
+ postDailyDueTodayTasks({ farm_id: farm.farm_id }, async (err, res) => {
+ expect(res.status).toBe(200);
+ const notifications = await knex('notification_user')
+ .join(
+ 'notification',
+ 'notification.notification_id',
+ 'notification_user.notification_id',
+ )
+ .where({
+ 'notification_user.user_id': farmWorker.user_id,
+ 'notification_user.deleted': false,
+ 'notification.deleted': false,
+ });
+ expect(notifications.length).toBe(0);
+ done();
+ });
+ });
+ });
+ });
+});
diff --git a/packages/api/tests/userFarm.test.js b/packages/api/tests/userFarm.test.js
index 2dbfaddf6d..4e8daf8d12 100644
--- a/packages/api/tests/userFarm.test.js
+++ b/packages/api/tests/userFarm.test.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (farm.test.js) is part of LiteFarm.
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,10 +13,8 @@
* GNU General Public License for more details, see .
*/
-
const chai = require('chai');
const chaiHttp = require('chai-http');
-const moment = require('moment')
chai.use(chaiHttp);
const server = require('./../src/server');
const knex = require('../src/util/knex');
@@ -24,141 +22,182 @@ const { tableCleanup } = require('./testEnvironment');
jest.mock('jsdom');
jest.mock('../src/middleware/acl/checkJwt');
jest.mock('../src/templates/sendEmailTemplate');
-const mocks = require('./mock.factories');
-let faker = require('faker');
+const mocks = require('./mock.factories');
+const { faker } = require('@faker-js/faker');
const userFarmModel = require('../src/models/userFarmModel');
const userModel = require('../src/models/userModel');
describe('User Farm Tests', () => {
let middleware;
- function getUserFarmsOfUserRequest({user_id}, callback) {
- chai.request(server).get(`/user_farm/user/${user_id}`)
- .end(callback);
+ function getUserFarmsOfUserRequest({ user_id }, callback) {
+ chai.request(server).get(`/user_farm/user/${user_id}`).end(callback);
}
// note: the object that is sent should be adjusted to not include consent_version
- function updateUserFarmConsentRequest({user_id, farm_id, params_user_id, params_farm_id}, callback) {
- chai.request(server).patch(`/user_farm/consent/farm/${params_farm_id || farm_id}/user/${params_user_id || user_id}`)
+ function updateUserFarmConsentRequest(
+ { user_id, farm_id, params_user_id, params_farm_id },
+ callback,
+ ) {
+ chai
+ .request(server)
+ .patch(
+ `/user_farm/consent/farm/${params_farm_id || farm_id}/user/${params_user_id || user_id}`,
+ )
.set('user_id', user_id)
.set('farm_id', farm_id)
- .send({has_consent: true, consent_version: '3.0'})
- .end(callback);
- }
-
- function updateOnboarding(targetUser, {user_id, farm_id}, callback) {
- chai.request(server).patch(`/user_farm/onboarding/farm/${farm_id}/user/${user_id}`)
- .send({step_one: targetUser.step_one, step_one_end: targetUser.step_one_end, step_two: targetUser.step_two, step_two_end: targetUser.step_two_end, step_three: targetUser.step_three, step_three_end: targetUser.step_three_end, step_four: targetUser.step_four, step_four_end: targetUser.step_four_end, step_five: targetUser.step_five, step_five_end: targetUser.step_five_end})
+ .send({ has_consent: true, consent_version: '3.0' })
.end(callback);
}
- function addUserFarmRequest(data, {user_id = owner.user_id, farm_id = farm.farm_id}, callback) {
- chai.request(server).post(`/user_farm`)
- .set('Content-Type', 'application/json')
- .set('user_id', user_id)
- .set('farm_id', farm_id)
- .send(data)
+ function updateOnboarding(targetUser, { user_id, farm_id }, callback) {
+ chai
+ .request(server)
+ .patch(`/user_farm/onboarding/farm/${farm_id}/user/${user_id}`)
+ .send({
+ step_one: targetUser.step_one,
+ step_one_end: targetUser.step_one_end,
+ step_two: targetUser.step_two,
+ step_two_end: targetUser.step_two_end,
+ step_three: targetUser.step_three,
+ step_three_end: targetUser.step_three_end,
+ step_four: targetUser.step_four,
+ step_four_end: targetUser.step_four_end,
+ step_five: targetUser.step_five,
+ step_five_end: targetUser.step_five_end,
+ })
.end(callback);
}
- function getUserFarmsOfFarmRequest({user_id, farm_id}, callback) {
- chai.request(server).get(`/user_farm/farm/${farm_id}`)
+ // function addUserFarmRequest(data, { user_id = owner.user_id, farm_id = farm.farm_id }, callback) {
+ // chai.request(server).post('/user_farm')
+ // .set('Content-Type', 'application/json')
+ // .set('user_id', user_id)
+ // .set('farm_id', farm_id)
+ // .send(data)
+ // .end(callback);
+ // }
+
+ function getUserFarmsOfFarmRequest({ user_id, farm_id }, callback) {
+ chai
+ .request(server)
+ .get(`/user_farm/farm/${farm_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.end(callback);
}
- function getActiveUserFarmsOfFarmRequest({user_id, farm_id}, callback) {
- chai.request(server).get(`/user_farm/active/farm/${farm_id}`)
+ function getActiveUserFarmsOfFarmRequest({ user_id, farm_id }, callback) {
+ chai
+ .request(server)
+ .get(`/user_farm/active/farm/${farm_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.end(callback);
}
// TODO: eventually change how role is passed into endpoint
- function updateRoleRequest(role_id, {user_id, farm_id}, target_user_id, callback) {
- chai.request(server).patch(`/user_farm/role/farm/${farm_id}/user/${target_user_id}`)
+ function updateRoleRequest(role_id, { user_id, farm_id }, target_user_id, callback) {
+ chai
+ .request(server)
+ .patch(`/user_farm/role/farm/${farm_id}/user/${target_user_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
- .send({role_id})
+ .send({ role_id })
.end(callback);
}
- function updateStatusRequest(status, {user_id, farm_id}, target_user_id, callback) {
- chai.request(server).patch(`/user_farm/status/farm/${farm_id}/user/${target_user_id}`)
+ function updateStatusRequest(status, { user_id, farm_id }, target_user_id, callback) {
+ chai
+ .request(server)
+ .patch(`/user_farm/status/farm/${farm_id}/user/${target_user_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
- .send({status})
+ .send({ status })
.end(callback);
}
- function updateWageRequest(wage, {user_id, farm_id}, target_user_id, callback) {
- chai.request(server).patch(`/user_farm/wage/farm/${farm_id}/user/${target_user_id}`)
+ function updateWageRequest(wage, { user_id, farm_id }, target_user_id, callback) {
+ chai
+ .request(server)
+ .patch(`/user_farm/wage/farm/${farm_id}/user/${target_user_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
- .send({wage})
+ .send({ wage })
.end(callback);
}
- function invitePseudoUserRequest(data, {user_id, farm_id, params_user_id, params_farm_id}, callback) {
- chai.request(server).post(`/user_farm/invite/farm/${params_farm_id || farm_id}/user/${params_user_id || user_id}`)
+ function invitePseudoUserRequest(
+ data,
+ { user_id, farm_id, params_user_id, params_farm_id },
+ callback,
+ ) {
+ chai
+ .request(server)
+ .post(`/user_farm/invite/farm/${params_farm_id || farm_id}/user/${params_user_id || user_id}`)
.set('user_id', user_id)
.set('farm_id', farm_id)
.send(data)
.end(callback);
}
- function fakeUserFarm(role_id=1, status='Active', has_consent=true) {
- return ({
- ...mocks.fakeUserFarm(),
- role_id,
- status,
- has_consent
- });
- }
+ // function fakeUserFarm(role_id=1, status='Active', has_consent=true) {
+ // return ({
+ // ...mocks.fakeUserFarm(),
+ // role_id,
+ // status,
+ // has_consent,
+ // });
+ // }
// initialize a user and a farm
- async function setupUserFarm({role_id=1, status='Active', has_consent=true}) {
+ async function setupUserFarm({ role_id = 1, status = 'Active', has_consent = true }) {
const userFarmInfo = {
role_id,
status,
- has_consent
- }
- let [ farm ] = await mocks.farmFactory();
- let [ user ] = await mocks.usersFactory();
- await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm]}, userFarmInfo);
- return {user, farm};
+ has_consent,
+ };
+ const [farm] = await mocks.farmFactory();
+ const [user] = await mocks.usersFactory();
+ await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm] }, userFarmInfo);
+ return { user, farm };
}
// generate user to a given farm
- async function createUserFarmAtFarm({role_id=1, status='Active', has_consent=true}, farm) {
+ async function createUserFarmAtFarm(
+ { role_id = 1, status = 'Active', has_consent = true },
+ farm,
+ ) {
const userFarmInfo = {
role_id,
status,
- has_consent
- }
- const [ user ] = await mocks.usersFactory();
- await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm]}, userFarmInfo);
+ has_consent,
+ };
+ const [user] = await mocks.usersFactory();
+ await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm] }, userFarmInfo);
return user;
}
// add given user to a newly generated farm
- async function createUserFarmForUser({role_id=1, status='Active', has_consent=true}, user) {
+ async function createUserFarmForUser(
+ { role_id = 1, status = 'Active', has_consent = true },
+ user,
+ ) {
const userFarmInfo = {
role_id,
status,
- has_consent
- }
- const [ farm ] = await mocks.farmFactory();
- await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm]}, userFarmInfo);
+ has_consent,
+ };
+ const [farm] = await mocks.farmFactory();
+ await mocks.userFarmFactory({ promisedUser: [user], promisedFarm: [farm] }, userFarmInfo);
return farm;
}
async function setupFarmWithVariousUsers() {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const manager = await createUserFarmAtFarm({role_id: 2}, farm);
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const inactiveUser = await createUserFarmAtFarm({role_id: 3, status: 'Inactive'}, farm);
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const manager = await createUserFarmAtFarm({ role_id: 2 }, farm);
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
+ const inactiveUser = await createUserFarmAtFarm({ role_id: 3, status: 'Inactive' }, farm);
return { owner, manager, worker, inactiveUser, farm };
}
@@ -172,23 +211,23 @@ describe('User Farm Tests', () => {
});
afterAll(async (done) => {
- console.time('cleanup')
+ console.time('cleanup');
await tableCleanup(knex);
- console.timeEnd('cleanup')
- console.time('destroy')
+ console.timeEnd('cleanup');
+ console.time('destroy');
await knex.destroy();
- console.timeEnd('destroy')
- console.log('calling done');
+ console.timeEnd('destroy');
done();
});
test('Get all user farms of a user', async (done) => {
- const {user, farm} = await setupUserFarm({});
- const farm2 = await createUserFarmForUser({}, user);
- const farm3 = await createUserFarmForUser({}, user);
+ const { user } = await setupUserFarm({});
+ await createUserFarmForUser({}, user);
+ await createUserFarmForUser({}, user);
- getUserFarmsOfUserRequest({user_id: user.user_id}, async (err, res) => {
+ getUserFarmsOfUserRequest({ user_id: user.user_id }, async (err, res) => {
+ expect(err).toEqual(null);
expect(res.status).toBe(200);
expect(res.body.length).toBe(3);
done();
@@ -196,617 +235,945 @@ describe('User Farm Tests', () => {
});
test('Update consent status for user farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const noConsentUser = await createUserFarmAtFarm({role_id: 3, has_consent: false}, farm);
+ const { farm } = await setupUserFarm({});
+ const noConsentUser = await createUserFarmAtFarm({ role_id: 3, has_consent: false }, farm);
let targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
expect(targetUser.has_consent).toBe(false);
- updateUserFarmConsentRequest({user_id: noConsentUser.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
- expect(targetUser.has_consent).toBe(true);
- done();
- });
+ updateUserFarmConsentRequest(
+ { user_id: noConsentUser.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
+ expect(targetUser.has_consent).toBe(true);
+ done();
+ },
+ );
});
test('Invited user should not update userFarm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const noConsentUser = await createUserFarmAtFarm({role_id: 3, has_consent: false, status: 'Invited'}, farm);
- let targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
+ const { farm } = await setupUserFarm({});
+ const noConsentUser = await createUserFarmAtFarm(
+ { role_id: 3, has_consent: false, status: 'Invited' },
+ farm,
+ );
+ const targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
expect(targetUser.has_consent).toBe(false);
- updateUserFarmConsentRequest({user_id: noConsentUser.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateUserFarmConsentRequest(
+ { user_id: noConsentUser.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Inactive user should not update userFarm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const noConsentUser = await createUserFarmAtFarm({role_id: 3, has_consent: false, status: 'Inactive'}, farm);
- let targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
+ const { farm } = await setupUserFarm({});
+ const noConsentUser = await createUserFarmAtFarm(
+ { role_id: 3, has_consent: false, status: 'Inactive' },
+ farm,
+ );
+ const targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
expect(targetUser.has_consent).toBe(false);
- updateUserFarmConsentRequest({user_id: noConsentUser.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateUserFarmConsentRequest(
+ { user_id: noConsentUser.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Owner should not accept/reject consent on behalf of another user', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const noConsentUser = await createUserFarmAtFarm({role_id: 3, has_consent: false, status: 'Invited'}, farm);
- let targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const noConsentUser = await createUserFarmAtFarm(
+ { role_id: 3, has_consent: false, status: 'Invited' },
+ farm,
+ );
+ const targetUser = await userFarmModel.query().where('user_id', noConsentUser.user_id).first();
expect(targetUser.has_consent).toBe(false);
- updateUserFarmConsentRequest({user_id: owner.user_id, farm_id: farm.farm_id, params_user_id:noConsentUser}, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateUserFarmConsentRequest(
+ { user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: noConsentUser },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Update step_one of farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- let targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
expect(targetUser.step_one).toBe(false);
targetUser.step_one = true;
targetUser.step_one_end = '2020-10-21 14:43:06.718035-07';
- updateOnboarding(targetUser,{user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
- expect(targetUser1.step_one).toBe(true);
- expect(targetUser1.step_one_end).toBe(targetUser.step_one_end);
- done();
- });
+ updateOnboarding(
+ targetUser,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
+ expect(targetUser1.step_one).toBe(true);
+ expect(targetUser1.step_one_end).toBe(targetUser.step_one_end);
+ done();
+ },
+ );
});
test('Update step_two of farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- let targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
expect(targetUser.step_two).toBe(false);
targetUser.step_two = true;
targetUser.step_two_end = '2020-10-21 14:43:06.718035-07';
- updateOnboarding(targetUser,{user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
- expect(targetUser1.step_two).toBe(true);
- expect(targetUser1.step_two_end).toBe(targetUser.step_two_end);
- done();
- });
+ updateOnboarding(
+ targetUser,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
+ expect(targetUser1.step_two).toBe(true);
+ expect(targetUser1.step_two_end).toBe(targetUser.step_two_end);
+ done();
+ },
+ );
});
test('Update step_three of farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- let targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
expect(targetUser.step_three).toBe(false);
targetUser.step_three = true;
targetUser.step_three_end = '2020-10-21 14:43:06.718035-07';
- updateOnboarding(targetUser,{user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
- expect(targetUser1.step_three).toBe(true);
- expect(targetUser1.step_three_end).toBe(targetUser.step_three_end);
- done();
- });
+ updateOnboarding(
+ targetUser,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
+ expect(targetUser1.step_three).toBe(true);
+ expect(targetUser1.step_three_end).toBe(targetUser.step_three_end);
+ done();
+ },
+ );
});
test('Update step_four of farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- let targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
expect(targetUser.step_four).toBe(false);
targetUser.step_four = true;
targetUser.step_four_end = '2020-10-21 14:43:06.718035-07';
- updateOnboarding(targetUser,{user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
- expect(targetUser1.step_four).toBe(true);
- expect(targetUser1.step_four_end).toBe(targetUser.step_four_end);
- done();
- });
+ updateOnboarding(
+ targetUser,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
+ expect(targetUser1.step_four).toBe(true);
+ expect(targetUser1.step_four_end).toBe(targetUser.step_four_end);
+ done();
+ },
+ );
});
test('Update step_five of farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- let targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
+ const { user: owner, farm } = await setupUserFarm({});
+ const targetUser = await userFarmModel.query().where('user_id', owner.user_id).first();
expect(targetUser.step_five).toBe(false);
targetUser.step_five = true;
targetUser.step_five_end = '2020-10-21 14:43:06.718035-07';
- updateOnboarding(targetUser,{user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
- expect(targetUser1.step_five).toBe(true);
- expect(targetUser1.step_five_end).toBe(targetUser.step_five_end);
- done();
- });
+ updateOnboarding(
+ targetUser,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const targetUser1 = await userFarmModel.query().where('user_id', owner.user_id).first();
+ expect(targetUser1.step_five).toBe(true);
+ expect(targetUser1.step_five_end).toBe(targetUser.step_five_end);
+ done();
+ },
+ );
});
describe('Get user farm info by farm: authorization tests', () => {
describe('Get all user farm info', () => {
test('Owner should get all user farm info', async (done) => {
- const {owner, farm} = await setupFarmWithVariousUsers();
- getUserFarmsOfFarmRequest({user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(4);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeDefined();
- for(const userFarm of res.body){
- if(userFarm.user_id === owner.user_id){
- expect(userFarm.gender).toBe(owner.gender);
- expect(userFarm.birth_year).toBe(owner.birth_year);
- }else{
- expect(userFarm.gender).toBeUndefined();
- expect(userFarm.birth_year).toBeUndefined();
+ const { owner, farm } = await setupFarmWithVariousUsers();
+ getUserFarmsOfFarmRequest(
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(4);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeDefined();
+ for (const userFarm of res.body) {
+ if (userFarm.user_id === owner.user_id) {
+ expect(userFarm.gender).toBe(owner.gender);
+ expect(userFarm.birth_year).toBe(owner.birth_year);
+ } else {
+ expect(userFarm.gender).toBeUndefined();
+ expect(userFarm.birth_year).toBeUndefined();
+ }
}
- }
- done();
- });
+ done();
+ },
+ );
});
test('Manager should get all user farm info', async (done) => {
- const {manager, farm} = await setupFarmWithVariousUsers();
- getUserFarmsOfFarmRequest({user_id: manager.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(4);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeDefined();
- done();
- });
+ const { manager, farm } = await setupFarmWithVariousUsers();
+ getUserFarmsOfFarmRequest(
+ { user_id: manager.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(4);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeDefined();
+ done();
+ },
+ );
});
test('Worker should get all user farm limited info', async (done) => {
- const {worker, farm} = await setupFarmWithVariousUsers();
- getUserFarmsOfFarmRequest({user_id: worker.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(4);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeUndefined();
- // check if worker can view appropriate info
- expect(res.body[0].first_name).toBeDefined();
- expect(res.body[0].last_name).toBeDefined();
- expect(res.body[0].profile_picture).toBeDefined();
- expect(res.body[0].phone_number).toBeDefined();
- expect(res.body[0].email).toBeDefined();
- expect(res.body[0].role).toBeDefined();
- expect(res.body[0].status).toBeDefined();
- done();
- });
+ const { worker, farm } = await setupFarmWithVariousUsers();
+ getUserFarmsOfFarmRequest(
+ { user_id: worker.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(4);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeUndefined();
+ // check if worker can view appropriate info
+ expect(res.body[0].first_name).toBeDefined();
+ expect(res.body[0].last_name).toBeDefined();
+ expect(res.body[0].profile_picture).toBeDefined();
+ expect(res.body[0].phone_number).toBeDefined();
+ expect(res.body[0].email).toBeDefined();
+ expect(res.body[0].role).toBeDefined();
+ expect(res.body[0].status).toBeDefined();
+ done();
+ },
+ );
});
test('Return 403 if unauthorized user tries to get any user farm info', async (done) => {
- const {farm} = await setupFarmWithVariousUsers();
- const {user: unauthorizedUser, farm2} = await setupUserFarm({role_id: 1});
- getUserFarmsOfFarmRequest({user_id: unauthorizedUser.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ const { farm } = await setupFarmWithVariousUsers();
+ const { user: unauthorizedUser } = await setupUserFarm({ role_id: 1 });
+ getUserFarmsOfFarmRequest(
+ { user_id: unauthorizedUser.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
describe('Get active user farm info', () => {
test('Owner should get active user farm info', async (done) => {
- const {owner, farm} = await setupFarmWithVariousUsers();
- getActiveUserFarmsOfFarmRequest({user_id: owner.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(3);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeDefined();
- done();
- });
+ const { owner, farm } = await setupFarmWithVariousUsers();
+ getActiveUserFarmsOfFarmRequest(
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(3);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeDefined();
+ done();
+ },
+ );
});
test('Manager should get active user farm info', async (done) => {
- const {manager, farm} = await setupFarmWithVariousUsers();
- getActiveUserFarmsOfFarmRequest({user_id: manager.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(3);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeDefined();
- done();
- });
+ const { manager, farm } = await setupFarmWithVariousUsers();
+ getActiveUserFarmsOfFarmRequest(
+ { user_id: manager.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(3);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeDefined();
+ done();
+ },
+ );
});
test('Worker should get active user farm limited info', async (done) => {
- const {worker, farm} = await setupFarmWithVariousUsers();
- getActiveUserFarmsOfFarmRequest({user_id: worker.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(200);
- expect(res.body.length).toBe(3);
- // check if sensitive info can be accessed
- expect(res.body[0].address).toBeUndefined();
- // check if worker can view appropriate info
- expect(res.body[0].first_name).toBeDefined();
- expect(res.body[0].last_name).toBeDefined();
- expect(res.body[0].profile_picture).toBeDefined();
- expect(res.body[0].phone_number).toBeDefined();
- expect(res.body[0].email).toBeDefined();
- expect(res.body[0].role).toBeDefined();
- expect(res.body[0].status).toBeDefined();
- done();
- });
+ const { worker, farm } = await setupFarmWithVariousUsers();
+ getActiveUserFarmsOfFarmRequest(
+ { user_id: worker.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ expect(res.body.length).toBe(3);
+ // check if sensitive info can be accessed
+ expect(res.body[0].address).toBeUndefined();
+ // check if worker can view appropriate info
+ expect(res.body[0].first_name).toBeDefined();
+ expect(res.body[0].last_name).toBeDefined();
+ expect(res.body[0].profile_picture).toBeDefined();
+ expect(res.body[0].phone_number).toBeDefined();
+ expect(res.body[0].email).toBeDefined();
+ expect(res.body[0].role).toBeDefined();
+ expect(res.body[0].status).toBeDefined();
+ done();
+ },
+ );
});
test('Return 403 if unauthorized user tries to get active user farm info', async (done) => {
- const {farm} = await setupFarmWithVariousUsers();
- const {user: unauthorizedUser, farm: farm2} = await setupUserFarm({role_id: 1});
- getActiveUserFarmsOfFarmRequest({user_id: unauthorizedUser.user_id, farm_id: farm.farm_id}, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ const { farm } = await setupFarmWithVariousUsers();
+ const { user: unauthorizedUser } = await setupUserFarm({ role_id: 1 });
+ getActiveUserFarmsOfFarmRequest(
+ { user_id: unauthorizedUser.user_id, farm_id: farm.farm_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
});
- xdescribe('Add user farm: authorization tests', () => {
- let userFarmToAdd;
- beforeEach(async () => {
- userFarmToAdd = fakeUserFarm();
- });
-
- test('Owner should successfully add user farm', async (done) => {
- addUserFarmRequest(userFarmToAdd, {user_id: owner.user_id}, async (err, res) => {
- expect(res.status).toBe(201);
- const addedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id);
- addedUserFarm = addedUserFarm[addedUserFarm.length - 1];
- expect(addedUserFarm.role_id).toBe(userFarmToAdd.role_id);
- expect(addedUserFarm.status).toBe(userFarmToAdd.status);
- expect(addedUserFarm.has_consent).toBe(userFarmToAdd.has_consent);
- done();
- });
- });
- });
+ // xdescribe('Add user farm: authorization tests', () => {
+ // let userFarmToAdd;
+ // beforeEach(async () => {
+ // userFarmToAdd = fakeUserFarm();
+ // });
+
+ // test('Owner should successfully add user farm', async (done) => {
+ // addUserFarmRequest(userFarmToAdd, { user_id: owner.user_id }, async (err, res) => {
+ // expect(res.status).toBe(201);
+ // const addedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id);
+ // addedUserFarm = addedUserFarm[addedUserFarm.length - 1];
+ // expect(addedUserFarm.role_id).toBe(userFarmToAdd.role_id);
+ // expect(addedUserFarm.status).toBe(userFarmToAdd.status);
+ // expect(addedUserFarm.has_consent).toBe(userFarmToAdd.has_consent);
+ // done();
+ // });
+ // });
+ // });
describe('Update user farm: authorization tests', () => {
describe('Update user farm role', () => {
// TODO: eventually change how role is passed into endpoint
test('Owner should update user farm role', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const target_role = 'Manager';
+ const { user: owner, farm } = await setupUserFarm({});
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const target_role_id = 2;
const target_user_id = worker.user_id;
- updateRoleRequest(target_role_id, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.role_id).toBe(target_role_id);
- done();
- });
+ updateRoleRequest(
+ target_role_id,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.role_id).toBe(target_role_id);
+ done();
+ },
+ );
});
test('Manager should update user farm role', async (done) => {
- const {user: manager, farm} = await setupUserFarm({role_id: 2});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const target_role = 'Manager';
+ const { user: manager, farm } = await setupUserFarm({ role_id: 2 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const target_role_id = 2;
const target_user_id = worker.user_id;
- updateRoleRequest(target_role_id, {user_id: manager.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.role_id).toBe(target_role_id);
- done();
- });
+ updateRoleRequest(
+ target_role_id,
+ { user_id: manager.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.role_id).toBe(target_role_id);
+ done();
+ },
+ );
});
test('Return 403 if worker tries to update user farm role', async (done) => {
- const {manager, worker, farm} = await setupFarmWithVariousUsers();
+ const { manager, worker, farm } = await setupFarmWithVariousUsers();
const target_role = 'Worker';
- const target_role_id = 3;
const target_user_id = manager.user_id;
- updateRoleRequest(target_role, {user_id: worker.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateRoleRequest(
+ target_role,
+ { user_id: worker.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Return 403 if unauthorized user tries to update user farm role', async (done) => {
- const {manager, farm} = await setupFarmWithVariousUsers();
- const {user: unauthorizedUser, farm2} = await setupUserFarm({role_id: 1});
+ const { manager, farm } = await setupFarmWithVariousUsers();
+ const { user: unauthorizedUser } = await setupUserFarm({ role_id: 1 });
const target_role = 'Worker';
- const target_role_id = 3;
const target_user_id = manager.user_id;
- updateRoleRequest(target_role, {user_id: unauthorizedUser.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateRoleRequest(
+ target_role,
+ { user_id: unauthorizedUser.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Return 400 if last owner/Manager tries to set themselves as standard worker', async (done) => {
- const {owner, manager, farm} = await setupFarmWithVariousUsers();
+ const { owner, manager, farm } = await setupFarmWithVariousUsers();
const target_role = 'Worker';
const target_role_id = 3;
let target_user_id = manager.user_id;
// turn manager to worker
- updateRoleRequest(target_role_id, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- let updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.role_id).toBe(target_role_id);
- target_user_id = owner.user_id;
- // try to turn owner to worker
- updateRoleRequest(target_role, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(400);
- done();
- });
- });
+ updateRoleRequest(
+ target_role_id,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.role_id).toBe(target_role_id);
+ target_user_id = owner.user_id;
+ // try to turn owner to worker
+ updateRoleRequest(
+ target_role,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(400);
+ done();
+ },
+ );
+ },
+ );
});
test('Return 404 if owner tries to update user farm role that is not part of their farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({});
- const {user: unauthorizedUser, farm: farm2} = await setupUserFarm({});
- const target_role = 'Manager';
+ const { user: owner, farm } = await setupUserFarm({});
+ const { user: unauthorizedUser } = await setupUserFarm({});
const target_role_id = 2;
const target_user_id = unauthorizedUser.user_id;
- updateRoleRequest(target_role_id, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(404);
- done();
- });
+ updateRoleRequest(
+ target_role_id,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(404);
+ done();
+ },
+ );
});
});
describe('Update user farm status', () => {
test('Owner should update user farm status', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const target_status = 'Inactive';
const target_user_id = worker.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.status).toBe(target_status);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.status).toBe(target_status);
+ done();
+ },
+ );
});
test('Manager should update user farm status', async (done) => {
- const {user: manager, farm} = await setupUserFarm({role_id: 2});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { user: manager, farm } = await setupUserFarm({ role_id: 2 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const target_status = 'Inactive';
const target_user_id = worker.user_id;
- updateStatusRequest(target_status, {user_id: manager.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.status).toBe(target_status);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: manager.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.status).toBe(target_status);
+ done();
+ },
+ );
});
test('Return 403 if worker tries to update user farm status', async (done) => {
- const {user: manager, farm} = await setupUserFarm({role_id: 2});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { user: manager, farm } = await setupUserFarm({ role_id: 2 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const target_status = 'Inactive';
const target_user_id = manager.user_id;
- updateStatusRequest(target_status, {user_id: worker.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: worker.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Return 403 if unauthorized user tries to update user farm status', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const {user: unauthorizedUser, farm: farm2} = await setupUserFarm({role_id: 1});
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const { user: unauthorizedUser } = await setupUserFarm({ role_id: 1 });
const target_status = 'Inactive';
const target_user_id = owner.user_id;
- updateStatusRequest(target_status, {user_id: unauthorizedUser.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: unauthorizedUser.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Allowed status change: Inactive -> Invited', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const inactiveUser = await createUserFarmAtFarm({role_id: 3, status: 'Inactive'}, farm);
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const inactiveUser = await createUserFarmAtFarm({ role_id: 3, status: 'Inactive' }, farm);
const target_status = 'Invited';
const target_user_id = inactiveUser.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.status).toBe(target_status);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.status).toBe(target_status);
+ done();
+ },
+ );
});
test('Allowed status change: Inactive -> Active', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const inactiveUser = await createUserFarmAtFarm({role_id: 3, status: 'Inactive'}, farm);
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const inactiveUser = await createUserFarmAtFarm({ role_id: 3, status: 'Inactive' }, farm);
const target_status = 'Active';
const target_user_id = inactiveUser.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id , farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- done();
- });
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ done();
+ },
+ );
});
});
- test('Allowed status change: Invited -> Inactive', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const invitedUser = await createUserFarmAtFarm({role_id: 3, status: 'Invited'}, farm);
- const target_status = 'Inactive';
- const target_user_id = invitedUser.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
+ test('Allowed status change: Invited -> Inactive', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const invitedUser = await createUserFarmAtFarm({ role_id: 3, status: 'Invited' }, farm);
+ const target_status = 'Inactive';
+ const target_user_id = invitedUser.user_id;
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
expect(updatedUserFarm.status).toBe(target_status);
done();
- });
- });
+ },
+ );
+ });
- test('Forbidden status change: Invited -> Active', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const invitedUser = await createUserFarmAtFarm({role_id: 3, status: 'Invited'}, farm);
- const target_status = 'Active';
- const target_user_id = invitedUser.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
+ test('Forbidden status change: Invited -> Active', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const invitedUser = await createUserFarmAtFarm({ role_id: 3, status: 'Invited' }, farm);
+ const target_status = 'Active';
+ const target_user_id = invitedUser.user_id;
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
expect(res.status).toBe(400);
done();
- });
- });
+ },
+ );
+ });
- test('Forbidden status change: Active -> Invited', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const target_status = 'Invited';
- const target_user_id = worker.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
+ test('Forbidden status change: Active -> Invited', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
+ const target_status = 'Invited';
+ const target_user_id = worker.user_id;
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
expect(res.status).toBe(400);
done();
- });
- });
+ },
+ );
+ });
- test('Allowed status change: Active -> Inactive', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const target_status = 'Inactive';
- const target_user_id = worker.user_id;
- updateStatusRequest(target_status, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
+ test('Allowed status change: Active -> Inactive', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
+ const target_status = 'Inactive';
+ const target_user_id = worker.user_id;
+ updateStatusRequest(
+ target_status,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
expect(updatedUserFarm.status).toBe(target_status);
done();
- });
- });
+ },
+ );
+ });
describe('Update user farm wage', () => {
test('Owner should update user farm wage', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const wage = {
type: 'hourly',
amount: 23,
};
const target_user_id = worker.user_id;
- updateWageRequest(wage, {user_id: owner.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.wage).toEqual(wage);
- done();
- });
+ updateWageRequest(
+ wage,
+ { user_id: owner.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.wage).toEqual(wage);
+ done();
+ },
+ );
});
test('Manager should update user farm wage', async (done) => {
- const {user: manager, farm} = await setupUserFarm({role_id: 2});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { user: manager, farm } = await setupUserFarm({ role_id: 2 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const wage = {
type: 'annually',
amount: 50000,
};
const target_user_id = worker.user_id;
- updateWageRequest(wage, {user_id: manager.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(200);
- const updatedUserFarm = await userFarmModel.query().where('farm_id', farm.farm_id).andWhere('user_id', target_user_id).first();
- expect(updatedUserFarm.wage).toEqual(wage);
- done();
- });
+ updateWageRequest(
+ wage,
+ { user_id: manager.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(200);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .where('farm_id', farm.farm_id)
+ .andWhere('user_id', target_user_id)
+ .first();
+ expect(updatedUserFarm.wage).toEqual(wage);
+ done();
+ },
+ );
});
test('Return 403 if worker tries to update user farm wage', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
+ const { farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
const wage = {
type: 'hourly',
amount: 50000,
};
const target_user_id = worker.user_id;
- updateWageRequest(wage, {user_id: worker.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateWageRequest(
+ wage,
+ { user_id: worker.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
test('Return 403 if unauthorized user tries to update user farm wage', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const worker = await createUserFarmAtFarm({role_id: 3}, farm);
- const {user: unauthorizedUser, farm: farm2} = await setupUserFarm({role_id: 1});
+ const { farm } = await setupUserFarm({ role_id: 1 });
+ const worker = await createUserFarmAtFarm({ role_id: 3 }, farm);
+ const { user: unauthorizedUser } = await setupUserFarm({ role_id: 1 });
const wage = {
type: 'hourly',
amount: 23,
};
const target_user_id = worker.user_id;
- updateWageRequest(wage, {user_id: unauthorizedUser.user_id, farm_id: farm.farm_id}, target_user_id, async (err, res) => {
- expect(res.status).toBe(403);
- done();
- });
+ updateWageRequest(
+ wage,
+ { user_id: unauthorizedUser.user_id, farm_id: farm.farm_id },
+ target_user_id,
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(403);
+ done();
+ },
+ );
});
});
describe('Invite pseudo user test', () => {
test('Should invite a pseudo user when email does not exist in user table', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const [psedoUserFarm] = await mocks.userFarmFactory({promisedFarm: [farm]}, { ...mocks.fakeUserFarm(), role_id: 4 });
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const [psedoUserFarm] = await mocks.userFarmFactory(
+ { promisedFarm: [farm] },
+ { ...mocks.fakeUserFarm(), role_id: 4 },
+ );
const email = faker.internet.email().toLowerCase();
- const {wage, role_id} = mocks.fakeUserFarm();
- invitePseudoUserRequest({ email, role_id, wage }, {user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id}, async (err, res) => {
- expect(res.status).toBe(201);
- const updatedUserFarm = await userFarmModel.query().findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
- const updatedUser = await userModel.query().findById(psedoUserFarm.user_id);
- expect(updatedUser.email).toBe(email);
- expect(updatedUser.status_id).toBe(2);
- expect(updatedUserFarm.wage).toEqual(wage);
- expect(updatedUserFarm.role_id).toBe(role_id);
- done();
- });
+ const { wage, role_id } = mocks.fakeUserFarm();
+ invitePseudoUserRequest(
+ { email, role_id, wage },
+ { user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(201);
+ const updatedUserFarm = await userFarmModel
+ .query()
+ .findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
+ const updatedUser = await userModel.query().findById(psedoUserFarm.user_id);
+ expect(updatedUser.email).toBe(email);
+ expect(updatedUser.status_id).toBe(2);
+ expect(updatedUserFarm.wage).toEqual(wage);
+ expect(updatedUserFarm.role_id).toBe(role_id);
+ done();
+ },
+ );
});
- test('Should give access of a pseudo farm to an existing account when email exists in user table', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const [psedoUserFarm] = await mocks.userFarmFactory({promisedFarm: [farm]}, { ...mocks.fakeUserFarm(), role_id: 4 });
- const [shift0] = await mocks.shiftFactory({promisedUserFarm: [psedoUserFarm]}, {...mocks.fakeShift(), created_by_user_id: owner.user_id, updated_by_user_id: owner.user_id});
- const [shift1] = await mocks.shiftFactory({promisedUserFarm: [psedoUserFarm]}, {...mocks.fakeShift(), created_by_user_id: owner.user_id, updated_by_user_id: owner.user_id});
+ test('Should give access of a pseudo farm to an account when email exists in user table', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const [psedoUserFarm] = await mocks.userFarmFactory(
+ { promisedFarm: [farm] },
+ { ...mocks.fakeUserFarm(), role_id: 4 },
+ );
+ const [shift0] = await mocks.shiftFactory(
+ { promisedUserFarm: [psedoUserFarm] },
+ {
+ ...mocks.fakeShift(),
+ created_by_user_id: owner.user_id,
+ updated_by_user_id: owner.user_id,
+ },
+ );
+ const [shift1] = await mocks.shiftFactory(
+ { promisedUserFarm: [psedoUserFarm] },
+ {
+ ...mocks.fakeShift(),
+ created_by_user_id: owner.user_id,
+ updated_by_user_id: owner.user_id,
+ },
+ );
const email = faker.internet.email().toLowerCase();
- const [existingUser] = await mocks.usersFactory({ ...mocks.fakeUser(), email, user_id: `existing user ${psedoUserFarm.user_id}` })
- const {wage, role_id} = mocks.fakeUserFarm();
- invitePseudoUserRequest({ email, role_id, wage }, {user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id}, async (err, res) => {
- expect(res.status).toBe(201);
- const oldUserFarm = await userFarmModel.query().findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
- const oldUser = await userModel.query().findById(psedoUserFarm.user_id);
- expect(oldUser).toBeUndefined();
- expect(oldUserFarm).toBeUndefined();
- const updatedUserFarm = await userModel.query().join('userFarm', 'userFarm.user_id', 'users.user_id').where({'users.user_id':existingUser.user_id, 'userFarm.farm_id': farm.farm_id }).first().select('*');
- expect(updatedUserFarm.email).toBe(email);
- expect(updatedUserFarm.status_id).toBe(1);
- expect(updatedUserFarm.wage).toEqual(wage);
- expect(updatedUserFarm.role_id).toBe(role_id);
- const updatedShift0 = await knex('shift').where({shift_id: shift0.shift_id}).first();
- expect(updatedShift0.user_id).toBe(existingUser.user_id);
- const updatedShift1 = await knex('shift').where({shift_id: shift1.shift_id}).first();
- expect(updatedShift1.user_id).toBe(existingUser.user_id);
- done();
+ const [existingUser] = await mocks.usersFactory({
+ ...mocks.fakeUser(),
+ email,
+ user_id: `existing user ${psedoUserFarm.user_id}`,
});
+ const { wage, role_id } = mocks.fakeUserFarm();
+ invitePseudoUserRequest(
+ { email, role_id, wage },
+ { user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(201);
+ const oldUserFarm = await userFarmModel
+ .query()
+ .findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
+ const oldUser = await userModel.query().findById(psedoUserFarm.user_id);
+ expect(oldUser).toBeUndefined();
+ expect(oldUserFarm).toBeUndefined();
+ const updatedUserFarm = await userModel
+ .query()
+ .join('userFarm', 'userFarm.user_id', 'users.user_id')
+ .where({ 'users.user_id': existingUser.user_id, 'userFarm.farm_id': farm.farm_id })
+ .first()
+ .select('*');
+ expect(updatedUserFarm.email).toBe(email);
+ expect(updatedUserFarm.status_id).toBe(1);
+ expect(updatedUserFarm.wage).toEqual(wage);
+ expect(updatedUserFarm.role_id).toBe(role_id);
+ const updatedShift0 = await knex('shift').where({ shift_id: shift0.shift_id }).first();
+ expect(updatedShift0.user_id).toBe(existingUser.user_id);
+ const updatedShift1 = await knex('shift').where({ shift_id: shift1.shift_id }).first();
+ expect(updatedShift1.user_id).toBe(existingUser.user_id);
+ done();
+ },
+ );
});
- test('Should merge a pseudo user to an existing userFarm when user is already a member of the farm', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const [psedoUserFarm] = await mocks.userFarmFactory({promisedFarm: [farm]}, { ...mocks.fakeUserFarm(), role_id: 4 });
- const [shift0] = await mocks.shiftFactory({promisedUserFarm: [psedoUserFarm]}, {...mocks.fakeShift(), created_by_user_id: owner.user_id, updated_by_user_id: owner.user_id});
- const [shift1] = await mocks.shiftFactory({promisedUserFarm: [psedoUserFarm]}, {...mocks.fakeShift(), created_by_user_id: owner.user_id, updated_by_user_id: owner.user_id});
+ test('Should merge a pseudo user to existing userFarm when user is already member of the farm', async (done) => {
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const [psedoUserFarm] = await mocks.userFarmFactory(
+ { promisedFarm: [farm] },
+ { ...mocks.fakeUserFarm(), role_id: 4 },
+ );
+ const [shift0] = await mocks.shiftFactory(
+ { promisedUserFarm: [psedoUserFarm] },
+ {
+ ...mocks.fakeShift(),
+ created_by_user_id: owner.user_id,
+ updated_by_user_id: owner.user_id,
+ },
+ );
+ const [shift1] = await mocks.shiftFactory(
+ { promisedUserFarm: [psedoUserFarm] },
+ {
+ ...mocks.fakeShift(),
+ created_by_user_id: owner.user_id,
+ updated_by_user_id: owner.user_id,
+ },
+ );
const email = faker.internet.email().toLowerCase();
const [existingUser] = await mocks.usersFactory({ ...mocks.fakeUser(), email });
- const [existringUserFarm] = await mocks.userFarmFactory({promisedFarm: [farm], promisedUser: [existingUser]});
- const [existingShift] = await mocks.shiftFactory({promisedUserFarm: [existringUserFarm]});
- const {wage, role_id} = mocks.fakeUserFarm();
- invitePseudoUserRequest({ email, role_id, wage }, {user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id}, async (err, res) => {
- expect(res.status).toBe(201);
- const oldUserFarm = await userFarmModel.query().findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
- const oldUser = await userModel.query().findById(psedoUserFarm.user_id);
- expect(oldUser).toBeUndefined();
- expect(oldUserFarm).toBeUndefined();
- const updatedUserFarm = await userModel.query().join('userFarm', 'userFarm.user_id', 'users.user_id').where({'users.user_id':existingUser.user_id, 'userFarm.farm_id': farm.farm_id }).first().select('*');
- expect(updatedUserFarm.email).toBe(email);
- expect(updatedUserFarm.status_id).toBe(1);
- expect(updatedUserFarm.wage).toEqual(wage);
- expect(updatedUserFarm.role_id).toBe(role_id);
- const updatedShifts = await knex('shift').where({user_id: existingUser.user_id});
- expect(updatedShifts.length).toBe(3);
- done();
+ const [existringUserFarm] = await mocks.userFarmFactory({
+ promisedFarm: [farm],
+ promisedUser: [existingUser],
});
+ const [existingShift] = await mocks.shiftFactory({ promisedUserFarm: [existringUserFarm] });
+ const { wage, role_id } = mocks.fakeUserFarm();
+ invitePseudoUserRequest(
+ { email, role_id, wage },
+ { user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: psedoUserFarm.user_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(201);
+ const oldUserFarm = await userFarmModel
+ .query()
+ .findById([psedoUserFarm.user_id, psedoUserFarm.farm_id]);
+ const oldUser = await userModel.query().findById(psedoUserFarm.user_id);
+ expect(oldUser).toBeUndefined();
+ expect(oldUserFarm).toBeUndefined();
+ const updatedUserFarm = await userModel
+ .query()
+ .join('userFarm', 'userFarm.user_id', 'users.user_id')
+ .where({ 'users.user_id': existingUser.user_id, 'userFarm.farm_id': farm.farm_id })
+ .first()
+ .select('*');
+ expect(updatedUserFarm.email).toBe(email);
+ expect(updatedUserFarm.status_id).toBe(1);
+ expect(updatedUserFarm.wage).toEqual(wage);
+ expect(updatedUserFarm.role_id).toBe(role_id);
+ const updatedShifts = await knex('shift').where({ user_id: existingUser.user_id });
+ expect(updatedShifts.length).toBe(3);
+ done();
+ },
+ );
});
test('Should return 400 if user is not a pseudo User', async (done) => {
- const {user: owner, farm} = await setupUserFarm({role_id: 1});
- const [managerFarm] = await mocks.userFarmFactory({promisedFarm: [farm]}, { ...mocks.fakeUserFarm(), role_id: 2 });
+ const { user: owner, farm } = await setupUserFarm({ role_id: 1 });
+ const [managerFarm] = await mocks.userFarmFactory(
+ { promisedFarm: [farm] },
+ { ...mocks.fakeUserFarm(), role_id: 2 },
+ );
const { email } = await userModel.query().findById(managerFarm.user_id);
- const {wage, role_id} = mocks.fakeUserFarm();
- invitePseudoUserRequest({ email, role_id, wage }, {user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: managerFarm.user_id}, async (err, res) => {
- expect(res.status).toBe(400);
- const userFarm = await userFarmModel.query().findById([managerFarm.user_id, managerFarm.farm_id]);
- delete userFarm.created_at;
- delete managerFarm.created_at;
- expect(userFarm).toEqual(managerFarm);
- done();
- });
+ const { wage, role_id } = mocks.fakeUserFarm();
+ invitePseudoUserRequest(
+ { email, role_id, wage },
+ { user_id: owner.user_id, farm_id: farm.farm_id, params_user_id: managerFarm.user_id },
+ async (err, res) => {
+ expect(err).toEqual(null);
+ expect(res.status).toBe(400);
+ const userFarm = await userFarmModel
+ .query()
+ .findById([managerFarm.user_id, managerFarm.farm_id]);
+ delete userFarm.created_at;
+ delete managerFarm.created_at;
+ expect(userFarm).toEqual(managerFarm);
+ done();
+ },
+ );
});
- })
+ });
});
});
diff --git a/packages/webapp/.env.default b/packages/webapp/.env.default
index c95eee8c00..9514f81e8d 100644
--- a/packages/webapp/.env.default
+++ b/packages/webapp/.env.default
@@ -1,9 +1,10 @@
-#auth0
-REACT_APP_AUTH0_CLIENT_ID=AUTH_0_CLIENTID
-REACT_APP_AUTH0_CLIENT_SECRET=AUTH_0SECRET
-REACT_APP_AUTH0_AUTH_EXTENSION_CLIENT_ID=AUTH0_EXTENSION_CLIENT_ID
-REACT_APP_AUTH0_AUTH_EXTENSION_CLIENT_SECRET=AUTH0_EXTENSION_SECRET
-REACT_APP_AUTH0_AUTH_EXTENSION_URI=AUTH0_EXTENSION_URI
-REACT_APP_GOOGLE_MAPS_API_KEY=GMAP_KEY
-REACT_APP_WEATHER_API_KEY=OWA_KEY
-REACT_APP_ENV=production
+# Sensitive values are redacted with a ? placeholder.
+# Contact smattingly@litefarm.org for assistance.
+
+VITE_GOOGLE_MAPS_API_KEY=?
+VITE_WEATHER_API_KEY=?
+VITE_GOOGLE_OAUTH_CLIENT_ID=?
+VITE_ENV=development
+VITE_DO_BUCKET_NAME=litefarm
+NODE_ENV=development
+VITE_API_URL=http://localhost:5001
diff --git a/packages/webapp/.eslintrc b/packages/webapp/.eslintrc
deleted file mode 100644
index 9682ffc75d..0000000000
--- a/packages/webapp/.eslintrc
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "env": {
- "es2021": true,
- "jest": true
- },
- "extends": [
-
-// "eslint:recommended",
-// "plugin:react/recommended",
-// "prettier/react",
- "prettier",
- "react-app"
- ],
- "parserOptions": {
- "ecmaFeatures": {
- "jsx": true
- },
- "ecmaVersion": 12,
- "sourceType": "module"
- },
- "plugins": [
- "react"
- ],
- "rules": {
- "no-unused-vars": "off",
- "eqeqeq": "error",
- "jsx-a11y/accessible-emoji": "off",
- "radix": "off",
- "react/prop-types": "off",
- "import/no-anonymous-default-export": "off",
- "no-extra-bind": "off"
- },
- "globals": {
- "cy": true,
- "Cypress": true
- }
-}
diff --git a/packages/webapp/.eslintrc.js b/packages/webapp/.eslintrc.js
new file mode 100644
index 0000000000..187ae15e94
--- /dev/null
+++ b/packages/webapp/.eslintrc.js
@@ -0,0 +1,43 @@
+module.exports = {
+ root: true,
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ ecmaFeatures: {
+ jsx: true,
+ },
+ },
+ settings: {
+ react: {
+ version: 'detect',
+ },
+ 'import/resolver': {
+ node: {
+ paths: ['src'],
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
+ },
+ },
+ },
+ env: {
+ browser: true,
+ amd: true,
+ node: true,
+ },
+ extends: ['eslint:recommended', 'plugin:react/recommended'],
+ rules: {
+ 'react/react-in-jsx-scope': 'off',
+ 'react/prop-types': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ 'no-unused-vars': 'off',
+ 'no-prototype-builtins': 'off',
+ },
+ globals: {
+ describe: 'readonly',
+ it: 'readonly',
+ cy: 'readonly',
+ Cypress: 'readonly',
+ beforeEach: 'readonly',
+ before: 'readonly',
+ },
+};
diff --git a/packages/webapp/.gitignore b/packages/webapp/.gitignore
index e5e35801a7..6fb282849b 100644
--- a/packages/webapp/.gitignore
+++ b/packages/webapp/.gitignore
@@ -24,6 +24,7 @@ yarn-error.log*
./cypress/screenshots*
./cypress/videos*
./cypress/integration/__snapshots__
+./cypress.env.json
public/locales/*/*_old.json
diff --git a/packages/webapp/.npmrc b/packages/webapp/.npmrc
new file mode 100644
index 0000000000..d67f374883
--- /dev/null
+++ b/packages/webapp/.npmrc
@@ -0,0 +1 @@
+node-linker=hoisted
diff --git a/packages/webapp/.storybook/main.js b/packages/webapp/.storybook/main.js
index f55ca4f783..2df63168ac 100644
--- a/packages/webapp/.storybook/main.js
+++ b/packages/webapp/.storybook/main.js
@@ -1,13 +1,41 @@
+const svgrPlugin = require('vite-plugin-svgr');
+const react = require('@vitejs/plugin-react');
module.exports = {
stories: ['../src/stories/**/*.stories.mdx', '../src/stories/**/*.stories.@(js|jsx|ts|tsx)'],
- addons: [
- '@storybook/addon-links',
- '@storybook/addon-essentials',
- '@storybook/addon-a11y',
- '@storybook/preset-create-react-app',
- ],
- webpackFinal: async (config, { configType }) => {
- config.node = { fs: 'empty', tls: 'empty', net: 'empty', module: 'empty', console: true };
- return config;
+ addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/addon-a11y'],
+ framework: '@storybook/react',
+ core: {
+ builder: 'storybook-builder-vite',
+ },
+ features: {
+ storyStoreV7: true,
+ },
+ async viteFinal(config, { configType }) {
+ config.plugins = config.plugins.filter(
+ (plugin) => !(Array.isArray(plugin) && plugin[0]?.name.includes('vite:react')),
+ );
+ return {
+ ...config,
+ plugins: [
+ ...config.plugins,
+ react({
+ jsxRuntime: 'classic',
+ exclude: [/\.stories\.(t|j)sx?$/, /node_modules/],
+ jsxImportSource: '@emotion/react',
+ babel: {
+ plugins: ['@emotion/babel-plugin'],
+ },
+ }),
+ svgrPlugin({
+ svgrOptions: {
+ icon: false,
+ },
+ }),
+ ],
+ optimizeDeps: {
+ ...config.optimizeDeps,
+ include: [...(config.optimizeDeps?.include ?? []), '@storybook/addon-docs/blocks'],
+ },
+ };
},
};
diff --git a/packages/webapp/.storybook/preview-head.html b/packages/webapp/.storybook/preview-head.html
index 915bcd1499..a94333cbd6 100644
--- a/packages/webapp/.storybook/preview-head.html
+++ b/packages/webapp/.storybook/preview-head.html
@@ -1,9 +1,5 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lite Farm
diff --git a/packages/webapp/.storybook/preview.js b/packages/webapp/.storybook/preview.js
deleted file mode 100644
index c819ad58bc..0000000000
--- a/packages/webapp/.storybook/preview.js
+++ /dev/null
@@ -1,5 +0,0 @@
-export const parameters = {
- actions: { argTypesRegex: '^on[A-Z].*' },
- layout: 'fullscreen',
- chromatic: { disableSnapshot: true },
-};
diff --git a/packages/webapp/.storybook/preview.jsx b/packages/webapp/.storybook/preview.jsx
new file mode 100644
index 0000000000..793d368782
--- /dev/null
+++ b/packages/webapp/.storybook/preview.jsx
@@ -0,0 +1,63 @@
+import React, { Suspense } from 'react';
+import state from './state';
+import { action } from '@storybook/addon-actions';
+import theme from '../src/assets/theme';
+import { CssBaseline, ThemeProvider } from '@material-ui/core';
+import { Provider } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import { GlobalScss } from '../src/components/GlobalScss';
+
+export const parameters = {
+ actions: { argTypesRegex: '^on[A-Z].*' },
+ controls: {
+ matchers: {
+ color: /(background|color)$/i,
+ date: /Date$/,
+ },
+ },
+ layout: 'fullscreen',
+ chromatic: { disableSnapshot: true },
+};
+const store = {
+ getState: () => {
+ return state;
+ },
+ subscribe: () => 0,
+ dispatch: action('dispatch'),
+};
+export const decorators = [
+ (Story) => {
+ const { t, ready } = useTranslation(
+ [
+ 'certifications',
+ 'crop_group',
+ 'crop_nutrients',
+ 'filter',
+ 'translation',
+ 'crop',
+ 'common',
+ 'disease',
+ 'task',
+ 'expense',
+ 'fertilizer',
+ 'message',
+ 'gender',
+ 'role',
+ 'harvest_uses',
+ 'soil',
+ ],
+ { useSuspense: false },
+ );
+ return (
+ Loading...
}>
+
+
+
+
+
+
+
+
+ );
+ },
+];
diff --git a/packages/webapp/.storybook/state.js b/packages/webapp/.storybook/state.js
new file mode 100755
index 0000000000..f57f682def
--- /dev/null
+++ b/packages/webapp/.storybook/state.js
@@ -0,0 +1,1927 @@
+export default {
+ profileForms: {
+ addInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+ },
+ farm: {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+ },
+ notification: {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+ },
+ userInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+ },
+ farmInfo: {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+ },
+ editInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ signUpInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+ },
+ forms: {
+ $form: {
+ initialValue: {
+ addInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+ },
+ farm: {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+ },
+ notification: {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+ },
+ userInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+ },
+ farmInfo: {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+ },
+ editInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ signUpInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+ },
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms',
+ value: {
+ addInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+ },
+ farm: {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+ },
+ notification: {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+ },
+ userInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+ },
+ farmInfo: {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+ },
+ editInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ signUpInfo: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+ },
+ },
+ },
+ addInfo: {
+ $form: {
+ initialValue: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo',
+ value: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+ },
+ },
+ first_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.first_name',
+ value: '',
+ },
+ last_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.last_name',
+ value: '',
+ },
+ email: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.email',
+ value: '',
+ },
+ role: {
+ initialValue: 'Worker',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.role',
+ value: 'Worker',
+ },
+ pay: {
+ $form: {
+ initialValue: {
+ type: '',
+ amount: null,
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.pay',
+ value: {
+ type: '',
+ amount: null,
+ },
+ },
+ type: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.pay.type',
+ value: '',
+ },
+ amount: {
+ initialValue: null,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.addInfo.pay.amount',
+ value: null,
+ },
+ },
+ },
+ farm: {
+ $form: {
+ initialValue: {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm',
+ value: {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+ },
+ },
+ farm_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.farm_name',
+ value: '',
+ },
+ address: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.address',
+ value: '',
+ },
+ gridPoints: {
+ $form: {
+ initialValue: {},
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.gridPoints',
+ value: {},
+ },
+ },
+ unit: {
+ initialValue: 'metric',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.unit',
+ value: 'metric',
+ },
+ currency: {
+ initialValue: 'CAD',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.currency',
+ value: 'CAD',
+ },
+ date: {
+ initialValue: 'MM/DD/YY',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.date',
+ value: 'MM/DD/YY',
+ },
+ sandbox: {
+ initialValue: false,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farm.sandbox',
+ value: false,
+ },
+ },
+ notification: {
+ $form: {
+ initialValue: {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification',
+ value: {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+ },
+ },
+ alert_pest: {
+ initialValue: true,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification.alert_pest',
+ value: true,
+ },
+ alert_weather: {
+ initialValue: true,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification.alert_weather',
+ value: true,
+ },
+ alert_worker_finish: {
+ initialValue: true,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification.alert_worker_finish',
+ value: true,
+ },
+ alert_before_planned_date: {
+ initialValue: true,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification.alert_before_planned_date',
+ value: true,
+ },
+ alert_action_after_scouting: {
+ initialValue: true,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.notification.alert_action_after_scouting',
+ value: true,
+ },
+ },
+ userInfo: {
+ $form: {
+ initialValue: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo',
+ value: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+ },
+ },
+ first_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.first_name',
+ value: '',
+ },
+ last_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.last_name',
+ value: '',
+ },
+ email: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.email',
+ value: '',
+ },
+ phone_number: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.phone_number',
+ value: '',
+ },
+ address: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.address',
+ value: '',
+ },
+ profile_picture: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.userInfo.profile_picture',
+ value: '',
+ },
+ },
+ farmInfo: {
+ $form: {
+ initialValue: {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo',
+ value: {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+ },
+ },
+ farm_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.farm_name',
+ value: '',
+ },
+ unit: {
+ initialValue: 'metric',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.unit',
+ value: 'metric',
+ },
+ currency: {
+ initialValue: 'CAD',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.currency',
+ value: 'CAD',
+ },
+ date: {
+ initialValue: 'MM/DD/YY',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.date',
+ value: 'MM/DD/YY',
+ },
+ phone_number: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.phone_number',
+ value: '',
+ },
+ phone_country: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.phone_country',
+ value: '',
+ },
+ address: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.address',
+ value: '',
+ },
+ gridPoints: {
+ $form: {
+ initialValue: {},
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.farmInfo.gridPoints',
+ value: {},
+ },
+ },
+ },
+ editInfo: {
+ $form: {
+ initialValue: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo',
+ value: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ },
+ first_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.first_name',
+ value: '',
+ },
+ last_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.last_name',
+ value: '',
+ },
+ email: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.email',
+ value: '',
+ },
+ role: {
+ initialValue: 'Worker',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.role',
+ value: 'Worker',
+ },
+ pay: {
+ $form: {
+ initialValue: {
+ type: 'hourly',
+ amount: 0,
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.pay',
+ value: {
+ type: 'hourly',
+ amount: 0,
+ },
+ },
+ type: {
+ initialValue: 'hourly',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.pay.type',
+ value: 'hourly',
+ },
+ amount: {
+ initialValue: 0,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.editInfo.pay.amount',
+ value: 0,
+ },
+ },
+ },
+ signUpInfo: {
+ $form: {
+ initialValue: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.signUpInfo',
+ value: {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+ },
+ },
+ first_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.signUpInfo.first_name',
+ value: '',
+ },
+ last_name: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.signUpInfo.last_name',
+ value: '',
+ },
+ email: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.signUpInfo.email',
+ value: '',
+ },
+ password: {
+ initialValue: '',
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'profileForms.signUpInfo.password',
+ value: '',
+ },
+ },
+ },
+ },
+ entitiesReducer: {
+ userFarmReducer: {
+ farmIdUserIdTuple: [
+ {
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ user_id: '2cc91b7a-83c6-11ec-9fa9-0242ac130004',
+ },
+ ],
+ byFarmIdUserId: {
+ '31881f94-83c6-11ec-9fa9-0242ac130004': {
+ '2cc91b7a-83c6-11ec-9fa9-0242ac130004': {
+ first_name: 'litefarmdev0+Storybook@gmail.com',
+ last_name: '',
+ profile_picture: null,
+ email: 'litefarmdev0+storybook@gmail.com',
+ phone_number: null,
+ user_id: '2cc91b7a-83c6-11ec-9fa9-0242ac130004',
+ gender: 'PREFER_NOT_TO_SAY',
+ birth_year: null,
+ farm_name: 'litefarmdev0+Storybook@gmail.com',
+ address: '49.2652639, -123.1676483',
+ grid_points: {
+ lat: 49.2652639,
+ lng: -123.1676483,
+ },
+ country_id: 37,
+ units: {
+ currency: 'CAD',
+ measurement: 'metric',
+ },
+ created_by_user_id: '2cc91b7a-83c6-11ec-9fa9-0242ac130004',
+ updated_by_user_id: '2cc91b7a-83c6-11ec-9fa9-0242ac130004',
+ created_at: '2022-02-02T01:19:39.935Z',
+ updated_at: '2022-02-02T01:19:39.939Z',
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ deleted: false,
+ farm_phone_number: null,
+ sandbox_farm: false,
+ owner_operated: null,
+ default_initial_location_id: null,
+ role_id: 1,
+ status: 'Active',
+ has_consent: true,
+ consent_version: '3.0',
+ wage: {
+ type: 'hourly',
+ amount: 0,
+ },
+ step_one: true,
+ step_one_end: '2022-02-02T01:19:39.908Z',
+ step_two: true,
+ step_two_end: '2022-02-02T01:19:42.589Z',
+ step_three: true,
+ step_three_end: '2022-02-02T01:19:44.774Z',
+ step_four: true,
+ step_four_end: '2022-02-02T01:19:47.449Z',
+ step_five: true,
+ step_five_end: '2022-02-02T01:19:48.374Z',
+ country: 'Canada',
+ role: 'Owner',
+ },
+ },
+ },
+ loading: false,
+ error: null,
+ loaded: true,
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ user_id: '2cc91b7a-83c6-11ec-9fa9-0242ac130004',
+ },
+ certifierSurveyReducer: {
+ ids: ['31881f94-83c6-11ec-9fa9-0242ac130004'],
+ entities: {
+ '31881f94-83c6-11ec-9fa9-0242ac130004': {
+ certification_id: null,
+ certifier_id: null,
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ interested: false,
+ requested_certification: null,
+ requested_certifier: null,
+ survey_id: '3606f734-83c6-11ec-a3cb-0242ac130004',
+ },
+ },
+ loading: false,
+ error: null,
+ loaded: true,
+ },
+ rolesReducer: {
+ roles: [],
+ loading: false,
+ loaded: false,
+ },
+ cropReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ cropVarietyReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ weatherReducer: {
+ ids: ['31881f94-83c6-11ec-9fa9-0242ac130004'],
+ entities: {
+ '31881f94-83c6-11ec-9fa9-0242ac130004': {
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ loading: false,
+ city: 'Vancouver',
+ date: 1643764789,
+ humidity: '75%',
+ iconName: 'wi-day-cloudy',
+ temperature: '4',
+ wind: '0.89',
+ measurement: 'metric',
+ lastActiveDatetime: 1643764789247,
+ error: null,
+ loaded: true,
+ },
+ },
+ },
+ barnReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ ceremonialReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ farmSiteBoundaryReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ fieldReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ gardenReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ greenhouseReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ surfaceWaterReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ naturalAreaReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ residenceReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ bufferZoneReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ watercourseReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ fenceReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ gateReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ waterValveReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ showedSpotlightReducer: {
+ loaded: true,
+ loading: false,
+ map: false,
+ draw_area: false,
+ draw_line: false,
+ drop_point: false,
+ adjust_area: false,
+ adjust_line: false,
+ navigation: true,
+ introduce_map: true,
+ crop_catalog: false,
+ documents: false,
+ compliance_docs_and_certification: false,
+ transplant: false,
+ management_plan_creation: false,
+ planting_task: false,
+ crop_variety_detail: false,
+ },
+ managementPlanReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ cropManagementPlanReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ plantingManagementPlanReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ containerMethodReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ bedMethodReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ rowMethodReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ broadcastMethodReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ documentReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ certifierReducer: {
+ ids: [1, 2, 3, 4, 5, 6, 7, 8, 9],
+ entities: {
+ 1: {
+ certification_id: 1,
+ certifier_acronym: 'IOPA',
+ certifier_id: 1,
+ certifier_name: 'Islands Organic Producers Association',
+ country_id: 37,
+ certifier_country_id: 1,
+ survey_id: '60f615459a6b1c00012ee41e ',
+ },
+ 2: {
+ certification_id: 1,
+ certifier_acronym: 'KOGS',
+ certifier_id: 2,
+ certifier_name: 'Kootenay Organic Growers Society',
+ country_id: 37,
+ certifier_country_id: 2,
+ survey_id: null,
+ },
+ 3: {
+ certification_id: 1,
+ certifier_acronym: 'LEOGA',
+ certifier_id: 3,
+ certifier_name: 'Living Earth Organic Growers',
+ country_id: 37,
+ certifier_country_id: 3,
+ survey_id: null,
+ },
+ 4: {
+ certification_id: 1,
+ certifier_acronym: 'BCARA',
+ certifier_id: 4,
+ certifier_name: 'British Columbia Association for Regenerative Agriculture',
+ country_id: 37,
+ certifier_country_id: 4,
+ survey_id: '60f615459a6b1c00012ee41e ',
+ },
+ 5: {
+ certification_id: 1,
+ certifier_acronym: 'BDASBC',
+ certifier_id: 5,
+ certifier_name: 'Bio-Dynamic Agricultural Society of British Columbia',
+ country_id: 37,
+ certifier_country_id: 5,
+ survey_id: null,
+ },
+ 6: {
+ certification_id: 1,
+ certifier_acronym: 'NOOA',
+ certifier_id: 6,
+ certifier_name: 'North Okanagan Organic Association',
+ country_id: 37,
+ certifier_country_id: 6,
+ survey_id: '61e7250d8929750001770230',
+ },
+ 7: {
+ certification_id: 1,
+ certifier_acronym: 'SOOPA',
+ certifier_id: 7,
+ certifier_name: 'Similkameen Okanagan Organic Producers Association',
+ country_id: 37,
+ certifier_country_id: 7,
+ survey_id: null,
+ },
+ 8: {
+ certification_id: 1,
+ certifier_acronym: 'PACS',
+ certifier_id: 8,
+ certifier_name: 'Pacific Agricultural Certification Society',
+ country_id: 37,
+ certifier_country_id: 8,
+ survey_id: null,
+ },
+ 9: {
+ certification_id: 1,
+ certifier_acronym: 'FVOPA',
+ certifier_id: 9,
+ certifier_name: 'Fraser Valley Organic Producers',
+ country_id: 37,
+ certifier_country_id: 9,
+ survey_id: null,
+ },
+ },
+ loading: false,
+ error: null,
+ loaded: true,
+ },
+ certificationReducer: {
+ ids: [1, 2],
+ entities: {
+ 1: {
+ certification_id: 1,
+ certification_translation_key: 'ORGANIC',
+ certification_type: 'Organic',
+ },
+ 2: {
+ certification_id: 2,
+ certification_translation_key: 'PGS',
+ certification_type: 'Participatory Guarantee System',
+ },
+ },
+ loading: false,
+ error: null,
+ loaded: true,
+ },
+ taskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ cleaningTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ fieldWorkTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ harvestTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ pestControlTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ soilAmendmentTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ plantTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ transplantTaskReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ taskTypeReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ harvestUseTypeReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ productReducer: {
+ ids: [],
+ entities: {},
+ loading: false,
+ loaded: false,
+ },
+ },
+ persistedStateReducer: {
+ userLogReducer: {
+ lastActiveDatetime: 1643764780134,
+ farm_id: '31881f94-83c6-11ec-9fa9-0242ac130004',
+ },
+ chooseFarmFlowReducer: {
+ ids: [],
+ entities: {},
+ },
+ mapFilterSettingReducer: {
+ ids: [],
+ entities: {},
+ },
+ mapCacheReducer: {
+ ids: [],
+ entities: {},
+ },
+ appSettingReducer: {},
+ },
+ tempStateReducer: {
+ homeReducer: {
+ loading: false,
+ },
+ mapLocationReducer: {
+ successMessage: null,
+ canShowSuccessHeader: false,
+ canShowSelection: false,
+ locations: [],
+ zoomLevel: null,
+ position: null,
+ },
+ hookFormPersistReducer: {
+ formData: {},
+ persistedPaths: [],
+ historyStack: [],
+ },
+ filterReducer: {
+ cropCatalogue: {
+ STATUS: {},
+ LOCATION: {},
+ SUPPLIERS: {},
+ },
+ documents: {
+ TYPE: {},
+ },
+ },
+ snackbarReducer: {
+ notifications: [],
+ },
+ navbarReducer: {
+ introducingCertifications: false,
+ },
+ },
+ baseReducer: {},
+ insightReducer: {
+ cropNutritionData: {
+ preview: 0,
+ data: [],
+ },
+ soilOMData: {
+ preview: 0,
+ data: [],
+ },
+ labourHappinessData: {
+ preview: 0,
+ data: [],
+ },
+ biodiversityData: {
+ preview: 0,
+ data: [],
+ },
+ pricesData: {
+ preview: 0,
+ amountOfFarms: 0,
+ data: [],
+ },
+ waterBalanceData: {
+ preview: 0,
+ data: [],
+ },
+ waterBalanceSchedule: {},
+ nitrogenBalanceData: {
+ preview: 0,
+ data: [],
+ },
+ nitrogenFrequencyData: {},
+ pricesDistance: 5,
+ },
+ financeReducer: {
+ forms: {
+ addSale: {},
+ editSale: {},
+ expenseDetail: {},
+ date_range: null,
+ forms: {
+ $form: {
+ initialValue: {
+ addSale: {},
+ editSale: {},
+ expenseDetail: {},
+ date_range: null,
+ },
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'financeReducer.forms',
+ value: {
+ addSale: {},
+ editSale: {},
+ expenseDetail: {},
+ date_range: null,
+ },
+ },
+ addSale: {
+ $form: {
+ initialValue: {},
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'financeReducer.forms.addSale',
+ value: {},
+ },
+ },
+ editSale: {
+ $form: {
+ initialValue: {},
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'financeReducer.forms.editSale',
+ value: {},
+ },
+ },
+ expenseDetail: {
+ $form: {
+ initialValue: {},
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'financeReducer.forms.expenseDetail',
+ value: {},
+ },
+ },
+ date_range: {
+ initialValue: null,
+ focus: false,
+ pending: false,
+ pristine: true,
+ submitted: false,
+ submitFailed: false,
+ retouched: false,
+ touched: false,
+ valid: true,
+ validating: false,
+ validated: false,
+ validity: {},
+ errors: {},
+ intents: [],
+ model: 'financeReducer.forms.date_range',
+ value: null,
+ },
+ },
+ },
+ financeReducer: {
+ sales: null,
+ cropSales: null,
+ shifts: null,
+ },
+ },
+ farmReducer: {
+ farm_data_schedule: null,
+ },
+ _persist: {
+ version: -1,
+ rehydrated: true,
+ },
+};
diff --git a/packages/webapp/cypress.env.json b/packages/webapp/cypress.env.json
index 063baa5f57..2406340684 100644
--- a/packages/webapp/cypress.env.json
+++ b/packages/webapp/cypress.env.json
@@ -6,5 +6,6 @@
"auth_username": "cypressRunner@litefarm.co",
"auth_password": "P4ssword!",
"auth_user_id": "auth0|5d93178e8a968e0e14cd1573",
- "user_farm_id": "16ce7028-e42b-11e9-9717-9bd9186e761c"
+ "user_farm_id": "16ce7028-e42b-11e9-9717-9bd9186e761c",
+ "apiUrl":"http://localhost:5001"
}
diff --git a/packages/webapp/cypress.json b/packages/webapp/cypress.json
index 3f33618c6b..3b2a24db75 100644
--- a/packages/webapp/cypress.json
+++ b/packages/webapp/cypress.json
@@ -1,3 +1,4 @@
{
- "projectId": "72wq5a"
+ "projectId": "72wq5a",
+ "baseUrl": "http://localhost:3000"
}
diff --git a/packages/webapp/cypress/fixtures/example.json b/packages/webapp/cypress/fixtures/example.json
new file mode 100644
index 0000000000..02e4254378
--- /dev/null
+++ b/packages/webapp/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+ "name": "Using fixtures to represent data",
+ "email": "hello@cypress.io",
+ "body": "Fixtures are a great way to mock data for responses to routes"
+}
diff --git a/packages/webapp/cypress/integration/certificationFlow.spec.js b/packages/webapp/cypress/integration/certificationFlow.spec.js
new file mode 100644
index 0000000000..c02988dfaf
--- /dev/null
+++ b/packages/webapp/cypress/integration/certificationFlow.spec.js
@@ -0,0 +1,14 @@
+///
+
+describe.only('Certification tests', () => {
+ before(() => {});
+ it('Survey stack export document test', () => {
+ //Test for LF-2322
+ //after running happy path test
+ //create a user account with language set to Spanish
+ //login to the default farm created by the happy path tests
+ //invite the spanish user to the default farm
+ //Spanish user should receive an invitation email in spanish
+ //repeat for all languages
+ });
+});
diff --git a/packages/webapp/cypress/integration/cropsFlow.spec.js b/packages/webapp/cypress/integration/cropsFlow.spec.js
new file mode 100644
index 0000000000..44f2f5e1c1
--- /dev/null
+++ b/packages/webapp/cypress/integration/cropsFlow.spec.js
@@ -0,0 +1,81 @@
+describe.only('Crops flow tests', () => {
+ before(() => {});
+
+ it('Crop catalogue view', () => {
+ //test for LF-2163
+ //Ensure "needs plan "status key exists on crop catalogue page key section
+ // ensure new status is displayed on crop tile
+ });
+
+ it('Create a new crop', () => {
+ //Test for LF-2237
+ cy.visit('/');
+
+ cy.loginFarmOwner();
+ //Action: User navigates into new crop flow
+ cy.visit('/crop/new');
+
+ //User enters crop name, Expected: Continue button is disabled
+
+ //user select crop group, Expected: Continue button is disabled
+
+ //user selects no as "can this be grown as a cover crop" radio option, Continue button is enabled
+ });
+
+ it('Crop variety view', () => {
+ //test for LF-2172
+ //Ensure status key section exists on crop variety page
+ // ensure statuses are displayed on varietal tile
+ });
+
+ it('Add a task to a crop plan', () => {
+ //test for LF-2392
+ //navigate to crop catalogue
+ //select a crop with a planned management plan
+ //select the variety with the planned management plan
+ //select the planned plan
+ // click add a task
+ //select a cleaning task and click continue
+ //select a date and click continue
+ //Ensure the initiating location is pre-selected by checking if continue button is enabled and click continue
+ // Ensure the crop management plan where add task was initiated is preselected and click continue
+ //click continue
+ //click save
+ //Ensure you are back on the initiating plan view
+ });
+
+ it('Complete a crop plan', () => {
+ //test for LF-2178
+ //Complete a crop plan
+ //Open the crop plan's detail page
+ //Completed date should exist
+ //Plan rating should exist
+ //Completion notes should exist
+ //Plan notes should exist
+ //Estimated annual harvest should exist
+ });
+
+ it('Abandon a task in a crop plan', () => {
+ //test for LF-2213
+ //Abandon a task in a crop plan
+ //Once the task in abandoned the displayed view should be the crop plan
+ //Ensure an alert is created to notify the user the task was assigned to that the task was abandoned(test for LF-2383)
+ //Ensure the notification exists on the notifications page
+ });
+
+ it('Complete a task in a crop plan', () => {
+ //test for LF-2213
+ //Complete a task in a crop plan
+ //Once the task in completed the displayed view should be the crop plan
+ });
+
+ it('Abandon a crop plan', () => {
+ //test for LF-2177
+ //Complete all tasks in a crop plan
+ //abandon the crop plan
+ //click on the abandoned crop plan
+ //Click on the details tab
+ //Abandonment date, Rating, Abandonment reason If “Something else” is selected, should show “What happened?”
+ //as well Abandonment notes Plan notes Estimated annual yield should exist
+ });
+});
diff --git a/packages/webapp/cypress/integration/documentsFlow.spec.js b/packages/webapp/cypress/integration/documentsFlow.spec.js
new file mode 100644
index 0000000000..c5acc5c719
--- /dev/null
+++ b/packages/webapp/cypress/integration/documentsFlow.spec.js
@@ -0,0 +1,39 @@
+import { getDateInputFormat } from '../../src/util/moment';
+
+describe.only('Documents flow tests', () => {
+ before(() => {});
+ it('Unarchive documents', () => {
+ //Test for LF-2307
+ //Action: on document read only user clicks unarchive, expected: unarchive modal pops up
+ //Title shoube "Unarchive document?"
+ //Body should read “Unarchiving this document will return it to your list of currently valid documents.
+ //Valid documents will be exported for your certifications. Do you want to proceed?”
+ // Primary button “Unarchive” should exist
+ //Secondary button: “Cancel” should exists
+ //Click anywhere in the background to dismiss the modal without making any changes
+ //Click the “Cancel” button to dismiss the modal without making any changes
+ //Click “Unarchive” to change the status of this document to “Valid”
+ });
+
+ it('Upload receipt', () => {
+ //Test for LF-2346
+ //Navigate to documents view page
+ //click add a document
+ //upload a sample receipt
+ //select receipt on the type dropdown
+ //type a document name
+ //save the document
+ //ensure document is uploaded correctly and card details are correct
+ });
+
+ it('Upload invoice', () => {
+ //Test for LF-2346
+ //Navigate to documents view page
+ //click add a document
+ //upload a sample invoice
+ //select receipt on the type dropdown
+ //type a document name
+ //save the document
+ //ensure document is uploaded correctly and card details are correct
+ });
+});
diff --git a/packages/webapp/cypress/integration/happyPath.spec.js b/packages/webapp/cypress/integration/happyPath.spec.js
new file mode 100644
index 0000000000..179dbfead2
--- /dev/null
+++ b/packages/webapp/cypress/integration/happyPath.spec.js
@@ -0,0 +1,393 @@
+import { getDateInputFormat } from '../../src/util/moment';
+
+describe.only('LiteFarm end to end test', () => {
+ it.only('Happy path', { defaultCommandTimeout: 7000 }, () => {
+ cy.visit('/');
+ cy.get('[data-cy=email]').should('exist');
+ cy.get('[data-cy=continue]').should('exist');
+ cy.get('[data-cy=continue]').should('be.disabled');
+ cy.get('[data-cy=continueGoogle]').should('exist');
+
+ //create test data
+ const emailOwner = 'mbolokonya@litefarm.org';
+ const emailWorker = 'worker@example.com';
+ const fullName = 'Test Farmer';
+ const password = 'P@ssword123';
+ const farmName = 'UBC FARM';
+ const location = '49.250833,-123.2410777';
+ const fieldName = 'Test Field';
+ const workerName = 'Test Worker';
+ const testCrop = 'New Crop';
+
+ //Login page
+ cy.get('[data-cy=email]').type(emailOwner);
+ cy.contains('Continue').should('exist').and('be.enabled').click();
+
+ //check you are on the create user account page
+ cy.contains('Create new user account').should('exist');
+ cy.get('[data-cy=createUser-fullName]').type(fullName);
+ cy.get('[data-cy=createUser-password]').type(password);
+ cy.contains('Create Account').should('exist').and('be.enabled').click();
+
+ //Get Started page
+ cy.contains('started').should('exist');
+ cy.get('[data-cy=getStarted]').should('exist');
+ cy.get('[data-cy=getStarted]').click();
+
+ //Add farm page
+ cy.url().should('include', '/add_farm');
+ cy.get('[data-cy=addFarm-continue]').should('exist');
+ cy.get('[data-cy=addFarm-continue]').should('be.disabled');
+ cy.get('[data-cy=addFarm-farmName]').should('exist');
+ cy.get('[data-cy=addFarm-location]').should('exist');
+
+ // Enter new farm details and click continue which should be enabled
+ cy.waitForGoogleApi().then(() => {
+ cy.get('[data-cy=addFarm-farmName]').type(farmName);
+ cy.get('[data-cy=addFarm-location]').type(location).wait(1000);
+ cy.get('[data-cy=addFarm-continue]').should('not.be.disabled').click();
+ });
+
+ //role selection page
+ cy.contains('What is your role on the farm').should('exist');
+ cy.url().should('include', '/role_selection');
+ cy.get('[data-cy=roleSelection-continue]').should('exist').and('be.disabled');
+ cy.get('[data-cy=roleSelection-role]').should('exist').check('Manager', { force: true });
+ cy.get('[data-cy=roleSelection-continue]').should('not.be.disabled').click();
+
+ //Consent page
+ cy.contains('Our Data Policy').should('exist');
+ cy.url().should('include', '/consent');
+ cy.get('[data-cy=consent-continue]').should('exist').and('be.disabled');
+ cy.get('[data-cy=consent-agree]').should('exist').check({ force: true });
+ cy.get('[data-cy=consent-continue]').should('not.be.disabled').click();
+
+ //interested in organic
+ cy.contains('Interested in certifications').should('exist');
+ cy.url().should('include', '/certification/interested_in_organic');
+ cy.get('[data-cy=interestedInOrganic-continue]').should('exist').and('be.disabled');
+ cy.get('[data-cy=interestedInOrganic-select]').should('exist');
+ cy.get('[type="radio"]').first().check({ force: true });
+ cy.get('[data-cy=interestedInOrganic-continue]').should('not.be.disabled').click();
+
+ //what type of certification(select organic)
+ cy.contains('What type of certification').should('exist');
+ cy.url().should('include', '/certification/selection');
+ cy.get('[data-cy=certificationSelection-continue]').should('exist').and('be.disabled');
+ cy.get('[data-cy=certificationSelection-type]').should('exist');
+ cy.get('[type="radio"]').first().check({ force: true });
+ cy.get('[data-cy=certificationSelection-continue]').should('not.be.disabled').click();
+
+ //who is your certifier(select BCARA)
+ cy.contains('Who is your certifier').should('exist');
+ cy.url().should('include', '/certification/certifier/selection');
+ cy.get('[data-cy=certifierSelection-proceed]').should('exist').and('be.disabled');
+ cy.get('[data-cy=certifierSelection-item]').should('exist').eq(1).click();
+ let certifier;
+ cy.get('[data-cy=certifierSelection-item]')
+ .eq(1)
+ .then(function ($elem) {
+ certifier = $elem.text();
+ let end = certifier.indexOf('(');
+ let result = certifier.substring(1, end);
+ //click the proceed button and ensure test is on the certification summary view and the certification selected is displayed
+ cy.get('[data-cy=certifierSelection-proceed]').should('not.be.disabled').click();
+ cy.url().should('include', '/certification/summary');
+ cy.contains(result).should('exist');
+ });
+
+ //certifacation summary
+ cy.get('[data-cy=certificationSummary-continue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+
+ //onboarding outro
+ cy.url().should('include', '/outro');
+ cy.get('[data-cy=outro-finish]').should('exist').and('not.be.disabled').click();
+
+ //farm home page
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=home-farmButton]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=navbar-option]')
+ .contains('Farm map')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+
+ //arrive at farm map page and draw a field
+ cy.url().should('include', '/map');
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=map-addFeature]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=map-drawer]').contains('Field').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=mapTutorial-continue]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+
+ let initialWidth;
+ let initialHeight;
+
+ cy.waitForGoogleApi().then(() => {
+ // here comes the code to execute after loading the google Apis
+
+ cy.get('[data-cy=map-mapContainer]').then(($canvas) => {
+ initialWidth = $canvas.width();
+ initialHeight = $canvas.height();
+ });
+ cy.wait(1000);
+ cy.get('[data-cy=map-mapContainer]').click(558, 344);
+ cy.wait(500);
+ cy.get('[data-cy=map-mapContainer]').click(570, 321);
+ cy.wait(500);
+ cy.get('[data-cy=map-mapContainer]').click(631, 355);
+ cy.wait(500);
+ cy.get('[data-cy=map-mapContainer]').click(605, 374);
+ cy.wait(500);
+ cy.get('[data-cy=map-mapContainer]').click(558, 344);
+ cy.get('[data-cy=mapTutorial-continue]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=map-drawCompleteContinue]')
+ .contains('Confirm')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ });
+ //Add field view
+ cy.get('[data-cy=createField-fieldName]').should('exist').type(fieldName);
+ cy.get('[data-cy=createField-save]').should('exist').and('not.be.disabled').click();
+
+ //Add a farm worker to the farm
+ cy.get('[data-cy=home-farmButton]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=navbar-option]')
+ .contains('People')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.url().should('include', '/people');
+ cy.get('[data-cy=people-inviteUser]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/invite_user');
+ cy.get('[data-cy=invite-fullName]').should('exist').type(workerName);
+ cy.contains('Choose Role').should('exist').click({ force: true });
+ cy.contains('Farm Worker').should('exist').click();
+ cy.get('[data-cy=invite-email]').should('exist').type(emailWorker);
+ cy.get('[data-cy=invite-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/people');
+ cy.contains(workerName).should('exist');
+
+ // Add a crop variety
+ cy.get('[data-cy=navbar-hamburger]').should('exist').click();
+ cy.contains('Crops').should('exist').click();
+ cy.url().should('include', '/crop_catalogue');
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=crop-addLink]')
+ .contains('Add a new crop')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+
+ cy.url().should('include', '/crop/new');
+ cy.get('[data-cy=crop-cropName]').should('exist').type(testCrop);
+ cy.contains('Select').should('exist').click({ force: true });
+ cy.contains('Cereals').should('exist').click();
+ cy.get('[type="radio"]').first().check({ force: true });
+ cy.get('[data-cy=crop-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/crop/new/add_crop_variety');
+ cy.get('[data-cy=crop-variety]').should('exist').type('New Variety');
+ cy.get('[data-cy=crop-supplier]').should('exist').type('New Supplier');
+ cy.get('[type="radio"]').first().check({ force: true });
+ cy.get('[data-cy=variety-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/crop/new/add_crop_variety/compliance');
+ cy.get('[data-cy=compliance-seed]').eq(1).should('exist').check({ force: true });
+ cy.get('[data-cy=compliance-seedAvailability]').eq(1).should('exist').check({ force: true });
+ cy.get('[data-cy=compliance-seedEngineered]').eq(0).should('exist').check({ force: true });
+ cy.get('[data-cy=compliance-seedTreated]').eq(2).should('exist').check({ force: true });
+ cy.get('[data-cy=compliance-newVarietySave]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/management');
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Next')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains(`Let's get started`)
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ //Add a management plan for the new variety
+ cy.get('[data-cy=crop-addPlan]')
+ .contains('Add a plan')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.url().should('include', '/add_management_plan');
+ cy.get('[data-cy=cropPlan-groundPlanted]').should('exist').first().check({ force: true });
+ cy.get('[data-cy=cropPlan-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/add_management_plan/needs_transplant');
+ cy.get('[data-cy=cropPlan-transplantSubmit]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/add_management_plan/plant_date');
+ const date = new Date();
+ date.setDate(date.getDate() + 7);
+ const formattedDate = getDateInputFormat(date);
+ cy.get('[data-cy=cropPlan-plantDate]').should('exist').type(formattedDate);
+ cy.get('[data-cy=cropPlan-seedGermination]').should('exist').type(7);
+ cy.get('[data-cy=cropPlan-plantHarvest]').should('exist').type(200);
+ cy.get('[data-cy=plantDate-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/add_management_plan/choose_final_planting_location');
+ cy.get('[data-cy=map-selectLocation]').should('exist');
+ let heightFactor;
+ let widthFactor;
+ cy.waitForGoogleApi().then(() => {
+ // here comes the code to execute after loading the google Apis
+ cy.get('[data-cy=map-selectLocation]').then(($canvas) => {
+ const canvasWidth = $canvas.width();
+ const canvasHeight = $canvas.height();
+
+ heightFactor = canvasHeight / initialHeight;
+ widthFactor = canvasWidth / initialWidth;
+ cy.contains(fieldName).should('exist');
+ cy.wait(500);
+ cy.get('[data-cy=map-selectLocation]').click(widthFactor * 570, heightFactor * 321, {
+ force: false,
+ });
+ });
+ });
+
+ cy.get('[data-cy=cropPlan-locationSubmit]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/add_management_plan/final_planting_method');
+
+ cy.get('[data-cy=cropPlan-plantingMethod]').eq(0).should('exist').check({ force: true });
+
+ cy.get('[data-cy=plantingMethod-submit]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/add_management_plan/row_method');
+
+ cy.get('[data-cy=rowMethod-equalLength]').eq(0).should('exist').check({ force: true });
+
+ cy.get('[data-cy=rowMethod-rows]').should('exist').should('have.value', '').type('10');
+ cy.get('[data-cy=rowMethod-length]').should('exist').should('have.value', '').type('30');
+ cy.get('[data-cy=rowMethod-spacing]').should('exist').should('have.value', '').type('15');
+ cy.contains('row').click();
+ cy.get('[data-cy=rowMethod-yield]').should('exist').should('have.value', '').type('1500');
+ cy.contains('row').click();
+
+ cy.get('[data-cy=rowMethod-submit]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/add_management_plan/row_guidance');
+ cy.get('[data-cy=planGuidance-submit]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=cropPlan-save]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=spotlight-next]')
+ .contains('Got it')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ //modify the management plan with quick assign modal
+ cy.get('[data-cy=taskCard-dueDate]').eq(0).should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=dateAssign-update]').should('exist').and('be.disabled');
+
+ date.setDate(date.getDate() + 30);
+ const dueDate = getDateInputFormat(date);
+
+ cy.get('[data-cy=dateAssign-date]').should('exist').type(dueDate);
+ cy.get('[data-cy=dateAssign-update]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click()
+ .then(() => {
+ function reformatDateString(s) {
+ var months = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ];
+ var parts = s.split('-');
+ return months[parts[1] - 1] + ' ' + Number(parts[2]) + ', ' + parts[0];
+ }
+
+ const Date = reformatDateString(dueDate);
+
+ cy.get('[data-cy=taskCard-dueDate]').eq(0).contains(Date).should('exist');
+ });
+
+ cy.get('[data-cy=taskCard-assignee]').eq(0).should('exist').and('not.be.disabled');
+ cy.get('[data-cy=taskCard]').eq(1).should('exist').click('right');
+ cy.get('[data-cy=taskReadOnly-pencil]').should('exist').click();
+ cy.get('[data-cy=quickAssign-update]').should('exist').and('not.be.disabled').click();
+
+ //logout
+ //cy.get('[data-cy=home-profileButton]').should('exist').click();
+ //cy.get('[data-cy=navbar-option]').contains('Log Out').should('exist').and('not.be.disabled').click();
+ });
+
+ it('Browser local detection', () => {
+ //Test for LF-2368
+ cy.visit('/', {
+ onBeforeLoad(win) {
+ // solution is here
+ Object.defineProperty(win.navigator, 'languages', {
+ value: ['fr-FR'],
+ });
+ },
+ });
+
+ cy.contains('CONTINUER AVEC GOOGLE').should('exist');
+ cy.get('[data-cy=email]').type('french@test.com');
+ cy.contains('Continue').should('exist').and('be.enabled').click();
+ cy.contains('Créer un nouveau compte utilisateur').should('exist');
+ });
+});
diff --git a/packages/webapp/cypress/integration/insightsFlow.spec.js b/packages/webapp/cypress/integration/insightsFlow.spec.js
new file mode 100644
index 0000000000..ccee4ea852
--- /dev/null
+++ b/packages/webapp/cypress/integration/insightsFlow.spec.js
@@ -0,0 +1,35 @@
+describe.only('Insights flow tests', () => {
+ before(() => {});
+
+ it('Biodiversity insights', () => {
+ //Test for LF-2014
+ cy.visit('/');
+
+ cy.loginFarmOwner();
+ //Action: User navigates to the biodiversity insights page
+ cy.visit('/Insights/Biodiversity');
+
+ cy.window()
+ .its('store')
+ .invoke('getState')
+ .its('insightReducer.biodiversityError')
+ .should('equal', false);
+ //view a modal (using the standard modal pattern) with the following attributes:
+ //Title: “Generating the latest biodiversity insights…”
+ //Body: “We’re generating the latest biodiversity insights for your farm. This can take up to 60 seconds.
+ //”Button: “Cancel”, Action click returns user to insights page
+
+ //If no results are returned within the time-out period (60 sec), replace the “Loading…” modal with the following modal:
+ //Title: “ There was a problem”
+
+ //Body: “LiteFarm generates biodiversity insights based on several sources and was unable to do so at this time.
+ //Please try again after 30 minutes.”
+
+ //Button: “OK” Action click returns user to insights page
+
+ //expected:Mammals should be the top section of the visualization
+ cy.insights().eq(0).contains('Mammals').should('exist');
+
+ //clicking "<" returns user to the insights page
+ });
+});
diff --git a/packages/webapp/cypress/integration/inviteUserFlow.spec.js b/packages/webapp/cypress/integration/inviteUserFlow.spec.js
new file mode 100644
index 0000000000..b7381c3f8c
--- /dev/null
+++ b/packages/webapp/cypress/integration/inviteUserFlow.spec.js
@@ -0,0 +1,43 @@
+describe.only('Invite user tests', () => {
+ before(() => {});
+ it('Invite an existing user with a chosen langauge', () => {
+ //Test for LF-2301
+ //after running happy path test
+ //create a user account with language set to Spanish
+ //login to the default farm created by the happy path tests
+ //invite the spanish user to the default farm
+ //Spanish user should receive an invitation email in spanish
+ //repeat for all languages
+ });
+
+ it.only('Invite a new user and select invitation langauge', () => {
+ //Test for LF-2366
+ const userName = 'NewUser';
+ const uuid = () => Cypress._.random(0, 1e6);
+ const id = uuid();
+ const userEmail = `${userName}${id}@example.com`;
+ let count = 1;
+ //after running happy path test
+ cy.visit('/');
+ //login as an admin user
+ cy.loginFarmOwner();
+ //navigate to the people view
+ cy.visit('/people');
+ //Click invite a user
+ cy.contains('Invite User').click();
+ //Input a name, select a role and an invitation language and click send invitation
+ cy.get('[data-cy=invite-fullName]').should('exist').type(userName);
+ cy.contains('Choose Role').should('exist').click({ force: true });
+ cy.contains('Farm Worker').should('exist').click();
+ cy.get('[data-cy=invite-email]').should('exist').type(userEmail);
+ count++;
+ cy.contains('English').should('exist').click({ force: true });
+ cy.contains('Spanish').should('exist').click();
+ //cy.intercept('POST', '/user/invite').as('invite');
+ cy.get('[data-cy=invite-submit]').should('exist').and('not.be.disabled').click();
+ //Ensure invitation is in correct language
+ cy.task('getLastEmail', userEmail).then((email) => {
+ cy.log(email);
+ });
+ });
+});
diff --git a/packages/webapp/cypress/integration/locationFlow.spec.js b/packages/webapp/cypress/integration/locationFlow.spec.js
new file mode 100644
index 0000000000..93dd0f12dd
--- /dev/null
+++ b/packages/webapp/cypress/integration/locationFlow.spec.js
@@ -0,0 +1,14 @@
+describe.only('Location flow tests', () => {
+ before(() => {});
+
+ it('Field area tests ', () => {
+ //Test for LF-2318
+ //Click on a crop enabled field
+ //Click on a crop on the crops tab
+ //Click back from the crop variety view
+ //click on the < button
+ // ensure you are back on the correct location details view
+ //click on the < button
+ //ensure you are back on the location map page
+ });
+});
diff --git a/packages/webapp/cypress/integration/loginFlow.spec.js b/packages/webapp/cypress/integration/loginFlow.spec.js
new file mode 100644
index 0000000000..bf5ae64ecc
--- /dev/null
+++ b/packages/webapp/cypress/integration/loginFlow.spec.js
@@ -0,0 +1,7 @@
+describe.only('Login flow tests', () => {
+ it('SSO Google Account', () => {
+ cy.loginByGoogleApi().then(() => {
+ cy.get('[data-cy=continueGoogle]').should('exist').and('not.be.disabled').click();
+ });
+ });
+});
diff --git a/packages/webapp/cypress/integration/notificationsFlow.spec.js b/packages/webapp/cypress/integration/notificationsFlow.spec.js
new file mode 100644
index 0000000000..60ad47f727
--- /dev/null
+++ b/packages/webapp/cypress/integration/notificationsFlow.spec.js
@@ -0,0 +1,153 @@
+import { getDateInputFormat } from '../../src/util/moment';
+
+describe.only('Notifications flow tests', () => {
+ before(() => {
+ //Ensure test environment is setup(i.e. farm exists, user accounts exist, tasks exist)
+ });
+
+ it('farm worker notifications flow tests', () => {
+ //notifications bell exists in the status bar
+ cy.get('[data-cy=home-notificationButton]').should('exist').and('not.be.disabled');
+ //Notifications bell displays the number of unread notifications,if a user has 10 or more notifications
+ //the notifications bell displays 9+
+
+ //On mouse hover over the notifications bell show “Go to Notification Centre”
+
+ //clicking on the notifications bell icon should open the notifications centre
+ cy.get('[data-cy=home-notificationButton]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/notifications');
+ });
+
+ it('admin user notifications flow tests', () => {
+ //Below is the test script for LF-2187 run it after running the happyPath spec
+ cy.visit('/');
+ cy.loginFarmOwner();
+ //notifications bell exists in the status bar
+ cy.get('[data-cy=home-notificationButton]').should('exist').and('not.be.disabled');
+ //Notifications bell displays the number of unread notifications,if a user has 10 or more notifications
+ //the notifications bell displays 9+
+ cy.get('[data-cy=notification-alert]').should('exist').and('have.text', '1');
+ //On mouse hover over the notifications bell show “Go to Notification Centre”
+ cy.get('[data-cy=home-notificationButton').trigger('mouseover');
+ //clicking on the notifications bell icon should open the notifications centre
+ cy.get('[data-cy=home-notificationButton]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/notifications');
+ });
+
+ it.only('Weekly scheduled notifications', () => {
+ //Test for LF-2386
+ //login as farm manager
+ cy.visit('/');
+ cy.loginFarmOwner();
+ //Create unassigned tasks due this week
+ cy.wait(2000);
+ cy.visit('/tasks');
+ cy.createUnassignedTaskThisWeek(); //creates a task due date to today assigned to the logged in user
+
+ //post request to the api to generate notifications
+
+ let id;
+ let authorization;
+
+ cy.window()
+ .its('store')
+ .invoke('getState')
+ .its('entitiesReducer.userFarmReducer.farm_id')
+ .then((farm_id) => {
+ id = farm_id;
+ authorization = 'JWT TOKEN';
+ cy.log(authorization);
+ cy.request({
+ method: 'POST',
+ url: `${Cypress.env('apiUrl')}/time_notification/weekly_unassigned_tasks/${id}`,
+ headers: {
+ Authorization: `Bearer ${authorization}`,
+ },
+ })
+ .then((response) => {
+ return response;
+ })
+ .its('status')
+ .should('eq', 201);
+ });
+
+ cy.visit('/notifications');
+ cy.get('[data-cy=notification-card]').eq(0).contains('Unassigned tasks').should('exist');
+
+ cy.get('[data-cy=notification-card]')
+ .eq(0)
+ .contains('You have unassigned tasks due this week.')
+ .should('exist');
+
+ cy.get('[data-cy=notification-card]').eq(0).click();
+ cy.contains('Take me there').click();
+
+ const today = new Date();
+ const day = today.getDay();
+ const Monday = today.setDate(today.getDate() - (day - 1));
+ const dispMonday = getDateInputFormat(Monday);
+ cy.get('._pillContainer_70or9_15 > :nth-child(2)')
+ .contains(`From: ${dispMonday}`)
+ .should('exist');
+ });
+
+ it('Daily scheduled notifications', () => {
+ //Test for LF-2387 run after happyPath
+ //login as farm manager
+ cy.visit('/');
+ cy.loginFarmOwner();
+ //Create unassigned tasks due this week
+ cy.wait(2000);
+ cy.visit('/tasks');
+ cy.createTaskToday(); //creates a task due date to today assigned to the logged in user
+
+ //post request to the api to generate notifications
+
+ let id;
+ let authorization;
+
+ cy.window()
+ .its('store')
+ .invoke('getState')
+ .its('entitiesReducer.userFarmReducer.farm_id')
+ .then((farm_id) => {
+ id = farm_id;
+ authorization = 'JWT TOKEN';
+ cy.log(authorization);
+ cy.request({
+ method: 'POST',
+ url: `${Cypress.env('apiUrl')}/time_notification/daily_due_today_tasks/${id}`,
+ headers: {
+ Authorization: `Bearer ${authorization}`,
+ },
+ })
+ .then((response) => {
+ return response;
+ })
+ .its('status')
+ .should('eq', 201);
+ });
+
+ cy.visit('/notifications');
+ cy.get('[data-cy=notification-card]').eq(0).contains('Tasks due today').should('exist');
+
+ cy.get('[data-cy=notification-card]').eq(0).click();
+ cy.contains('Take me there').click();
+ });
+
+ it('Re-assign notification flow', () => {
+ //Test for LF-2376
+ //Run happy path test
+ //login as an admin user
+
+ //Create a task
+ cy.visit('/tasks');
+ cy.createTask();
+ //Assign the task to self
+ cy.get('[data-cy=taskCard]').eq(0).should('exist').contains('Test F.').click();
+ //Change the assignee of the task to self
+ //check that notification bell has incremented by one
+ //Navigate to notifications view, assert that the newest notification is a reassignment notification for the task
+ //re-assigned task
+ });
+});
diff --git a/packages/webapp/cypress/integration/tasksFlow.spec.js b/packages/webapp/cypress/integration/tasksFlow.spec.js
new file mode 100644
index 0000000000..34bec7f18b
--- /dev/null
+++ b/packages/webapp/cypress/integration/tasksFlow.spec.js
@@ -0,0 +1,236 @@
+import { getDateInputFormat } from '../../src/util/moment';
+
+describe.only('Tasks flow tests', () => {
+ before(() => {
+ //Ensure test environment is setup(i.e. farm exists, user accounts exist, tasks exist)
+ });
+
+ it('farm worker tasks flow tests', () => {
+ cy.visit('/');
+ cy.loginFarmWorker();
+ cy.get('[data-cy=home-taskButton]').should('exist').and('not.be.disabled').click();
+ cy.url().should('include', '/tasks');
+ cy.get('[data-cy=pill-close]').should('exist').and('not.be.disabled').click();
+
+ //Unassigned tasks : Farm workers should be able to assign the task to themselves
+ cy.contains('Unassigned').should('exist').and('not.be.disabled').click();
+ //(the farm worker and “Unassigned” should be the only quick assign options)
+ cy.selectDropdown().click();
+ cy.selectOptions().contains('Unassigned').should('exist');
+ cy.selectOptions().contains('Test Worker').should('exist');
+ cy.contains('Cancel').should('exist').click({ force: true });
+
+ //Tasks assigned to the farm worker: Farm workers should be able to Unassign the task
+ cy.contains('Test W.').should('exist').and('not.be.disabled').click();
+ // (the farm worker and “Unassigned” should be the only quick assign options)
+ cy.selectDropdown().click();
+ cy.selectOptions().contains('Test Worker').should('exist');
+ cy.selectOptions().contains('Unassigned').should('exist').click();
+ cy.contains('Update').should('exist').click({ force: true });
+
+ //Tasks assigned to other individuals on the farm: None! Task card should be read-only
+ cy.contains('Test F.').should('exist').click();
+ cy.contains('Assign').should('not.exist');
+
+ //No visual cue that the user can update due date
+
+ //clicking on a task should open the read_only view for said task(test for LF-2374)
+ //cy.url().should('include', '/read_only');
+
+ //Assignee input should exist and should be.disabled, there should not be a pencil next to the input (test for LF-2374)
+
+ //Due date input should exist and be disabled there should not be a pencil next to the input (test for LF-2374)
+
+ //locations map should exist and display here said task will be carried out
+ //Task specific data should exist(e.g. cleaning agent and estimated water usage for a cleaning task)
+ });
+
+ it('admin user tasks flow tests', () => {
+ //Test for Lf-2314
+
+ cy.visit('/');
+ cy.loginFarmOwner();
+ cy.get('[data-cy=home-taskButton]').should('exist').and('not.be.disabled').click();
+
+ cy.createTask();
+ cy.createTask();
+
+ //assign all unassigned tasks on date to selected user
+ cy.url().should('include', '/tasks');
+ cy.get('[data-cy=pill-close]').should('exist').and('not.be.disabled').click();
+ cy.contains('Unassigned').last().should('exist').and('not.be.disabled').click({ force: true });
+ cy.get('[data-cy=quickAssign-assignAll]').should('exist').check({ force: true });
+ cy.get('[data-cy=quickAssign-update]').should('exist').and('not.be.disabled').click();
+ cy.contains('Tasks').should('exist');
+
+ //clicking on a task should open the read_only view for said task (test for LF-2374)
+ //cy.url().should('include', '/read_only');
+
+ //Assignee input should exist and should be.disabled, there should be a pencil next to the input and
+ //the quick assign modal should appear on click (test for LF-2374)
+
+ //Due date input should exist and be disabledhere should be a pencil next to the input and
+ //the quick assign modal should appear on click (test for LF-2374)
+
+ //locations map should exist and display here said task will be carried out
+ //Task specific data should exist(e.g. cleaning agent and estimated water usage for a cleaning task)
+ });
+
+ it('Admin user must be able to complete tasks on behalf pseudo users', () => {
+ //Test for LF-2230
+ cy.visit('/');
+ cy.loginFarmOwner();
+ cy.get('[data-cy=home-taskButton]').should('exist').and('not.be.disabled').click();
+ cy.createTask();
+ cy.get('[data-cy=pill-close]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=taskCard]').eq(25).should('exist').click('right');
+ cy.get('[data-cy=taskReadOnly-pencil]').should('exist').click();
+ cy.contains('Test Farmer').should('exist').click({ force: true });
+ cy.contains('Sudo').should('exist').click({ force: true });
+ cy.get('[data-cy=quickAssign-update]').should('exist').and('not.be.disabled').click();
+ cy.contains('Mark Complete').should('exist').click({ force: true });
+ cy.contains('Continue').should('exist').click({ force: true });
+ cy.get('[data-cy=harvestComplete-rating]').should('exist').check({ force: true });
+ cy.get('[data-cy=harvestComplete-save]').should('exist').and('not.be.disabled').click();
+ });
+
+ it.only('harvest task for apricot', () => {
+ //tests for LF-2332
+ cy.visit('/');
+ cy.loginFarmOwner();
+
+ //create a harvest plan for apricot
+ cy.get('[data-cy=navbar-hamburger]').should('exist').click();
+ cy.contains('Crops').should('exist').click();
+ cy.contains('Apricot').should('exist').click();
+
+ cy.contains('New Variety').should('exist').and('not.be.disabled').click();
+
+ cy.get('[data-cy=crop-addPlan]')
+ .contains('Add a plan')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+
+ cy.get('[data-cy=cropPlan-groundPlanted]').should('exist').eq(1).check({ force: true });
+ cy.get('[data-cy=cropPlan-age]').should('exist').type(200);
+ cy.get('[data-cy=cropPlan-wildCrop]').should('exist').eq(1).check({ force: true });
+ cy.get('[data-cy=cropPlan-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.get('[data-cy=cropPlan-transplanted]').should('exist').eq(1).check({ force: true });
+ cy.get('[data-cy=cropPlan-transplantSubmit]').should('exist').and('not.be.disabled').click();
+
+ const date = new Date();
+ date.setDate(date.getDate() + 7);
+ const formattedDate = getDateInputFormat(date);
+ cy.get('[data-cy=cropPlan-plantDate]').should('exist').type(formattedDate);
+ cy.get('[data-cy=plantDate-submit]').should('exist').and('not.be.disabled').click();
+
+ cy.wait(2000);
+ cy.get('[data-cy=map-selectLocation]').click(540, 201, {
+ force: false,
+ });
+ cy.contains('Continue').should('exist').and('not.be.disabled').click({ force: true });
+
+ cy.get('[type="radio"]').first().check({ force: true });
+ cy.contains('Continue').should('exist').and('not.be.disabled').click({ force: true });
+ cy.get('[type="radio"]').first().check({ force: true });
+
+ cy.get('[data-cy=rowMethod-rows]').should('exist').type(10);
+ cy.get('[data-cy=rowMethod-length]').should('exist').type(30);
+ cy.get('[data-cy=rowMethod-spacing]').should('exist').clear().type('15');
+ cy.contains('Estimated').click();
+ cy.get('[data-cy=rowMethod-yield]').should('have.value', '1.43');
+ });
+
+ it('harvest task compeletion tests', () => {
+ //these are tests for LF2360 run this test script after running the happy path test
+ //Action: click on the tasks icon. Expected: The tasks view opens with several task cards visible
+ cy.visit('/');
+ cy.loginFarmOwner();
+ cy.get('[data-cy=home-taskButton]').should('exist').and('not.be.disabled').click();
+
+ //Action: Click on a harvest task, task card. Expected: Task read only view for selected harvest task is displayed
+ cy.get('[data-cy=taskCard]').eq(0).should('exist').click('right');
+
+ //Action: Click on complete task button Expected: Enter task completion flow
+ cy.get('[data-cy=taskReadOnly-complete]').should('exist').and('not.be.disabled').click();
+
+ //Action: Complete harvest task completion flow. Expected: Task read only view displayed
+ //with the task card for the just completed harvest task showing the correct details
+ cy.get('[data-cy=harvestQuantity-quantity]').should('exist').type(1000);
+ cy.get('[data-cy=harvestQuantity-continue]').should('exist').and('not.be.disabled').click();
+
+ cy.get('[data-cy=harvestUses-quantity]').should('exist').type(1000);
+ cy.contains('Select').should('exist').click({ force: true });
+ cy.contains('Self').should('exist').click({ force: true });
+ cy.get('[data-cy=harvestUses-continue]').should('exist').and('not.be.disabled').click();
+
+ cy.get('[data-cy=harvestComplete-rating]').should('exist').check({ force: true });
+ cy.get('[data-cy=harvestComplete-save]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/tasks');
+ cy.get('[data-cy=taskCard]').eq(0).should('exist').click('right');
+ cy.contains('completed').should('exist');
+ });
+
+ it('tasks filters tests', () => {
+ //tests for LF2365, run this test after running the happyPath spec
+ cy.visit('/');
+ cy.loginFarmOwner();
+ cy.get('[data-cy=home-taskButton]').should('exist').and('not.be.disabled').click();
+
+ // //user clicks on the funnel icon on the tasks view to open the tasks filter view
+ cy.get('[data-cy=tasks-filter]').click({ force: true });
+ // //user clicks on the assignee input
+ // //assert that all active users appear in the dropdown (test for LF-2365)
+ // //assert that the assignee input is searchable
+ // //user types a letter into the assignee input, assert that the filter workspace
+ // //user clicks on one of the users, assert that a pill is generated for said user
+
+ // user clicks on the type filter, all 7 task types should appear (test for LF-2364)
+ });
+
+ it('Complete crop plan', () => {
+ //Test for LF-2178
+ //Go to completed crop plan’s detail page, user should see the following:
+ //Expect Completed date
+ //Expect Plan rating
+ // Expect Completion notes
+ // Expect Plan notes
+ // Expect Estimated annual yield
+ });
+
+ it('Abandon task', () => {
+ //Test for LF-2391
+ //navigate to the read only view of an abandoned tasks
+ //expected due date label and input between abandonment date and location
+ //Test for F21-588
+ //Abandon a task assigned to another user
+ //Ensure user not asked to rate the task.
+ //Rating not shown on the abandoned task page and it should be assigned as “I prefer not to say”
+ });
+
+ it('location tasks tab', () => {
+ //test for LF-2199
+ //navigate to maps view
+ //click on a location task
+ //tasks tab should be visible click on tasks tab
+ //task cards for selected location should be visible
+ //task count should be visible and correct
+ // create a task link should exist
+ });
+
+ it('Admin user must be able to unassign tasks', () => {
+ //Test for LF-2323
+ //login as a user with admin rights
+ //navigate to the tasks view
+ //create a task, ensure an assignee is selected
+ //back on the task view, change the assignee for the created task to unassigned and click update
+ //ensure task card is updated to reflect the new assignee status
+ //change the assignee to another user via quick assign modal
+ //click the task card to enter the task readonly view
+ //click the pencil next to assignee to open the quick assign modal and change the assignee to unassigned
+ //ensure the change to assignee persists for selected task
+ });
+});
diff --git a/packages/webapp/cypress/plugins/index.js b/packages/webapp/cypress/plugins/index.js
new file mode 100644
index 0000000000..9be1041911
--- /dev/null
+++ b/packages/webapp/cypress/plugins/index.js
@@ -0,0 +1,55 @@
+///
+// cypress/plugins/index.js
+
+// ***********************************************************
+// This example plugins/index.js can be used to load plugins
+//
+// You can change the location of this file or turn off loading
+// the plugins file with the 'pluginsFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/plugins-guide
+// ***********************************************************
+
+// This function is called when a project is opened or re-opened (e.g. due to
+// the project's config changing)
+
+/**
+ * @type {Cypress.PluginConfig}
+ */
+// eslint-disable-next-line no-unused-vars
+const axios = require('axios');
+const ms = require('smtp-tester');
+
+module.exports = (on, config) => {
+ // `on` is used to hook into various events Cypress emits
+ // `config` is the resolved Cypress config
+ config.env.googleRefreshToken = process.env.GOOGLE_REFRESH_TOKEN;
+ config.env.googleClientId = process.env.REACT_APP_GOOGLE_CLIENTID;
+ config.env.googleClientSecret = process.env.REACT_APP_GOOGLE_CLIENT_SECRET;
+
+ require('@cypress/code-coverage/task')(on, config);
+
+ // starts the SMTP server at localhost:7777
+ const port = 465;
+ const mailServer = ms.init(port);
+ console.log('mail server at port %d', port);
+
+ // process all emails
+ mailServer.bind((addr, id, email) => {
+ console.log('--- email ---');
+ console.log(addr, id, email);
+ });
+
+ let lastEmail = {};
+
+ on('task', {
+ getLastEmail(email) {
+ // cy.task cannot return undefined
+ // thus we return null as a fallback
+ return lastEmail[email] || null;
+ },
+ });
+
+ return config;
+};
diff --git a/packages/webapp/cypress/support/commands.js b/packages/webapp/cypress/support/commands.js
new file mode 100644
index 0000000000..939e93a34d
--- /dev/null
+++ b/packages/webapp/cypress/support/commands.js
@@ -0,0 +1,232 @@
+import 'cypress-react-selector';
+import { getDateInputFormat } from '../../src/util/moment';
+
+// cypress/support/commands.js
+Cypress.Commands.add('loginByGoogleApi', () => {
+ cy.log(process.env.REACT_APP_GOOGLE_CLIENTID);
+ cy.log('Logging in to Google');
+ cy.request({
+ method: 'POST',
+ url: 'https://www.googleapis.com/oauth2/v4/token',
+ body: {
+ grant_type: 'refresh_token',
+ client_id: Cypress.env('REACT_APP_GOOGLE_CLIENTID'),
+ client_secret: Cypress.env('REACT_APP_GOOGLE_CLIENT_SECRET'),
+ refresh_token: Cypress.env('GOOGLE_REFRESH_TOKEN'),
+ },
+ }).then(({ body }) => {
+ const { access_token, id_token } = body;
+
+ cy.request({
+ method: 'GET',
+ url: 'https://www.googleapis.com/oauth2/v3/userinfo',
+ headers: { Authorization: `Bearer ${access_token}` },
+ }).then(({ body }) => {
+ cy.log(body);
+ const userItem = {
+ token: id_token,
+ user: {
+ googleId: body.sub,
+ email: body.email,
+ givenName: body.given_name,
+ familyName: body.family_name,
+ imageUrl: body.picture,
+ },
+ };
+
+ window.localStorage.setItem('id_token', userItem.token);
+ });
+ });
+});
+
+Cypress.Commands.add('waitForGoogleApi', () => {
+ let mapWaitCount = 0;
+ const mapWaitMax = 5;
+
+ cyMapLoad();
+
+ function cyMapLoad() {
+ mapWaitCount++;
+
+ cy.window().then((win) => {
+ if (typeof win.google != 'undefined') {
+ console.log(`Done at attempt #${mapWaitCount}:`, win);
+ return true;
+ } else if (mapWaitCount <= mapWaitMax) {
+ console.log('Waiting attempt #' + mapWaitCount); // just log
+ cy.wait(2000);
+ cyMapLoad();
+ } else if (mapWaitCount > mapWaitMax) {
+ console.log('Failed to load google api');
+ return false;
+ }
+ });
+ }
+});
+
+Cypress.Commands.add('loginFarmOwner', () => {
+ const emailOwner = 'mbolokonya@litefarm.org';
+ const password = 'P@ssword123';
+
+ //Enter password page
+ cy.get('[data-cy=email]').type(emailOwner);
+ cy.contains('Continue').should('exist').and('be.enabled').click();
+ cy.get('[data-cy=enterPassword-password]').type(password);
+ cy.get('[data-cy=enterPassword-submit]').should('exist').and('be.enabled').click();
+
+ cy.get('[data-cy=chooseFarm-ubc]').eq(0).should('exist').click('right');
+ cy.get('[data-cy="chooseFarm-proceed"]').should('exist').and('be.enabled').click();
+});
+
+Cypress.Commands.add('loginFarmWorker', () => {
+ const emailOwner = 'worker@example.com';
+ const password = 'P@ssword123';
+
+ //Enter password page
+ cy.get('[data-cy=email]').type(emailOwner);
+ cy.contains('Continue').should('exist').and('be.enabled').click();
+ cy.get('[data-cy=enterPassword-password]').type(password);
+ cy.get('[data-cy=enterPassword-submit]').should('exist').and('be.enabled').click();
+
+ cy.get('[data-cy=chooseFarm-ubc]').eq(0).should('exist').click('right');
+ cy.get('[data-cy=chooseFarm-proceed]').should('exist').and('be.enabled').click();
+});
+
+Cypress.Commands.add('createSudoUser', () => {
+ cy.get('[data-cy=home-farmButton]').should('exist').and('not.be.disabled').click();
+ cy.get('[data-cy=navbar-option]')
+ .contains('People')
+ .should('exist')
+ .and('not.be.disabled')
+ .click();
+ cy.url().should('include', '/people');
+ cy.get('[data-cy=people-inviteUser]').should('exist').and('not.be.disabled').click();
+
+ cy.url().should('include', '/invite_user');
+ cy.get('[data-cy=invite-fullName]').should('exist').type('Sudo User');
+ cy.contains('Choose Role').should('exist').click({ force: true });
+ cy.contains('Farm Worker').should('exist').click();
+ cy.get('[data-cy=invite-submit]').should('exist').and('not.be.disabled').click();
+});
+
+Cypress.Commands.add('selectDropdown', () => {
+ cy.get('.css-tj5bde-Svg').should('exist');
+});
+Cypress.Commands.add('selectOptions', () => {
+ cy.get('.css-1plh46m-MenuList2').should('exist');
+});
+
+Cypress.Commands.add('insights', () => {
+ cy.get('._infoTextLine_avdgi_23').should('exist');
+});
+//
+Cypress.Commands.add('createTask', () => {
+ //Create an unassigned cleaning task due tomorrow
+ cy.contains('Create').should('exist').and('not.be.disabled').click({ force: true });
+ cy.contains('Clean').should('exist').and('not.be.disabled').click({ force: true });
+
+ const date = new Date();
+ date.setDate(date.getDate() + 1);
+ const dueDate = getDateInputFormat(date);
+
+ cy.get('[data-cy=addTask-taskDate]').should('exist').type(dueDate);
+
+ cy.get('[data-cy=addTask-continue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.wait(2000);
+ cy.get('[data-cy=map-selectLocation]').click(540, 201, {
+ force: false,
+ });
+ cy.get('[data-cy=addTask-locationContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-cropsContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-detailsContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-assignmentSave]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+});
+
+Cypress.Commands.add('createTaskToday', () => {
+ //Create an unassigned cleaning task due today
+ cy.contains('Create').should('exist').and('not.be.disabled').click({ force: true });
+ cy.contains('Clean').should('exist').and('not.be.disabled').click({ force: true });
+
+ const date = new Date();
+ const dueDate = getDateInputFormat(date);
+
+ cy.get('[data-cy=addTask-taskDate]').should('exist').type(dueDate);
+
+ cy.get('[data-cy=addTask-continue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.wait(2000);
+ cy.get('[data-cy=map-selectLocation]').click(540, 201, {
+ force: false,
+ });
+ cy.get('[data-cy=addTask-locationContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy="addTask-cropsContinue"]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-detailsContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('.css-ujecln-Input2').click();
+ cy.contains('Test Farmer').click({ force: true });
+ cy.get('[data-cy=addTask-assignmentSave]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+});
+
+Cypress.Commands.add('createUnassignedTaskThisWeek', () => {
+ //Create an unassigned cleaning task due today
+ cy.contains('Create').should('exist').and('not.be.disabled').click({ force: true });
+ cy.contains('Clean').should('exist').and('not.be.disabled').click({ force: true });
+
+ const date = new Date();
+ const dueDate = getDateInputFormat(date);
+
+ cy.get('[data-cy=addTask-taskDate]').should('exist').type(dueDate);
+
+ cy.get('[data-cy=addTask-continue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.wait(2000);
+ cy.get('[data-cy=map-selectLocation]').click(540, 201, {
+ force: false,
+ });
+ cy.get('[data-cy=addTask-locationContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy="addTask-cropsContinue"]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-detailsContinue]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+ cy.get('[data-cy=addTask-assignmentSave]')
+ .should('exist')
+ .and('not.be.disabled')
+ .click({ force: true });
+});
diff --git a/packages/webapp/cypress/support/index.js b/packages/webapp/cypress/support/index.js
new file mode 100644
index 0000000000..89dc263cc5
--- /dev/null
+++ b/packages/webapp/cypress/support/index.js
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands';
+import '@cypress/code-coverage/support';
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/packages/webapp/dev.Dockerfile b/packages/webapp/dev.Dockerfile
deleted file mode 100644
index 37c0f2e078..0000000000
--- a/packages/webapp/dev.Dockerfile
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM node:10.14.0
-
-WORKDIR /usr/src/app
-
-COPY ./package.json .
-
-COPY ./package-lock.json .
-
-RUN npm install
-
-COPY . .
-
-CMD npm start
diff --git a/packages/webapp/i18next-parser.config.js b/packages/webapp/i18next-parser.config.js
deleted file mode 100644
index 75e19843c4..0000000000
--- a/packages/webapp/i18next-parser.config.js
+++ /dev/null
@@ -1,86 +0,0 @@
-module.exports = {
- contextSeparator: '_',
- // Key separator used in your translation keys
-
- createOldCatalogues: true,
- // Save the \_old files
-
- defaultNamespace: 'translation',
- // Default namespace used in your i18next config
-
- defaultValue: 'MISSING',
- // Default value to give to empty keys
-
- indentation: 2,
- // Indentation of the catalog files
-
- keepRemoved: false,
- // Keep keys from the catalog that are no longer in code
-
- keySeparator: '.',
- // Key separator used in your translation keys
- // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
-
- // see below for more details
- lexers: {
- hbs: ['HandlebarsLexer'],
- handlebars: ['HandlebarsLexer'],
-
- htm: ['HTMLLexer'],
- html: ['HTMLLexer'],
-
- mjs: ['JavascriptLexer'],
- js: ['JavascriptLexer'], // if you're writing jsx inside .js files, change this to JsxLexer
- ts: ['JavascriptLexer'],
- jsx: ['JsxLexer'],
- tsx: ['JsxLexer'],
-
- default: ['JavascriptLexer'],
- },
-
- lineEnding: 'lf',
- // Control the line ending. See options at https://github.com/ryanve/eol
-
- locales: ['en', 'es', 'pt', 'fr'],
- // An array of the locales in your applications
-
- namespaceSeparator: ':',
- // Namespace separator used in your translation keys
- // If you want to use plain english keys, separators such as `.` and `:` will conflict. You might want to set `keySeparator: false` and `namespaceSeparator: false`. That way, `t('Status: Loading...')` will not think that there are a namespace and three separator dots for instance.
-
- output: 'public/locales/$LOCALE/$NAMESPACE.json',
- // Supports $LOCALE and $NAMESPACE injection
- // Supports JSON (.json) and YAML (.yml) file formats
- // Where to write the locale files relative to process.cwd()
-
- input: undefined,
- // An array of globs that describe where to look for source files
- // relative to the location of the configuration file
-
- sort: true,
- // Whether or not to sort the catalog
-
- skipDefaultValues: false,
- // Whether to ignore default values.
-
- useKeysAsDefaultValue: false,
- // Whether to use the keys as the default value; ex. "Hello": "Hello", "World": "World"
- // This option takes precedence over the `defaultValue` and `skipDefaultValues` options
-
- verbose: false,
- // Display info about the parsing including some stats
-
- failOnWarnings: false,
- // Exit with an exit code of 1 on warnings
-
- customValueTemplate: null,
- // If you wish to customize the value output the value as an object, you can set your own format.
- // ${defaultValue} is the default value you set in your translation function.
- // Any other custom property will be automatically extracted.
- //
- // Example:
- // {
- // message: "${defaultValue}",
- // description: "${maxLength}", // t('my-key', {maxLength: 150})
- // }
-};
diff --git a/packages/webapp/index.html b/packages/webapp/index.html
new file mode 100644
index 0000000000..4106e71710
--- /dev/null
+++ b/packages/webapp/index.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Lite Farm
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
+
+
diff --git a/packages/webapp/package-lock.json b/packages/webapp/package-lock.json
deleted file mode 100644
index 4d5cc597ca..0000000000
--- a/packages/webapp/package-lock.json
+++ /dev/null
@@ -1,30047 +0,0 @@
-{
- "name": "webapp",
- "version": "1.0.2",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz",
- "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==",
- "requires": {
- "@babel/highlight": "^7.12.13"
- }
- },
- "@babel/compat-data": {
- "version": "7.13.6",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.6.tgz",
- "integrity": "sha512-VhgqKOWYVm7lQXlvbJnWOzwfAQATd2nV52koT0HZ/LdDH0m4DUDwkKYsH+IwpXb+bKPyBJzawA4I6nBKqZcpQw=="
- },
- "@babel/core": {
- "version": "7.12.3",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz",
- "integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==",
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.1",
- "@babel/helper-module-transforms": "^7.12.1",
- "@babel/helpers": "^7.12.1",
- "@babel/parser": "^7.12.3",
- "@babel/template": "^7.10.4",
- "@babel/traverse": "^7.12.1",
- "@babel/types": "^7.12.1",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.1",
- "json5": "^2.1.2",
- "lodash": "^4.17.19",
- "resolve": "^1.3.2",
- "semver": "^5.4.1",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- }
- }
- },
- "@babel/generator": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.0.tgz",
- "integrity": "sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw==",
- "requires": {
- "@babel/types": "^7.13.0",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- }
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz",
- "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-builder-binary-assignment-operator-visitor": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz",
- "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==",
- "requires": {
- "@babel/helper-explode-assignable-expression": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.0.tgz",
- "integrity": "sha512-SOWD0JK9+MMIhTQiUVd4ng8f3NXhPVQvTv7D3UN4wbp/6cAHnB2EmMaU1zZA2Hh1gwme+THBrVSqTFxHczTh0Q==",
- "requires": {
- "@babel/compat-data": "^7.13.0",
- "@babel/helper-validator-option": "^7.12.17",
- "browserslist": "^4.14.5",
- "semver": "7.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "semver": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
- "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
- }
- }
- },
- "@babel/helper-create-class-features-plugin": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.0.tgz",
- "integrity": "sha512-twwzhthM4/+6o9766AW2ZBHpIHPSGrPGk1+WfHiu13u/lBnggXGNYCpeAyVfNwGDKfkhEDp+WOD/xafoJ2iLjA==",
- "requires": {
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-member-expression-to-functions": "^7.13.0",
- "@babel/helper-optimise-call-expression": "^7.12.13",
- "@babel/helper-replace-supers": "^7.13.0",
- "@babel/helper-split-export-declaration": "^7.12.13"
- }
- },
- "@babel/helper-create-regexp-features-plugin": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz",
- "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "regexpu-core": "^4.7.1"
- }
- },
- "@babel/helper-define-polyfill-provider": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.1.2.tgz",
- "integrity": "sha512-hWeolZJivTNGHXHzJjQz/NwDaG4mGXf22ZroOP8bQYgvHNzaQ5tylsVbAcAS2oDjXBwpu8qH2I/654QFS2rDpw==",
- "requires": {
- "@babel/helper-compilation-targets": "^7.13.0",
- "@babel/helper-module-imports": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/traverse": "^7.13.0",
- "debug": "^4.1.1",
- "lodash.debounce": "^4.0.8",
- "resolve": "^1.14.2",
- "semver": "^6.1.2"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "@babel/helper-environment-visitor": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz",
- "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-explode-assignable-expression": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz",
- "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==",
- "requires": {
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz",
- "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==",
- "requires": {
- "@babel/helper-get-function-arity": "^7.12.13",
- "@babel/template": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz",
- "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz",
- "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==",
- "requires": {
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz",
- "integrity": "sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ==",
- "requires": {
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz",
- "integrity": "sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz",
- "integrity": "sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw==",
- "requires": {
- "@babel/helper-module-imports": "^7.12.13",
- "@babel/helper-replace-supers": "^7.13.0",
- "@babel/helper-simple-access": "^7.12.13",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/helper-validator-identifier": "^7.12.11",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.0",
- "lodash": "^4.17.19"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz",
- "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz",
- "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ=="
- },
- "@babel/helper-remap-async-to-generator": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz",
- "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "@babel/helper-wrap-function": "^7.13.0",
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helper-replace-supers": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz",
- "integrity": "sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw==",
- "requires": {
- "@babel/helper-member-expression-to-functions": "^7.13.0",
- "@babel/helper-optimise-call-expression": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz",
- "integrity": "sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz",
- "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==",
- "requires": {
- "@babel/types": "^7.12.1"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz",
- "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==",
- "requires": {
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz",
- "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw=="
- },
- "@babel/helper-validator-option": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz",
- "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw=="
- },
- "@babel/helper-wrap-function": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz",
- "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==",
- "requires": {
- "@babel/helper-function-name": "^7.12.13",
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/helpers": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.0.tgz",
- "integrity": "sha512-aan1MeFPxFacZeSz6Ld7YZo5aPuqnKlD7+HZY75xQsueczFccP9A7V05+oe0XpLwHK3oLorPe9eaAUljL7WEaQ==",
- "requires": {
- "@babel/template": "^7.12.13",
- "@babel/traverse": "^7.13.0",
- "@babel/types": "^7.13.0"
- }
- },
- "@babel/highlight": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.12.13.tgz",
- "integrity": "sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.12.11",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "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"
- }
- }
- }
- },
- "@babel/parser": {
- "version": "7.13.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.4.tgz",
- "integrity": "sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA=="
- },
- "@babel/plugin-proposal-async-generator-functions": {
- "version": "7.13.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.5.tgz",
- "integrity": "sha512-8cErJEDzhZgNKzYyjCKsHuyPqtWxG8gc9h4OFSUDJu0vCAOsObPU2LcECnW0kJwh/b+uUz46lObVzIXw0fzAbA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-remap-async-to-generator": "^7.13.0",
- "@babel/plugin-syntax-async-generators": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-class-properties": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz",
- "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==",
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-proposal-decorators": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.12.1.tgz",
- "integrity": "sha512-knNIuusychgYN8fGJHONL0RbFxLGawhXOJNLBk75TniTsZZeA+wdkDuv6wp4lGwzQEKjZi6/WYtnb3udNPmQmQ==",
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.12.1",
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-decorators": "^7.12.1"
- }
- },
- "@babel/plugin-proposal-dynamic-import": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.17.tgz",
- "integrity": "sha512-ZNGoFZqrnuy9H2izB2jLlnNDAfVPlGl5NhFEiFe4D84ix9GQGygF+CWMGHKuE+bpyS/AOuDQCnkiRNqW2IzS1Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-dynamic-import": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-export-default-from": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.16.7.tgz",
- "integrity": "sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-export-default-from": "^7.16.7"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
- "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
- "dev": true
- }
- }
- },
- "@babel/plugin-proposal-export-namespace-from": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz",
- "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
- }
- },
- "@babel/plugin-proposal-json-strings": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.13.tgz",
- "integrity": "sha512-v9eEi4GiORDg8x+Dmi5r8ibOe0VXoKDeNPYcTTxdGN4eOWikrJfDJCJrr1l5gKGvsNyGJbrfMftC2dTL6oz7pg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-json-strings": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-logical-assignment-operators": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.13.tgz",
- "integrity": "sha512-fqmiD3Lz7jVdK6kabeSr1PZlWSUVqSitmHEe3Z00dtGTKieWnX9beafvavc32kjORa5Bai4QNHgFDwWJP+WtSQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-nullish-coalescing-operator": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.0.tgz",
- "integrity": "sha512-UkAvFA/9+lBBL015gjA68NvKiCReNxqFLm3SdNKaM3XXoDisA7tMAIX4PmIwatFoFqMxxT3WyG9sK3MO0Kting==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-numeric-separator": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz",
- "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-object-rest-spread": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.0.tgz",
- "integrity": "sha512-B4qphdSTp0nLsWcuei07JPKeZej4+Hd22MdnulJXQa1nCcGSBlk8FiqenGERaPZ+PuYhz4Li2Wjc8yfJvHgUMw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
- "@babel/plugin-transform-parameters": "^7.13.0"
- }
- },
- "@babel/plugin-proposal-optional-catch-binding": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.13.tgz",
- "integrity": "sha512-9+MIm6msl9sHWg58NvqpNpLtuFbmpFYk37x8kgnGzAHvX35E1FyAwSUt5hIkSoWJFSAH+iwU8bJ4fcD1zKXOzg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-optional-chaining": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.0.tgz",
- "integrity": "sha512-OVRQOZEBP2luZrvEbNSX5FfWDousthhdEoAOpej+Tpe58HFLvqRClT89RauIvBuCDFEip7GW1eT86/5lMy2RNA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1",
- "@babel/plugin-syntax-optional-chaining": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-private-methods": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz",
- "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==",
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-proposal-unicode-property-regex": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz",
- "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==",
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-async-generators": {
- "version": "7.8.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
- "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-bigint": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
- "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-class-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
- "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-decorators": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.14.5.tgz",
- "integrity": "sha512-c4sZMRWL4GSvP1EXy0woIP7m4jkVcEuG8R1TOZxPBPtp4FSM/kiPZub9UIs/Jrb5ZAOzvTUSGYrWsrSu1JvoPw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-syntax-dynamic-import": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
- "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-export-default-from": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.16.7.tgz",
- "integrity": "sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
- "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
- "dev": true
- }
- }
- },
- "@babel/plugin-syntax-export-namespace-from": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
- "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.3"
- }
- },
- "@babel/plugin-syntax-flow": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.14.5.tgz",
- "integrity": "sha512-9WK5ZwKCdWHxVuU13XNT6X73FGmutAXeor5lGFq6qhOFtMFUF4jkbijuyUdZZlpYq6E2hZeZf/u3959X9wsv0Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-syntax-import-meta": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
- "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-json-strings": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
- "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.13.tgz",
- "integrity": "sha512-d4HM23Q1K7oq/SLNmG6mRt85l2csmQ0cHRaxRXjKW0YFdEXqlZ5kzFQKH5Uc3rDJECgu+yCRgPkG04Mm98R/1g==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-logical-assignment-operators": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
- "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-nullish-coalescing-operator": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
- "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-numeric-separator": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
- "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-syntax-object-rest-spread": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
- "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-optional-catch-binding": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
- "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-optional-chaining": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
- "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.8.0"
- }
- },
- "@babel/plugin-syntax-top-level-await": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz",
- "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-syntax-typescript": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz",
- "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-transform-arrow-functions": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz",
- "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-async-to-generator": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz",
- "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==",
- "requires": {
- "@babel/helper-module-imports": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-remap-async-to-generator": "^7.13.0"
- }
- },
- "@babel/plugin-transform-block-scoped-functions": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz",
- "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-block-scoping": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz",
- "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-classes": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz",
- "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-optimise-call-expression": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-replace-supers": "^7.13.0",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "globals": "^11.1.0"
- }
- },
- "@babel/plugin-transform-computed-properties": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz",
- "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-destructuring": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz",
- "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-dotall-regex": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz",
- "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==",
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-duplicate-keys": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz",
- "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-exponentiation-operator": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz",
- "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==",
- "requires": {
- "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-flow-strip-types": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.12.1.tgz",
- "integrity": "sha512-8hAtkmsQb36yMmEtk2JZ9JnVyDSnDOdlB+0nEGzIDLuK4yR3JcEjfuFPYkdEPSh8Id+rAMeBEn+X0iVEyho6Hg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-flow": "^7.12.1"
- }
- },
- "@babel/plugin-transform-for-of": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz",
- "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-function-name": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz",
- "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==",
- "requires": {
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-literals": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz",
- "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-member-expression-literals": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz",
- "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-modules-amd": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz",
- "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==",
- "requires": {
- "@babel/helper-module-transforms": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0",
- "babel-plugin-dynamic-import-node": "^2.3.3"
- }
- },
- "@babel/plugin-transform-modules-commonjs": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.0.tgz",
- "integrity": "sha512-j7397PkIB4lcn25U2dClK6VLC6pr2s3q+wbE8R3vJvY6U1UTBBj0n6F+5v6+Fd/UwfDPAorMOs2TV+T4M+owpQ==",
- "requires": {
- "@babel/helper-module-transforms": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-simple-access": "^7.12.13",
- "babel-plugin-dynamic-import-node": "^2.3.3"
- }
- },
- "@babel/plugin-transform-modules-systemjs": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.13.tgz",
- "integrity": "sha512-aHfVjhZ8QekaNF/5aNdStCGzwTbU7SI5hUybBKlMzqIMC7w7Ho8hx5a4R/DkTHfRfLwHGGxSpFt9BfxKCoXKoA==",
- "requires": {
- "@babel/helper-hoist-variables": "^7.12.13",
- "@babel/helper-module-transforms": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/helper-validator-identifier": "^7.12.11",
- "babel-plugin-dynamic-import-node": "^2.3.3"
- }
- },
- "@babel/plugin-transform-modules-umd": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz",
- "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==",
- "requires": {
- "@babel/helper-module-transforms": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-named-capturing-groups-regex": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz",
- "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==",
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.12.13"
- }
- },
- "@babel/plugin-transform-new-target": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz",
- "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-object-super": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz",
- "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/helper-replace-supers": "^7.12.13"
- }
- },
- "@babel/plugin-transform-parameters": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz",
- "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-property-literals": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz",
- "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-react-constant-elements": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.14.5.tgz",
- "integrity": "sha512-NBqLEx1GxllIOXJInJAQbrnwwYJsV3WaMHIcOwD8rhYS0AabTWn7kHdHgPgu5RmHLU0q4DMxhAMu8ue/KampgQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-transform-react-display-name": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.13.tgz",
- "integrity": "sha512-MprESJzI9O5VnJZrL7gg1MpdqmiFcUv41Jc7SahxYsNP2kDkFqClxxTZq+1Qv4AFCamm+GXMRDQINNn+qrxmiA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-react-jsx": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.12.17.tgz",
- "integrity": "sha512-mwaVNcXV+l6qJOuRhpdTEj8sT/Z0owAVWf9QujTZ0d2ye9X/K+MTOTSizcgKOj18PGnTc/7g1I4+cIUjsKhBcw==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.12.13",
- "@babel/helper-module-imports": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-syntax-jsx": "^7.12.13",
- "@babel/types": "^7.12.17"
- }
- },
- "@babel/plugin-transform-react-jsx-development": {
- "version": "7.12.17",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.12.17.tgz",
- "integrity": "sha512-BPjYV86SVuOaudFhsJR1zjgxxOhJDt6JHNoD48DxWEIxUCAMjV1ys6DYw4SDYZh0b1QsS2vfIA9t/ZsQGsDOUQ==",
- "requires": {
- "@babel/plugin-transform-react-jsx": "^7.12.17"
- }
- },
- "@babel/plugin-transform-react-jsx-self": {
- "version": "7.14.9",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.14.9.tgz",
- "integrity": "sha512-Fqqu0f8zv9W+RyOnx29BX/RlEsBRANbOf5xs5oxb2aHP4FKbLXxIaVPUiCti56LAR1IixMH4EyaixhUsKqoBHw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-transform-react-jsx-source": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.14.5.tgz",
- "integrity": "sha512-1TpSDnD9XR/rQ2tzunBVPThF5poaYT9GqP+of8fAtguYuI/dm2RkrMBDemsxtY0XBzvW7nXjYM0hRyKX9QYj7Q==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.14.5"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- }
- }
- },
- "@babel/plugin-transform-react-pure-annotations": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.12.1.tgz",
- "integrity": "sha512-RqeaHiwZtphSIUZ5I85PEH19LOSzxfuEazoY7/pWASCAIBuATQzpSVD+eT6MebeeZT2F4eSL0u4vw6n4Nm0Mjg==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.10.4",
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-transform-regenerator": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.13.tgz",
- "integrity": "sha512-lxb2ZAvSLyJ2PEe47hoGWPmW22v7CtSl9jW8mingV4H2sEX/JOcrAj2nPuGWi56ERUm2bUpjKzONAuT6HCn2EA==",
- "requires": {
- "regenerator-transform": "^0.14.2"
- }
- },
- "@babel/plugin-transform-reserved-words": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz",
- "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-runtime": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.1.tgz",
- "integrity": "sha512-Ac/H6G9FEIkS2tXsZjL4RAdS3L3WHxci0usAnz7laPWUmFiGtj7tIASChqKZMHTSQTQY6xDbOq+V1/vIq3QrWg==",
- "requires": {
- "@babel/helper-module-imports": "^7.12.1",
- "@babel/helper-plugin-utils": "^7.10.4",
- "resolve": "^1.8.1",
- "semver": "^5.5.1"
- }
- },
- "@babel/plugin-transform-shorthand-properties": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz",
- "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-spread": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz",
- "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1"
- }
- },
- "@babel/plugin-transform-sticky-regex": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz",
- "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-template-literals": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz",
- "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.13.0"
- }
- },
- "@babel/plugin-transform-typeof-symbol": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz",
- "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-typescript": {
- "version": "7.15.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.8.tgz",
- "integrity": "sha512-ZXIkJpbaf6/EsmjeTbiJN/yMxWPFWvlr7sEG1P95Xb4S4IBcrf2n7s/fItIhsAmOf8oSh3VJPDppO6ExfAfKRQ==",
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.15.4",
- "@babel/helper-plugin-utils": "^7.14.5",
- "@babel/plugin-syntax-typescript": "^7.14.5"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.15.8",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
- "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
- "requires": {
- "@babel/highlight": "^7.14.5"
- }
- },
- "@babel/generator": {
- "version": "7.15.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz",
- "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==",
- "requires": {
- "@babel/types": "^7.15.6",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz",
- "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-create-class-features-plugin": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz",
- "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.15.4",
- "@babel/helper-function-name": "^7.15.4",
- "@babel/helper-member-expression-to-functions": "^7.15.4",
- "@babel/helper-optimise-call-expression": "^7.15.4",
- "@babel/helper-replace-supers": "^7.15.4",
- "@babel/helper-split-export-declaration": "^7.15.4"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz",
- "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==",
- "requires": {
- "@babel/helper-get-function-arity": "^7.15.4",
- "@babel/template": "^7.15.4",
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz",
- "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz",
- "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz",
- "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz",
- "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz",
- "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ=="
- },
- "@babel/helper-replace-supers": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz",
- "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==",
- "requires": {
- "@babel/helper-member-expression-to-functions": "^7.15.4",
- "@babel/helper-optimise-call-expression": "^7.15.4",
- "@babel/traverse": "^7.15.4",
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz",
- "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==",
- "requires": {
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.15.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
- "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w=="
- },
- "@babel/highlight": {
- "version": "7.14.5",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
- "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.5",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.15.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz",
- "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA=="
- },
- "@babel/template": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz",
- "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==",
- "requires": {
- "@babel/code-frame": "^7.14.5",
- "@babel/parser": "^7.15.4",
- "@babel/types": "^7.15.4"
- }
- },
- "@babel/traverse": {
- "version": "7.15.4",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz",
- "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==",
- "requires": {
- "@babel/code-frame": "^7.14.5",
- "@babel/generator": "^7.15.4",
- "@babel/helper-function-name": "^7.15.4",
- "@babel/helper-hoist-variables": "^7.15.4",
- "@babel/helper-split-export-declaration": "^7.15.4",
- "@babel/parser": "^7.15.4",
- "@babel/types": "^7.15.4",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.15.6",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz",
- "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.14.9",
- "to-fast-properties": "^2.0.0"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- },
- "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"
- }
- }
- }
- },
- "@babel/plugin-transform-unicode-escapes": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz",
- "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/plugin-transform-unicode-regex": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz",
- "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==",
- "requires": {
- "@babel/helper-create-regexp-features-plugin": "^7.12.13",
- "@babel/helper-plugin-utils": "^7.12.13"
- }
- },
- "@babel/preset-env": {
- "version": "7.13.5",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.5.tgz",
- "integrity": "sha512-xUeKBIIcbwxGevyWMSWZOW98W1lp7toITvVsMxSddCEQy932yYiF4fCB+CG3E/MXzFX3KbefgvCqEQ7TDoE6UQ==",
- "requires": {
- "@babel/compat-data": "^7.13.5",
- "@babel/helper-compilation-targets": "^7.13.0",
- "@babel/helper-plugin-utils": "^7.13.0",
- "@babel/helper-validator-option": "^7.12.17",
- "@babel/plugin-proposal-async-generator-functions": "^7.13.5",
- "@babel/plugin-proposal-class-properties": "^7.13.0",
- "@babel/plugin-proposal-dynamic-import": "^7.12.17",
- "@babel/plugin-proposal-export-namespace-from": "^7.12.13",
- "@babel/plugin-proposal-json-strings": "^7.12.13",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.12.13",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.13.0",
- "@babel/plugin-proposal-numeric-separator": "^7.12.13",
- "@babel/plugin-proposal-object-rest-spread": "^7.13.0",
- "@babel/plugin-proposal-optional-catch-binding": "^7.12.13",
- "@babel/plugin-proposal-optional-chaining": "^7.13.0",
- "@babel/plugin-proposal-private-methods": "^7.13.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.12.13",
- "@babel/plugin-syntax-async-generators": "^7.8.0",
- "@babel/plugin-syntax-class-properties": "^7.12.13",
- "@babel/plugin-syntax-dynamic-import": "^7.8.0",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
- "@babel/plugin-syntax-json-strings": "^7.8.0",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
- "@babel/plugin-syntax-optional-chaining": "^7.8.0",
- "@babel/plugin-syntax-top-level-await": "^7.12.13",
- "@babel/plugin-transform-arrow-functions": "^7.13.0",
- "@babel/plugin-transform-async-to-generator": "^7.13.0",
- "@babel/plugin-transform-block-scoped-functions": "^7.12.13",
- "@babel/plugin-transform-block-scoping": "^7.12.13",
- "@babel/plugin-transform-classes": "^7.13.0",
- "@babel/plugin-transform-computed-properties": "^7.13.0",
- "@babel/plugin-transform-destructuring": "^7.13.0",
- "@babel/plugin-transform-dotall-regex": "^7.12.13",
- "@babel/plugin-transform-duplicate-keys": "^7.12.13",
- "@babel/plugin-transform-exponentiation-operator": "^7.12.13",
- "@babel/plugin-transform-for-of": "^7.13.0",
- "@babel/plugin-transform-function-name": "^7.12.13",
- "@babel/plugin-transform-literals": "^7.12.13",
- "@babel/plugin-transform-member-expression-literals": "^7.12.13",
- "@babel/plugin-transform-modules-amd": "^7.13.0",
- "@babel/plugin-transform-modules-commonjs": "^7.13.0",
- "@babel/plugin-transform-modules-systemjs": "^7.12.13",
- "@babel/plugin-transform-modules-umd": "^7.13.0",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.13",
- "@babel/plugin-transform-new-target": "^7.12.13",
- "@babel/plugin-transform-object-super": "^7.12.13",
- "@babel/plugin-transform-parameters": "^7.13.0",
- "@babel/plugin-transform-property-literals": "^7.12.13",
- "@babel/plugin-transform-regenerator": "^7.12.13",
- "@babel/plugin-transform-reserved-words": "^7.12.13",
- "@babel/plugin-transform-shorthand-properties": "^7.12.13",
- "@babel/plugin-transform-spread": "^7.13.0",
- "@babel/plugin-transform-sticky-regex": "^7.12.13",
- "@babel/plugin-transform-template-literals": "^7.13.0",
- "@babel/plugin-transform-typeof-symbol": "^7.12.13",
- "@babel/plugin-transform-unicode-escapes": "^7.12.13",
- "@babel/plugin-transform-unicode-regex": "^7.12.13",
- "@babel/preset-modules": "^0.1.3",
- "@babel/types": "^7.13.0",
- "babel-plugin-polyfill-corejs2": "^0.1.4",
- "babel-plugin-polyfill-corejs3": "^0.1.3",
- "babel-plugin-polyfill-regenerator": "^0.1.2",
- "core-js-compat": "^3.9.0",
- "semver": "7.0.0"
- },
- "dependencies": {
- "semver": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
- "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
- }
- }
- },
- "@babel/preset-flow": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.16.7.tgz",
- "integrity": "sha512-6ceP7IyZdUYQ3wUVqyRSQXztd1YmFHWI4Xv11MIqAlE4WqxBSd/FZ61V9k+TS5Gd4mkHOtQtPp9ymRpxH4y1Ug==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/helper-validator-option": "^7.16.7",
- "@babel/plugin-transform-flow-strip-types": "^7.16.7"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
- "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/plugin-syntax-flow": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz",
- "integrity": "sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- }
- },
- "@babel/plugin-transform-flow-strip-types": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz",
- "integrity": "sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-flow": "^7.16.7"
- }
- }
- }
- },
- "@babel/preset-modules": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz",
- "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
- "@babel/plugin-transform-dotall-regex": "^7.4.4",
- "@babel/types": "^7.4.4",
- "esutils": "^2.0.2"
- }
- },
- "@babel/preset-react": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.13.tgz",
- "integrity": "sha512-TYM0V9z6Abb6dj1K7i5NrEhA13oS5ujUYQYDfqIBXYHOc2c2VkFgc+q9kyssIyUfy4/hEwqrgSlJ/Qgv8zJLsA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.12.13",
- "@babel/plugin-transform-react-display-name": "^7.12.13",
- "@babel/plugin-transform-react-jsx": "^7.12.13",
- "@babel/plugin-transform-react-jsx-development": "^7.12.12",
- "@babel/plugin-transform-react-pure-annotations": "^7.12.1"
- }
- },
- "@babel/preset-typescript": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.12.1.tgz",
- "integrity": "sha512-hNK/DhmoJPsksdHuI/RVrcEws7GN5eamhi28JkO52MqIxU8Z0QpmiSOQxZHWOHV7I3P4UjHV97ay4TcamMA6Kw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-transform-typescript": "^7.12.1"
- }
- },
- "@babel/register": {
- "version": "7.16.9",
- "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.16.9.tgz",
- "integrity": "sha512-jJ72wcghdRIlENfvALcyODhNoGE5j75cYHdC+aQMh6cU/P86tiiXTp9XYZct1UxUMo/4+BgQRyNZEGx0KWGS+g==",
- "dev": true,
- "requires": {
- "clone-deep": "^4.0.1",
- "find-cache-dir": "^2.0.0",
- "make-dir": "^2.1.0",
- "pirates": "^4.0.0",
- "source-map-support": "^0.5.16"
- }
- },
- "@babel/runtime": {
- "version": "7.13.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.7.tgz",
- "integrity": "sha512-h+ilqoX998mRVM5FtB5ijRuHUDVt5l3yfoOi2uh18Z/O3hvyaHQ39NpxVkCIG5yFs+mLq/ewFp8Bss6zmWv6ZA==",
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@babel/runtime-corejs3": {
- "version": "7.13.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.7.tgz",
- "integrity": "sha512-zkDsGGSRU2YyYTXkPfcxuYuCVc6xBOeH1ZMh72ywBvmrDs+kSmoMuCUXZJUPbXZafrPivDHS2Oq7wI37gaTvqw==",
- "requires": {
- "core-js-pure": "^3.0.0",
- "regenerator-runtime": "^0.13.4"
- }
- },
- "@babel/template": {
- "version": "7.12.13",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz",
- "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==",
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@babel/parser": "^7.12.13",
- "@babel/types": "^7.12.13"
- }
- },
- "@babel/traverse": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.0.tgz",
- "integrity": "sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==",
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@babel/generator": "^7.13.0",
- "@babel/helper-function-name": "^7.12.13",
- "@babel/helper-split-export-declaration": "^7.12.13",
- "@babel/parser": "^7.13.0",
- "@babel/types": "^7.13.0",
- "debug": "^4.1.0",
- "globals": "^11.1.0",
- "lodash": "^4.17.19"
- }
- },
- "@babel/types": {
- "version": "7.13.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.0.tgz",
- "integrity": "sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==",
- "requires": {
- "@babel/helper-validator-identifier": "^7.12.11",
- "lodash": "^4.17.19",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@base2/pretty-print-object": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@base2/pretty-print-object/-/pretty-print-object-1.0.1.tgz",
- "integrity": "sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==",
- "dev": true
- },
- "@bcoe/v8-coverage": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
- "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="
- },
- "@cnakazawa/watch": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz",
- "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==",
- "requires": {
- "exec-sh": "^0.3.2",
- "minimist": "^1.2.0"
- }
- },
- "@csstools/convert-colors": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
- "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
- },
- "@csstools/normalize.css": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
- "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
- },
- "@cypress/request": {
- "version": "2.88.6",
- "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz",
- "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==",
- "dev": true,
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^8.3.2"
- }
- },
- "@cypress/xvfb": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
- "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==",
- "dev": true,
- "requires": {
- "debug": "^3.1.0",
- "lodash.once": "^4.1.1"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "@discoveryjs/json-ext": {
- "version": "0.5.6",
- "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz",
- "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==",
- "dev": true
- },
- "@emotion/cache": {
- "version": "10.0.29",
- "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz",
- "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==",
- "dev": true,
- "requires": {
- "@emotion/sheet": "0.9.4",
- "@emotion/stylis": "0.8.5",
- "@emotion/utils": "0.11.3",
- "@emotion/weak-memoize": "0.2.5"
- }
- },
- "@emotion/core": {
- "version": "10.3.1",
- "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz",
- "integrity": "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "@emotion/cache": "^10.0.27",
- "@emotion/css": "^10.0.27",
- "@emotion/serialize": "^0.11.15",
- "@emotion/sheet": "0.9.4",
- "@emotion/utils": "0.11.3"
- }
- },
- "@emotion/css": {
- "version": "10.0.27",
- "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz",
- "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==",
- "dev": true,
- "requires": {
- "@emotion/serialize": "^0.11.15",
- "@emotion/utils": "0.11.3",
- "babel-plugin-emotion": "^10.0.27"
- }
- },
- "@emotion/hash": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
- "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
- },
- "@emotion/is-prop-valid": {
- "version": "0.8.8",
- "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
- "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
- "requires": {
- "@emotion/memoize": "0.7.4"
- }
- },
- "@emotion/memoize": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
- "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw=="
- },
- "@emotion/react": {
- "version": "11.1.5",
- "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.1.5.tgz",
- "integrity": "sha512-xfnZ9NJEv9SU9K2sxXM06lzjK245xSeHRpUh67eARBm3PBHjjKIZlfWZ7UQvD0Obvw6ZKjlC79uHrlzFYpOB/Q==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "@emotion/cache": "^11.1.3",
- "@emotion/serialize": "^1.0.0",
- "@emotion/sheet": "^1.0.1",
- "@emotion/utils": "^1.0.0",
- "@emotion/weak-memoize": "^0.2.5",
- "hoist-non-react-statics": "^3.3.1"
- },
- "dependencies": {
- "@emotion/cache": {
- "version": "11.1.3",
- "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
- "integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
- "requires": {
- "@emotion/memoize": "^0.7.4",
- "@emotion/sheet": "^1.0.0",
- "@emotion/utils": "^1.0.0",
- "@emotion/weak-memoize": "^0.2.5",
- "stylis": "^4.0.3"
- }
- },
- "@emotion/serialize": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.1.tgz",
- "integrity": "sha512-TXlKs5sgUKhFlszp/rg4lIAZd7UUSmJpwaf9/lAEFcUh2vPi32i7x4wk7O8TN8L8v2Ol8k0CxnhRBY0zQalTxA==",
- "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.0.1",
- "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
- "integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
- },
- "@emotion/utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
- "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
- },
- "csstype": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
- "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
- }
- }
- },
- "@emotion/serialize": {
- "version": "0.11.16",
- "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz",
- "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==",
- "dev": true,
- "requires": {
- "@emotion/hash": "0.8.0",
- "@emotion/memoize": "0.7.4",
- "@emotion/unitless": "0.7.5",
- "@emotion/utils": "0.11.3",
- "csstype": "^2.5.7"
- }
- },
- "@emotion/sheet": {
- "version": "0.9.4",
- "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz",
- "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==",
- "dev": true
- },
- "@emotion/styled": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz",
- "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==",
- "dev": true,
- "requires": {
- "@emotion/styled-base": "^10.3.0",
- "babel-plugin-emotion": "^10.0.27"
- }
- },
- "@emotion/styled-base": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz",
- "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "@emotion/is-prop-valid": "0.8.8",
- "@emotion/serialize": "^0.11.15",
- "@emotion/utils": "0.11.3"
- }
- },
- "@emotion/stylis": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz",
- "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==",
- "dev": true
- },
- "@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": "0.11.3",
- "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz",
- "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==",
- "dev": true
- },
- "@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=="
- },
- "@eslint/eslintrc": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
- "integrity": "sha512-1JTKgrOKAHVivSvOYw+sJOunkBjUOvjqWk1DPja7ZFhIS2mX/4EgTT8M7eTK9jrKhL/FvXXEbQwIs3pg1xp3dg==",
- "requires": {
- "ajv": "^6.12.4",
- "debug": "^4.1.1",
- "espree": "^7.3.0",
- "globals": "^12.1.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.2.1",
- "js-yaml": "^3.13.1",
- "lodash": "^4.17.20",
- "minimatch": "^3.0.4",
- "strip-json-comments": "^3.1.1"
- },
- "dependencies": {
- "globals": {
- "version": "12.4.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
- "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
- "requires": {
- "type-fest": "^0.8.1"
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
- }
- }
- },
- "@googlemaps/js-api-loader": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/@googlemaps/js-api-loader/-/js-api-loader-1.11.1.tgz",
- "integrity": "sha512-2ug4uBu0onRXTAo7Yxkay5N7pdNIz3XpTElMTLdCtEfQDxikbjeR6GS8atVhblX+ubFBNlXvDzz7VtuXv0vMRQ==",
- "requires": {
- "fast-deep-equal": "^3.1.3"
- }
- },
- "@googlemaps/markerclustererplus": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@googlemaps/markerclustererplus/-/markerclustererplus-1.1.0.tgz",
- "integrity": "sha512-Y5jiaoMzhUQ8tCyJzvV5/+6VYF154eeczPZKqQ6kdINoL6Jui4DzVPNPitWFjXmPL9UDkBoxu0PLxOQQGvNWug=="
- },
- "@hapi/address": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz",
- "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ=="
- },
- "@hapi/bourne": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz",
- "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA=="
- },
- "@hapi/hoek": {
- "version": "8.5.1",
- "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz",
- "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow=="
- },
- "@hapi/joi": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz",
- "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==",
- "requires": {
- "@hapi/address": "2.x.x",
- "@hapi/bourne": "1.x.x",
- "@hapi/hoek": "8.x.x",
- "@hapi/topo": "3.x.x"
- }
- },
- "@hapi/topo": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz",
- "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==",
- "requires": {
- "@hapi/hoek": "^8.3.0"
- }
- },
- "@istanbuljs/load-nyc-config": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
- "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
- "requires": {
- "camelcase": "^5.3.1",
- "find-up": "^4.1.0",
- "get-package-type": "^0.1.0",
- "js-yaml": "^3.13.1",
- "resolve-from": "^5.0.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
- }
- }
- },
- "@istanbuljs/schema": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
- "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="
- },
- "@jest/console": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz",
- "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==",
- "requires": {
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^26.6.2",
- "jest-util": "^26.6.2",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "@jest/core": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz",
- "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==",
- "requires": {
- "@jest/console": "^26.6.2",
- "@jest/reporters": "^26.6.2",
- "@jest/test-result": "^26.6.2",
- "@jest/transform": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.4",
- "jest-changed-files": "^26.6.2",
- "jest-config": "^26.6.3",
- "jest-haste-map": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-regex-util": "^26.0.0",
- "jest-resolve": "^26.6.2",
- "jest-resolve-dependencies": "^26.6.3",
- "jest-runner": "^26.6.3",
- "jest-runtime": "^26.6.3",
- "jest-snapshot": "^26.6.2",
- "jest-util": "^26.6.2",
- "jest-validate": "^26.6.2",
- "jest-watcher": "^26.6.2",
- "micromatch": "^4.0.2",
- "p-each-series": "^2.1.0",
- "rimraf": "^3.0.0",
- "slash": "^3.0.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "@jest/environment": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz",
- "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==",
- "requires": {
- "@jest/fake-timers": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "jest-mock": "^26.6.2"
- }
- },
- "@jest/fake-timers": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz",
- "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==",
- "requires": {
- "@jest/types": "^26.6.2",
- "@sinonjs/fake-timers": "^6.0.1",
- "@types/node": "*",
- "jest-message-util": "^26.6.2",
- "jest-mock": "^26.6.2",
- "jest-util": "^26.6.2"
- }
- },
- "@jest/globals": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz",
- "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==",
- "requires": {
- "@jest/environment": "^26.6.2",
- "@jest/types": "^26.6.2",
- "expect": "^26.6.2"
- }
- },
- "@jest/reporters": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz",
- "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==",
- "requires": {
- "@bcoe/v8-coverage": "^0.2.3",
- "@jest/console": "^26.6.2",
- "@jest/test-result": "^26.6.2",
- "@jest/transform": "^26.6.2",
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.2",
- "graceful-fs": "^4.2.4",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-instrument": "^4.0.3",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-lib-source-maps": "^4.0.0",
- "istanbul-reports": "^3.0.2",
- "jest-haste-map": "^26.6.2",
- "jest-resolve": "^26.6.2",
- "jest-util": "^26.6.2",
- "jest-worker": "^26.6.2",
- "node-notifier": "^8.0.0",
- "slash": "^3.0.0",
- "source-map": "^0.6.0",
- "string-length": "^4.0.1",
- "terminal-link": "^2.0.0",
- "v8-to-istanbul": "^7.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- }
- }
- },
- "@jest/source-map": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz",
- "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==",
- "requires": {
- "callsites": "^3.0.0",
- "graceful-fs": "^4.2.4",
- "source-map": "^0.6.0"
- }
- },
- "@jest/test-result": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz",
- "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==",
- "requires": {
- "@jest/console": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
- }
- },
- "@jest/test-sequencer": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz",
- "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==",
- "requires": {
- "@jest/test-result": "^26.6.2",
- "graceful-fs": "^4.2.4",
- "jest-haste-map": "^26.6.2",
- "jest-runner": "^26.6.3",
- "jest-runtime": "^26.6.3"
- }
- },
- "@jest/transform": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz",
- "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==",
- "requires": {
- "@babel/core": "^7.1.0",
- "@jest/types": "^26.6.2",
- "babel-plugin-istanbul": "^6.0.0",
- "chalk": "^4.0.0",
- "convert-source-map": "^1.4.0",
- "fast-json-stable-stringify": "^2.0.0",
- "graceful-fs": "^4.2.4",
- "jest-haste-map": "^26.6.2",
- "jest-regex-util": "^26.0.0",
- "jest-util": "^26.6.2",
- "micromatch": "^4.0.2",
- "pirates": "^4.0.1",
- "slash": "^3.0.0",
- "source-map": "^0.6.1",
- "write-file-atomic": "^3.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "@jest/types": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz",
- "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==",
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^15.0.0",
- "chalk": "^4.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "@mapbox/point-geometry": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
- "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI="
- },
- "@material-ui/core": {
- "version": "4.11.3",
- "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.3.tgz",
- "integrity": "sha512-Adt40rGW6Uds+cAyk3pVgcErpzU/qxc7KBR94jFHBYretU4AtWZltYcNsbeMn9tXL86jjVL1kuGcIHsgLgFGRw==",
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/styles": "^4.11.3",
- "@material-ui/system": "^4.11.3",
- "@material-ui/types": "^5.1.0",
- "@material-ui/utils": "^4.11.2",
- "@types/react-transition-group": "^4.2.0",
- "clsx": "^1.0.4",
- "hoist-non-react-statics": "^3.3.2",
- "popper.js": "1.16.1-lts",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0",
- "react-transition-group": "^4.4.0"
- }
- },
- "@material-ui/icons": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz",
- "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==",
- "requires": {
- "@babel/runtime": "^7.4.4"
- }
- },
- "@material-ui/styles": {
- "version": "4.11.3",
- "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.3.tgz",
- "integrity": "sha512-HzVzCG+PpgUGMUYEJ2rTEmQYeonGh41BYfILNFb/1ueqma+p1meSdu4RX6NjxYBMhf7k+jgfHFTTz+L1SXL/Zg==",
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@emotion/hash": "^0.8.0",
- "@material-ui/types": "^5.1.0",
- "@material-ui/utils": "^4.11.2",
- "clsx": "^1.0.4",
- "csstype": "^2.5.2",
- "hoist-non-react-statics": "^3.3.2",
- "jss": "^10.5.1",
- "jss-plugin-camel-case": "^10.5.1",
- "jss-plugin-default-unit": "^10.5.1",
- "jss-plugin-global": "^10.5.1",
- "jss-plugin-nested": "^10.5.1",
- "jss-plugin-props-sort": "^10.5.1",
- "jss-plugin-rule-value-function": "^10.5.1",
- "jss-plugin-vendor-prefixer": "^10.5.1",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/system": {
- "version": "4.11.3",
- "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.3.tgz",
- "integrity": "sha512-SY7otguNGol41Mu2Sg6KbBP1ZRFIbFLHGK81y4KYbsV2yIcaEPOmsCK6zwWlp+2yTV3J/VwT6oSBARtGIVdXPw==",
- "requires": {
- "@babel/runtime": "^7.4.4",
- "@material-ui/utils": "^4.11.2",
- "csstype": "^2.5.2",
- "prop-types": "^15.7.2"
- }
- },
- "@material-ui/types": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz",
- "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A=="
- },
- "@material-ui/utils": {
- "version": "4.11.2",
- "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz",
- "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==",
- "requires": {
- "@babel/runtime": "^7.4.4",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.0 || ^17.0.0"
- }
- },
- "@mdx-js/loader": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/@mdx-js/loader/-/loader-1.6.22.tgz",
- "integrity": "sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==",
- "dev": true,
- "requires": {
- "@mdx-js/mdx": "1.6.22",
- "@mdx-js/react": "1.6.22",
- "loader-utils": "2.0.0"
- }
- },
- "@mdx-js/mdx": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz",
- "integrity": "sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==",
- "dev": true,
- "requires": {
- "@babel/core": "7.12.9",
- "@babel/plugin-syntax-jsx": "7.12.1",
- "@babel/plugin-syntax-object-rest-spread": "7.8.3",
- "@mdx-js/util": "1.6.22",
- "babel-plugin-apply-mdx-type-prop": "1.6.22",
- "babel-plugin-extract-import-names": "1.6.22",
- "camelcase-css": "2.0.1",
- "detab": "2.0.4",
- "hast-util-raw": "6.0.1",
- "lodash.uniq": "4.5.0",
- "mdast-util-to-hast": "10.0.1",
- "remark-footnotes": "2.0.0",
- "remark-mdx": "1.6.22",
- "remark-parse": "8.0.3",
- "remark-squeeze-paragraphs": "4.0.0",
- "style-to-object": "0.3.0",
- "unified": "9.2.0",
- "unist-builder": "2.0.3",
- "unist-util-visit": "2.0.3"
- },
- "dependencies": {
- "@babel/core": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
- "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
- "@babel/helper-module-transforms": "^7.12.1",
- "@babel/helpers": "^7.12.5",
- "@babel/parser": "^7.12.7",
- "@babel/template": "^7.12.7",
- "@babel/traverse": "^7.12.9",
- "@babel/types": "^7.12.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.1",
- "json5": "^2.1.2",
- "lodash": "^4.17.19",
- "resolve": "^1.3.2",
- "semver": "^5.4.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
- "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "remark-parse": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
- "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
- "dev": true,
- "requires": {
- "ccount": "^1.0.0",
- "collapse-white-space": "^1.0.2",
- "is-alphabetical": "^1.0.0",
- "is-decimal": "^1.0.0",
- "is-whitespace-character": "^1.0.0",
- "is-word-character": "^1.0.0",
- "markdown-escapes": "^1.0.0",
- "parse-entities": "^2.0.0",
- "repeat-string": "^1.5.4",
- "state-toggle": "^1.0.0",
- "trim": "0.0.1",
- "trim-trailing-lines": "^1.0.0",
- "unherit": "^1.0.4",
- "unist-util-remove-position": "^2.0.0",
- "vfile-location": "^3.0.0",
- "xtend": "^4.0.1"
- },
- "dependencies": {
- "trim": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim/-/trim-1.0.1.tgz",
- "integrity": "sha512-3JVP2YVqITUisXblCDq/Bi4P9457G/sdEamInkyvCsjbTcXLXIiG7XCb4kGMFWh6JGXesS3TKxOPtrncN/xe8w==",
- "dev": true
- }
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "trim": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim/-/trim-1.0.1.tgz",
- "integrity": "sha512-3JVP2YVqITUisXblCDq/Bi4P9457G/sdEamInkyvCsjbTcXLXIiG7XCb4kGMFWh6JGXesS3TKxOPtrncN/xe8w=="
- }
- }
- },
- "@mdx-js/react": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-1.6.22.tgz",
- "integrity": "sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==",
- "dev": true
- },
- "@mdx-js/util": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/@mdx-js/util/-/util-1.6.22.tgz",
- "integrity": "sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==",
- "dev": true
- },
- "@mrmlnc/readdir-enhanced": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
- "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
- "dev": true,
- "requires": {
- "call-me-maybe": "^1.0.1",
- "glob-to-regexp": "^0.3.0"
- }
- },
- "@nodelib/fs.scandir": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
- "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==",
- "requires": {
- "@nodelib/fs.stat": "2.0.4",
- "run-parallel": "^1.1.9"
- }
- },
- "@nodelib/fs.stat": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz",
- "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q=="
- },
- "@nodelib/fs.walk": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz",
- "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==",
- "requires": {
- "@nodelib/fs.scandir": "2.1.4",
- "fastq": "^1.6.0"
- }
- },
- "@npmcli/move-file": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
- "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
- "requires": {
- "mkdirp": "^1.0.4",
- "rimraf": "^3.0.2"
- },
- "dependencies": {
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
- }
- }
- },
- "@pmmmwh/react-refresh-webpack-plugin": {
- "version": "0.4.3",
- "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.4.3.tgz",
- "integrity": "sha512-br5Qwvh8D2OQqSXpd1g/xqXKnK0r+Jz6qVKBbWmpUcrbGOxUrf39V5oZ1876084CGn18uMdR5uvPqBv9UqtBjQ==",
- "requires": {
- "ansi-html": "^0.0.7",
- "error-stack-parser": "^2.0.6",
- "html-entities": "^1.2.1",
- "native-url": "^0.2.6",
- "schema-utils": "^2.6.5",
- "source-map": "^0.7.3"
- },
- "dependencies": {
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- }
- }
- },
- "@popperjs/core": {
- "version": "2.8.4",
- "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.8.4.tgz",
- "integrity": "sha512-h0lY7g36rhjNV8KVHKS3/BEOgfsxu0AiRI8+ry5IFBGEsQFkpjxtcpVc9ndN8zrKUeMZXAWMc7eQMepfgykpxQ=="
- },
- "@redux-saga/core": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
- "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
- "requires": {
- "@babel/runtime": "^7.6.3",
- "@redux-saga/deferred": "^1.1.2",
- "@redux-saga/delay-p": "^1.1.2",
- "@redux-saga/is": "^1.1.2",
- "@redux-saga/symbols": "^1.1.2",
- "@redux-saga/types": "^1.1.0",
- "redux": "^4.0.4",
- "typescript-tuple": "^2.2.1"
- }
- },
- "@redux-saga/deferred": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
- "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
- },
- "@redux-saga/delay-p": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
- "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
- "requires": {
- "@redux-saga/symbols": "^1.1.2"
- }
- },
- "@redux-saga/is": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
- "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
- "requires": {
- "@redux-saga/symbols": "^1.1.2",
- "@redux-saga/types": "^1.1.0"
- }
- },
- "@redux-saga/symbols": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
- "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
- },
- "@redux-saga/types": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
- "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
- },
- "@reduxjs/toolkit": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.6.0.tgz",
- "integrity": "sha512-eGL50G+Vj5AG5uD0lineb6rRtbs96M8+hxbcwkHpZ8LQcmt0Bm33WyBSnj5AweLkjQ7ZP+KFRDHiLMznljRQ3A==",
- "requires": {
- "immer": "^9.0.1",
- "redux": "^4.1.0",
- "redux-thunk": "^2.3.0",
- "reselect": "^4.0.0"
- },
- "dependencies": {
- "immer": {
- "version": "9.0.12",
- "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
- "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
- },
- "reselect": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
- "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
- }
- }
- },
- "@restart/context": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz",
- "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q=="
- },
- "@restart/hooks": {
- "version": "0.3.26",
- "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.26.tgz",
- "integrity": "sha512-7Hwk2ZMYm+JLWcb7R9qIXk1OoUg1Z+saKWqZXlrvFwT3w6UArVNWgxYOzf+PJoK9zZejp8okPAKTctthhXLt5g==",
- "requires": {
- "lodash": "^4.17.20",
- "lodash-es": "^4.17.20"
- }
- },
- "@rollup/plugin-node-resolve": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
- "integrity": "sha512-RxtSL3XmdTAE2byxekYLnx+98kEUOrPHF/KRVjLH+DEIHy6kjIw7YINQzn+NXiH/NTrQLAwYs0GWB+csWygA9Q==",
- "requires": {
- "@rollup/pluginutils": "^3.0.8",
- "@types/resolve": "0.0.8",
- "builtin-modules": "^3.1.0",
- "is-module": "^1.0.0",
- "resolve": "^1.14.2"
- }
- },
- "@rollup/plugin-replace": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz",
- "integrity": "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==",
- "requires": {
- "@rollup/pluginutils": "^3.1.0",
- "magic-string": "^0.25.7"
- }
- },
- "@rollup/pluginutils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
- "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
- "requires": {
- "@types/estree": "0.0.39",
- "estree-walker": "^1.0.1",
- "picomatch": "^2.2.2"
- },
- "dependencies": {
- "@types/estree": {
- "version": "0.0.39",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
- "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
- }
- }
- },
- "@sentry/browser": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-6.4.1.tgz",
- "integrity": "sha512-3cDud6GWutnJqcnheIq0lPNTsUJbrRLevQ+g1YfawVXFUxfmmY2bOsGd/Mxq17LxYeBHgKTitXv3DU1bsQ+WBQ==",
- "requires": {
- "@sentry/core": "6.4.1",
- "@sentry/types": "6.4.1",
- "@sentry/utils": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/core": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/core/-/core-6.4.1.tgz",
- "integrity": "sha512-Lx13oTiP+Tjvm5VxulcCszNVd2S1wY4viSnr+ygq62ySVERR+t7uOZDSARZ0rZ259GwW6nkbMh9dDmD0d6VCGQ==",
- "requires": {
- "@sentry/hub": "6.4.1",
- "@sentry/minimal": "6.4.1",
- "@sentry/types": "6.4.1",
- "@sentry/utils": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/hub": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-6.4.1.tgz",
- "integrity": "sha512-7IZRP5buDE6s/c3vWzzPR/ySE+8GUuHPgTEPiDCPOCWwUN11zXDafJDKkJqY3muJfebUKmC/JG67RyBx+XlnlQ==",
- "requires": {
- "@sentry/types": "6.4.1",
- "@sentry/utils": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/minimal": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-6.4.1.tgz",
- "integrity": "sha512-4x/PRbDZACCKJqjta9EkhiIMyGMf7VgBX13EEWEDVWLP7ymFukBuTr4ap/Tz9429kB/yXZuDGGMIZp/G618H3g==",
- "requires": {
- "@sentry/hub": "6.4.1",
- "@sentry/types": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/react": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/react/-/react-6.4.1.tgz",
- "integrity": "sha512-/rbp9jFgFc+m3DWhI58uKSLQxXtIW5bKqu5eVO/9jedhLzGRGBp0eOlJ5qtZ3KtYKSyPbA4uEBY5qI0rGwipeA==",
- "requires": {
- "@sentry/browser": "6.4.1",
- "@sentry/minimal": "6.4.1",
- "@sentry/types": "6.4.1",
- "@sentry/utils": "6.4.1",
- "hoist-non-react-statics": "^3.3.2",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/tracing": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-6.4.1.tgz",
- "integrity": "sha512-EPRadE9n/wpUjx4jqP/8vXdOAZBk7vjlzRKniJgKgQUO3v03i0ui6xydaal2mvhplIyOCI2muXdGhjUO7ga4uw==",
- "requires": {
- "@sentry/hub": "6.4.1",
- "@sentry/minimal": "6.4.1",
- "@sentry/types": "6.4.1",
- "@sentry/utils": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sentry/types": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/types/-/types-6.4.1.tgz",
- "integrity": "sha512-sTu/GaLsLYk1AkAqpkMT4+4q665LtZjhV0hkgiTD4N3zPl5uSf1pCIzxPRYjOpe7NEANmWv8U4PaGKGtc2eMfA=="
- },
- "@sentry/utils": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-6.4.1.tgz",
- "integrity": "sha512-xJ1uVa5fvg23pXQfulvCIBb9pQ3p1awyd1PapK2AYi+wKjTuYl4B9edmhjRREEQEExznl/d2OVm78fRXLq7M9Q==",
- "requires": {
- "@sentry/types": "6.4.1",
- "tslib": "^1.9.3"
- }
- },
- "@sinonjs/commons": {
- "version": "1.8.3",
- "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz",
- "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==",
- "requires": {
- "type-detect": "4.0.8"
- }
- },
- "@sinonjs/fake-timers": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
- "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
- "requires": {
- "@sinonjs/commons": "^1.7.0"
- }
- },
- "@storybook/addon-a11y": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-6.4.13.tgz",
- "integrity": "sha512-4N0YkNc5VPy4hb6pvYT3n6epFP1dM5wX1J+hCLcJgs9XIemVsuh/mtB0lKzNy5ZDXndQCmLuoW3jkFspKZVItA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/theming": "6.4.13",
- "axe-core": "^4.2.0",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "react-sizeme": "^3.0.1",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/addon-actions": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-6.4.13.tgz",
- "integrity": "sha512-Bf/M3Kdq60xj48oXnRCm7+qstWL9wT8rjFPFm7+A0NSfVSlox6pFU5SfPuOI4Za/6Ll2XDaYwsaF3QYHX0jQAA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "polished": "^4.0.5",
- "prop-types": "^15.7.2",
- "react-inspector": "^5.1.0",
- "regenerator-runtime": "^0.13.7",
- "telejson": "^5.3.2",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2",
- "uuid-browser": "^3.1.0"
- }
- },
- "@storybook/addon-backgrounds": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-backgrounds/-/addon-backgrounds-6.4.13.tgz",
- "integrity": "sha512-U+TowEgEHCWifdnaJE5P7kgRHjYrztwpjp/8tX4iXHlCVFBFid+v4EKqXQGbvTzX66g2Yfv/h68NGEpcFW/svQ==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "memoizerific": "^1.11.3",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/addon-controls": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-controls/-/addon-controls-6.4.13.tgz",
- "integrity": "sha512-XDaeYcwCi4qQ8hGXn4Mbdb6CQGGfZoBm5UjUaWBjDJdo54AyZv3VYdNgWFdiitqk5LRyh2omHD54EditM774NQ==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/node-logger": "6.4.13",
- "@storybook/store": "6.4.13",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "lodash": "^4.17.21",
- "ts-dedent": "^2.0.0"
- }
- },
- "@storybook/addon-docs": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-docs/-/addon-docs-6.4.13.tgz",
- "integrity": "sha512-frsHcZD3jabIXxYkenwigJhAiqmbeBztc1cUTMWSZ9kVDJN6h2msq/vD0LEotfjcvDe3XS2HZgBjdDJ1UUUj/g==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.10",
- "@babel/generator": "^7.12.11",
- "@babel/parser": "^7.12.11",
- "@babel/plugin-transform-react-jsx": "^7.12.12",
- "@babel/preset-env": "^7.12.11",
- "@jest/transform": "^26.6.2",
- "@mdx-js/loader": "^1.6.22",
- "@mdx-js/mdx": "^1.6.22",
- "@mdx-js/react": "^1.6.22",
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/builder-webpack4": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/csf-tools": "6.4.13",
- "@storybook/node-logger": "6.4.13",
- "@storybook/postinstall": "6.4.13",
- "@storybook/preview-web": "6.4.13",
- "@storybook/source-loader": "6.4.13",
- "@storybook/store": "6.4.13",
- "@storybook/theming": "6.4.13",
- "acorn": "^7.4.1",
- "acorn-jsx": "^5.3.1",
- "acorn-walk": "^7.2.0",
- "core-js": "^3.8.2",
- "doctrine": "^3.0.0",
- "escodegen": "^2.0.0",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "html-tags": "^3.1.0",
- "js-string-escape": "^1.0.1",
- "loader-utils": "^2.0.0",
- "lodash": "^4.17.21",
- "nanoid": "^3.1.23",
- "p-limit": "^3.1.0",
- "prettier": "<=2.3.0",
- "prop-types": "^15.7.2",
- "react-element-to-jsx-string": "^14.3.4",
- "regenerator-runtime": "^0.13.7",
- "remark-external-links": "^8.0.0",
- "remark-slug": "^6.0.0",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/compat-data": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
- "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz",
- "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.7",
- "@babel/helper-compilation-targets": "^7.16.7",
- "@babel/helper-module-transforms": "^7.16.7",
- "@babel/helpers": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- }
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
- "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.16.4",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.17.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
- "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
- "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz",
- "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
- "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- }
- }
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- }
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "browserslist": {
- "version": "4.19.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
- "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001286",
- "electron-to-chromium": "^1.4.17",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001300",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
- "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "electron-to-chromium": {
- "version": "1.4.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz",
- "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==",
- "dev": true
- },
- "escodegen": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
- "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
- "dev": true,
- "requires": {
- "esprima": "^4.0.1",
- "estraverse": "^5.2.0",
- "esutils": "^2.0.2",
- "optionator": "^0.8.1",
- "source-map": "~0.6.1"
- },
- "dependencies": {
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "optional": true
- }
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
- }
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
- },
- "optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
- "dev": true,
- "requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
- "dev": true
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2"
- }
- }
- }
- },
- "@storybook/addon-essentials": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-essentials/-/addon-essentials-6.4.13.tgz",
- "integrity": "sha512-ekvyeVckKkffGQMzp6cT0/Mi8Wo1fqF/DGp3vJIcIrExfvuZa/qi8PoHyx+cr8dfI0b8Jf8Lv7qcLIxNnkA5Bg==",
- "dev": true,
- "requires": {
- "@storybook/addon-actions": "6.4.13",
- "@storybook/addon-backgrounds": "6.4.13",
- "@storybook/addon-controls": "6.4.13",
- "@storybook/addon-docs": "6.4.13",
- "@storybook/addon-measure": "6.4.13",
- "@storybook/addon-outline": "6.4.13",
- "@storybook/addon-toolbars": "6.4.13",
- "@storybook/addon-viewport": "6.4.13",
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/node-logger": "6.4.13",
- "core-js": "^3.8.2",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0"
- }
- },
- "@storybook/addon-jest": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-jest/-/addon-jest-6.4.13.tgz",
- "integrity": "sha512-6Ux/kWq3kEc6D91t4sX4j+IAzBhWzYZpKV5zpMYmPaIV/7SYpKsjIcmpxRJpel6GhvxIp2xSa6PeBu2/6yhmbw==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "react-sizeme": "^3.0.1",
- "regenerator-runtime": "^0.13.7",
- "upath": "^1.2.0"
- }
- },
- "@storybook/addon-links": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-links/-/addon-links-6.4.13.tgz",
- "integrity": "sha512-d/uxMZoEjgCRhVvJXYIKJ0VtHARA7p7/oDxBMiexBDGZ2FzZWtq/nejdER539X71JMUkjkaqTs+ekTunZe0eMg==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/router": "6.4.13",
- "@types/qs": "^6.9.5",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "prop-types": "^15.7.2",
- "qs": "^6.10.0",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- }
- }
- },
- "@storybook/addon-measure": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-measure/-/addon-measure-6.4.13.tgz",
- "integrity": "sha512-uOnJrSWNlMznScCfeXkhqlenLoz6DBgNgBxuP7P6TiF5cxq7Xwv23RX3Hj1nzybP+wvUPEj08FBCh8BqgGOsOA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "core-js": "^3.8.2",
- "global": "^4.4.0"
- }
- },
- "@storybook/addon-outline": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-outline/-/addon-outline-6.4.13.tgz",
- "integrity": "sha512-9BR70PRQeHtED/NkDp6JPRPrpKA43AubgRu4PHUJ0sbaD7o2DMHPKtt2AcsZoL7JSeGDl30cYzfn3pVZDPVxEA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0"
- }
- },
- "@storybook/addon-storyshots": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-storyshots/-/addon-storyshots-6.4.13.tgz",
- "integrity": "sha512-SrMSbuPNZizmQwELWEbZYyPlxppznbXz0r1mq2AabVFVQz+bZh7aNBUlNQyQMIxw1Hwnycx0YD7Lm+IS35mWiQ==",
- "dev": true,
- "requires": {
- "@jest/transform": "^26.6.2",
- "@storybook/addons": "6.4.13",
- "@storybook/babel-plugin-require-context-hook": "1.0.1",
- "@storybook/client-api": "6.4.13",
- "@storybook/core": "6.4.13",
- "@storybook/core-client": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@types/glob": "^7.1.3",
- "@types/jest": "^26.0.16",
- "@types/jest-specific-snapshot": "^0.5.3",
- "core-js": "^3.8.2",
- "glob": "^7.1.6",
- "global": "^4.4.0",
- "jest-specific-snapshot": "^4.0.0",
- "preact-render-to-string": "^5.1.19",
- "pretty-format": "^26.6.2",
- "react-test-renderer": "^16.8.0 || ^17.0.0",
- "read-pkg-up": "^7.0.1",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0"
- }
- },
- "@storybook/addon-storysource": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-storysource/-/addon-storysource-6.4.13.tgz",
- "integrity": "sha512-fpKUCqk3I0Gk/1DduasqS19zvAfTnGn7dfmOtkqzPUEAjbeKcnQDhRBOYr7qykdSjk76HD2+6jrsvcWwaeWFHA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/router": "6.4.13",
- "@storybook/source-loader": "6.4.13",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "estraverse": "^5.2.0",
- "loader-utils": "^2.0.0",
- "prettier": "<=2.3.0",
- "prop-types": "^15.7.2",
- "react-syntax-highlighter": "^13.5.3",
- "regenerator-runtime": "^0.13.7"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- }
- }
- },
- "@storybook/addon-toolbars": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-6.4.13.tgz",
- "integrity": "sha512-57/bO5MsVnRjmxff+JjQzqjWCzX1KDHR8zla1RpaGsW5ejXcQumW38Xbp0OCscD7wGLL/b58GM/9OIk38LqBwA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "regenerator-runtime": "^0.13.7"
- }
- },
- "@storybook/addon-viewport": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addon-viewport/-/addon-viewport-6.4.13.tgz",
- "integrity": "sha512-EzgPyLRTDgezSlZ7yCKDhR/VcKBECEdd7JCLiuVbfrThVhaKzM9gCx5pDnc0qTflx0DagqkIWFHNVPQt2KnQ3g==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "memoizerific": "^1.11.3",
- "prop-types": "^15.7.2",
- "regenerator-runtime": "^0.13.7"
- }
- },
- "@storybook/addons": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.4.13.tgz",
- "integrity": "sha512-2oxZ/VOuXUpOvtKGy+fR1FNwyfaTkzKs9I6cZq2zbEGK2q/5x6rtczwNRm5PjK35At+VurMq0E+IHH10JO9vHw==",
- "dev": true,
- "requires": {
- "@storybook/api": "6.4.13",
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/router": "6.4.13",
- "@storybook/theming": "6.4.13",
- "@types/webpack-env": "^1.16.0",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "regenerator-runtime": "^0.13.7"
- }
- },
- "@storybook/api": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.4.13.tgz",
- "integrity": "sha512-Hr5/dL4tLnQPjrUlVdhsYMSAuJmsZcu3jdfqpjbsDC9S2HNaVtyHGBhQ33jD8+xtXoorsuS7t4SfWzLOgPPflg==",
- "dev": true,
- "requires": {
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/router": "6.4.13",
- "@storybook/semver": "^7.3.2",
- "@storybook/theming": "6.4.13",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "memoizerific": "^1.11.3",
- "regenerator-runtime": "^0.13.7",
- "store2": "^2.12.0",
- "telejson": "^5.3.2",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/babel-plugin-require-context-hook": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@storybook/babel-plugin-require-context-hook/-/babel-plugin-require-context-hook-1.0.1.tgz",
- "integrity": "sha512-WM4vjgSVi8epvGiYfru7BtC3f0tGwNs7QK3Uc4xQn4t5hHQvISnCqbNrHdDYmNW56Do+bBztE8SwP6NGUvd7ww==",
- "dev": true
- },
- "@storybook/builder-webpack4": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/builder-webpack4/-/builder-webpack4-6.4.13.tgz",
- "integrity": "sha512-Vjvje/XpFirVY6bOU+ahS2niapjA0Qams5jBE8YnPUhbigqsLOMMpnJ+C505xC6S5VW0lMkhJpCQ1NQyva3sRw==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.10",
- "@babel/plugin-proposal-class-properties": "^7.12.1",
- "@babel/plugin-proposal-decorators": "^7.12.12",
- "@babel/plugin-proposal-export-default-from": "^7.12.1",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
- "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
- "@babel/plugin-proposal-optional-chaining": "^7.12.7",
- "@babel/plugin-proposal-private-methods": "^7.12.1",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-transform-arrow-functions": "^7.12.1",
- "@babel/plugin-transform-block-scoping": "^7.12.12",
- "@babel/plugin-transform-classes": "^7.12.1",
- "@babel/plugin-transform-destructuring": "^7.12.1",
- "@babel/plugin-transform-for-of": "^7.12.1",
- "@babel/plugin-transform-parameters": "^7.12.1",
- "@babel/plugin-transform-shorthand-properties": "^7.12.1",
- "@babel/plugin-transform-spread": "^7.12.1",
- "@babel/plugin-transform-template-literals": "^7.12.1",
- "@babel/preset-env": "^7.12.11",
- "@babel/preset-react": "^7.12.10",
- "@babel/preset-typescript": "^7.12.7",
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/channel-postmessage": "6.4.13",
- "@storybook/channels": "6.4.13",
- "@storybook/client-api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/node-logger": "6.4.13",
- "@storybook/preview-web": "6.4.13",
- "@storybook/router": "6.4.13",
- "@storybook/semver": "^7.3.2",
- "@storybook/store": "6.4.13",
- "@storybook/theming": "6.4.13",
- "@storybook/ui": "6.4.13",
- "@types/node": "^14.0.10",
- "@types/webpack": "^4.41.26",
- "autoprefixer": "^9.8.6",
- "babel-loader": "^8.0.0",
- "babel-plugin-macros": "^2.8.0",
- "babel-plugin-polyfill-corejs3": "^0.1.0",
- "case-sensitive-paths-webpack-plugin": "^2.3.0",
- "core-js": "^3.8.2",
- "css-loader": "^3.6.0",
- "file-loader": "^6.2.0",
- "find-up": "^5.0.0",
- "fork-ts-checker-webpack-plugin": "^4.1.6",
- "glob": "^7.1.6",
- "glob-promise": "^3.4.0",
- "global": "^4.4.0",
- "html-webpack-plugin": "^4.0.0",
- "pnp-webpack-plugin": "1.6.4",
- "postcss": "^7.0.36",
- "postcss-flexbugs-fixes": "^4.2.1",
- "postcss-loader": "^4.2.0",
- "raw-loader": "^4.0.2",
- "stable": "^0.1.8",
- "style-loader": "^1.3.0",
- "terser-webpack-plugin": "^4.2.3",
- "ts-dedent": "^2.0.0",
- "url-loader": "^4.1.1",
- "util-deprecate": "^1.0.2",
- "webpack": "4",
- "webpack-dev-middleware": "^3.7.3",
- "webpack-filter-warnings-plugin": "^1.2.1",
- "webpack-hot-middleware": "^2.25.1",
- "webpack-virtual-modules": "^0.2.2"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/compat-data": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
- "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz",
- "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.7",
- "@babel/helper-compilation-targets": "^7.16.7",
- "@babel/helper-module-transforms": "^7.16.7",
- "@babel/helpers": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- }
- },
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
- "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
- "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.16.4",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.17.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-create-class-features-plugin": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz",
- "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.16.7",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-member-expression-to-functions": "^7.16.7",
- "@babel/helper-optimise-call-expression": "^7.16.7",
- "@babel/helper-replace-supers": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz",
- "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
- "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz",
- "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
- "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
- "dev": true
- },
- "@babel/helper-replace-supers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
- "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-member-expression-to-functions": "^7.16.7",
- "@babel/helper-optimise-call-expression": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
- "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz",
- "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
- "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/plugin-proposal-decorators": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz",
- "integrity": "sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.16.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-decorators": "^7.16.7"
- }
- },
- "@babel/plugin-syntax-decorators": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz",
- "integrity": "sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- }
- },
- "@babel/plugin-syntax-typescript": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz",
- "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- }
- },
- "@babel/plugin-transform-typescript": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz",
- "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.16.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-typescript": "^7.16.7"
- }
- },
- "@babel/preset-typescript": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz",
- "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/helper-validator-option": "^7.16.7",
- "@babel/plugin-transform-typescript": "^7.16.7"
- }
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "browserslist": {
- "version": "4.19.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
- "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001286",
- "electron-to-chromium": "^1.4.17",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001300",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
- "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "css-loader": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
- "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.3.1",
- "cssesc": "^3.0.0",
- "icss-utils": "^4.1.1",
- "loader-utils": "^1.2.3",
- "normalize-path": "^3.0.0",
- "postcss": "^7.0.32",
- "postcss-modules-extract-imports": "^2.0.0",
- "postcss-modules-local-by-default": "^3.0.2",
- "postcss-modules-scope": "^2.2.0",
- "postcss-modules-values": "^3.0.0",
- "postcss-value-parser": "^4.1.0",
- "schema-utils": "^2.7.0",
- "semver": "^6.3.0"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz",
- "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==",
- "dev": true
- },
- "file-loader": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
- "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
- "dev": true,
- "requires": {
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "loader-utils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
- "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- }
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.0"
- }
- }
- }
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "postcss-loader": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-4.3.0.tgz",
- "integrity": "sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==",
- "dev": true,
- "requires": {
- "cosmiconfig": "^7.0.0",
- "klona": "^2.0.4",
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0",
- "semver": "^7.3.4"
- },
- "dependencies": {
- "loader-utils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
- "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- }
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@storybook/channel-postmessage": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.4.13.tgz",
- "integrity": "sha512-fyju7H/t2oDp9yci6KImRDPr9FnGV6B0juJ+2kEtVAmeDo55BScjT96SQuS/uk4c0wo6NZMrCt6HiC4zOmrD6g==",
- "dev": true,
- "requires": {
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "qs": "^6.10.0",
- "telejson": "^5.3.2"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- }
- }
- },
- "@storybook/channel-websocket": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/channel-websocket/-/channel-websocket-6.4.13.tgz",
- "integrity": "sha512-edc/KRF2dpMyCI67ik8loo2cNh7TUP8HoO/YJBVPTEGmOQxMWgmYs+loTd1xoZAFBdkVKvLXBiu8umPpdh2MpA==",
- "dev": true,
- "requires": {
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "telejson": "^5.3.2"
- }
- },
- "@storybook/channels": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.4.13.tgz",
- "integrity": "sha512-QWvm2TiqPZVPQLBq7ETcABNi17HIhNaXhJJUyNFBBXFtAHcbzMRFEBi6gkCVXK7QdtFo3Z68TU5htDkwjYVerg==",
- "dev": true,
- "requires": {
- "core-js": "^3.8.2",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/client-api": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.4.13.tgz",
- "integrity": "sha512-YoF0iKeOTv06HFTLSg1M8Fs9JZwFcNhGFHXv7/LtuTZ9n6ATgaZm7eTTdKrn1d8Qjxql7c7Lm/7mdZgus9ByBA==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/channel-postmessage": "6.4.13",
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/store": "6.4.13",
- "@types/qs": "^6.9.5",
- "@types/webpack-env": "^1.16.0",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "memoizerific": "^1.11.3",
- "qs": "^6.10.0",
- "regenerator-runtime": "^0.13.7",
- "store2": "^2.12.0",
- "synchronous-promise": "^2.0.15",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- }
- }
- },
- "@storybook/client-logger": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.4.13.tgz",
- "integrity": "sha512-VPrrgJRURztXAKTeHOpzKMAHnNupkGApUDNlPIs0Qxyn5gaSiy806q4XPoROno3mVgEe+7Chf86hRiL8pJnlCA==",
- "dev": true,
- "requires": {
- "core-js": "^3.8.2",
- "global": "^4.4.0"
- }
- },
- "@storybook/components": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.4.13.tgz",
- "integrity": "sha512-edeoYycQMsPaXPyPvYV4Aoiz4A/9kPsZt0Wf2zBGMGX6cpaGV3aoy8pFBl6XSq2hPxIn8JdcB/8MK3/tj35h4w==",
- "dev": true,
- "requires": {
- "@popperjs/core": "^2.6.0",
- "@storybook/client-logger": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/theming": "6.4.13",
- "@types/color-convert": "^2.0.0",
- "@types/overlayscrollbars": "^1.12.0",
- "@types/react-syntax-highlighter": "11.0.5",
- "color-convert": "^2.0.1",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "markdown-to-jsx": "^7.1.3",
- "memoizerific": "^1.11.3",
- "overlayscrollbars": "^1.13.1",
- "polished": "^4.0.5",
- "prop-types": "^15.7.2",
- "react-colorful": "^5.1.2",
- "react-popper-tooltip": "^3.1.1",
- "react-syntax-highlighter": "^13.5.3",
- "react-textarea-autosize": "^8.3.0",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/core": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/core/-/core-6.4.13.tgz",
- "integrity": "sha512-OSbji5w4jrGNALbxJwktZhi8qw4bGgL88dL72O40173b8ROLBOGkEkkz/BpHbqx2PhS9sGVNVMK2b2BwAiiu7g==",
- "dev": true,
- "requires": {
- "@storybook/core-client": "6.4.13",
- "@storybook/core-server": "6.4.13"
- }
- },
- "@storybook/core-client": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/core-client/-/core-client-6.4.13.tgz",
- "integrity": "sha512-1m7cAlF16mtVdSNmP8a4z00GCkw2dMyUyJX8snzgYGLD5FaqPLyNGJIidqllHsBUXBfEL2FSu+E9QygK12+O1w==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/channel-postmessage": "6.4.13",
- "@storybook/channel-websocket": "6.4.13",
- "@storybook/client-api": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/preview-web": "6.4.13",
- "@storybook/store": "6.4.13",
- "@storybook/ui": "6.4.13",
- "airbnb-js-shims": "^2.2.1",
- "ansi-to-html": "^0.6.11",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "qs": "^6.10.0",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0",
- "unfetch": "^4.2.0",
- "util-deprecate": "^1.0.2"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- }
- }
- },
- "@storybook/core-common": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/core-common/-/core-common-6.4.13.tgz",
- "integrity": "sha512-KoFa4yktuqWsW+/O6uc7iba25X9eKhp80l9tHsa1RWE94mQdCBUo5VsNoe35JvqFSDOspQ+brCe6vBUaIYe+cQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.10",
- "@babel/plugin-proposal-class-properties": "^7.12.1",
- "@babel/plugin-proposal-decorators": "^7.12.12",
- "@babel/plugin-proposal-export-default-from": "^7.12.1",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
- "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
- "@babel/plugin-proposal-optional-chaining": "^7.12.7",
- "@babel/plugin-proposal-private-methods": "^7.12.1",
- "@babel/plugin-syntax-dynamic-import": "^7.8.3",
- "@babel/plugin-transform-arrow-functions": "^7.12.1",
- "@babel/plugin-transform-block-scoping": "^7.12.12",
- "@babel/plugin-transform-classes": "^7.12.1",
- "@babel/plugin-transform-destructuring": "^7.12.1",
- "@babel/plugin-transform-for-of": "^7.12.1",
- "@babel/plugin-transform-parameters": "^7.12.1",
- "@babel/plugin-transform-shorthand-properties": "^7.12.1",
- "@babel/plugin-transform-spread": "^7.12.1",
- "@babel/preset-env": "^7.12.11",
- "@babel/preset-react": "^7.12.10",
- "@babel/preset-typescript": "^7.12.7",
- "@babel/register": "^7.12.1",
- "@storybook/node-logger": "6.4.13",
- "@storybook/semver": "^7.3.2",
- "@types/node": "^14.0.10",
- "@types/pretty-hrtime": "^1.0.0",
- "babel-loader": "^8.0.0",
- "babel-plugin-macros": "^3.0.1",
- "babel-plugin-polyfill-corejs3": "^0.1.0",
- "chalk": "^4.1.0",
- "core-js": "^3.8.2",
- "express": "^4.17.1",
- "file-system-cache": "^1.0.5",
- "find-up": "^5.0.0",
- "fork-ts-checker-webpack-plugin": "^6.0.4",
- "fs-extra": "^9.0.1",
- "glob": "^7.1.6",
- "handlebars": "^4.7.7",
- "interpret": "^2.2.0",
- "json5": "^2.1.3",
- "lazy-universal-dotenv": "^3.0.1",
- "picomatch": "^2.3.0",
- "pkg-dir": "^5.0.0",
- "pretty-hrtime": "^1.0.3",
- "resolve-from": "^5.0.0",
- "slash": "^3.0.0",
- "telejson": "^5.3.2",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2",
- "webpack": "4"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/compat-data": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
- "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz",
- "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.7",
- "@babel/helper-compilation-targets": "^7.16.7",
- "@babel/helper-module-transforms": "^7.16.7",
- "@babel/helpers": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- }
- },
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-annotate-as-pure": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz",
- "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
- "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.16.4",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.17.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-create-class-features-plugin": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz",
- "integrity": "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw==",
- "dev": true,
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.16.7",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-member-expression-to-functions": "^7.16.7",
- "@babel/helper-optimise-call-expression": "^7.16.7",
- "@babel/helper-replace-supers": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-member-expression-to-functions": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz",
- "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
- "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-optimise-call-expression": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz",
- "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz",
- "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==",
- "dev": true
- },
- "@babel/helper-replace-supers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz",
- "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-member-expression-to-functions": "^7.16.7",
- "@babel/helper-optimise-call-expression": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
- "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz",
- "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
- "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- }
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/plugin-proposal-decorators": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz",
- "integrity": "sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.16.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-decorators": "^7.16.7"
- }
- },
- "@babel/plugin-syntax-decorators": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz",
- "integrity": "sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- }
- },
- "@babel/plugin-syntax-typescript": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz",
- "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7"
- }
- },
- "@babel/plugin-transform-typescript": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz",
- "integrity": "sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==",
- "dev": true,
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.16.7",
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/plugin-syntax-typescript": "^7.16.7"
- }
- },
- "@babel/preset-typescript": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz",
- "integrity": "sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.16.7",
- "@babel/helper-validator-option": "^7.16.7",
- "@babel/plugin-transform-typescript": "^7.16.7"
- }
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "babel-plugin-macros": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
- "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.12.5",
- "cosmiconfig": "^7.0.0",
- "resolve": "^1.19.0"
- }
- },
- "browserslist": {
- "version": "4.19.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
- "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001286",
- "electron-to-chromium": "^1.4.17",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001300",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
- "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
- "dev": true
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "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==",
- "dev": true,
- "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==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "electron-to-chromium": {
- "version": "1.4.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz",
- "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==",
- "dev": true
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "fork-ts-checker-webpack-plugin": {
- "version": "6.5.0",
- "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz",
- "integrity": "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.8.3",
- "@types/json-schema": "^7.0.5",
- "chalk": "^4.1.0",
- "chokidar": "^3.4.2",
- "cosmiconfig": "^6.0.0",
- "deepmerge": "^4.2.2",
- "fs-extra": "^9.0.0",
- "glob": "^7.1.6",
- "memfs": "^3.1.2",
- "minimatch": "^3.0.4",
- "schema-utils": "2.7.0",
- "semver": "^7.3.2",
- "tapable": "^1.0.0"
- },
- "dependencies": {
- "cosmiconfig": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
- "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
- "dev": true,
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.1.0",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.7.2"
- }
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true
- },
- "pkg-dir": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz",
- "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==",
- "dev": true,
- "requires": {
- "find-up": "^5.0.0"
- }
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- },
- "schema-utils": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz",
- "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.4",
- "ajv": "^6.12.2",
- "ajv-keywords": "^3.4.1"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@storybook/core-events": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.4.13.tgz",
- "integrity": "sha512-zNlzNv7qVXjLf7yfvY9KfLvDY8nVskxrjmz0+21rIqUefS9+7SWBrtJJURpCaoPf/BmACqh/6c1RnuOY7TESnw==",
- "dev": true,
- "requires": {
- "core-js": "^3.8.2"
- }
- },
- "@storybook/core-server": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/core-server/-/core-server-6.4.13.tgz",
- "integrity": "sha512-i3zrtHHkV6/b+jJF65BQu+YuXen+T/MF1f5J+li5nvJnLKhssVQmvpGvWyJezT3OgFkC1+BFBokFY6NXHHw77g==",
- "dev": true,
- "requires": {
- "@discoveryjs/json-ext": "^0.5.3",
- "@storybook/builder-webpack4": "6.4.13",
- "@storybook/core-client": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/csf-tools": "6.4.13",
- "@storybook/manager-webpack4": "6.4.13",
- "@storybook/node-logger": "6.4.13",
- "@storybook/semver": "^7.3.2",
- "@storybook/store": "6.4.13",
- "@types/node": "^14.0.10",
- "@types/node-fetch": "^2.5.7",
- "@types/pretty-hrtime": "^1.0.0",
- "@types/webpack": "^4.41.26",
- "better-opn": "^2.1.1",
- "boxen": "^5.1.2",
- "chalk": "^4.1.0",
- "cli-table3": "^0.6.1",
- "commander": "^6.2.1",
- "compression": "^1.7.4",
- "core-js": "^3.8.2",
- "cpy": "^8.1.2",
- "detect-port": "^1.3.0",
- "express": "^4.17.1",
- "file-system-cache": "^1.0.5",
- "fs-extra": "^9.0.1",
- "globby": "^11.0.2",
- "ip": "^1.1.5",
- "lodash": "^4.17.21",
- "node-fetch": "^2.6.1",
- "pretty-hrtime": "^1.0.3",
- "prompts": "^2.4.0",
- "regenerator-runtime": "^0.13.7",
- "serve-favicon": "^2.5.0",
- "slash": "^3.0.0",
- "telejson": "^5.3.3",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2",
- "watchpack": "^2.2.0",
- "webpack": "4",
- "ws": "^8.2.3"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "cli-table3": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.1.tgz",
- "integrity": "sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==",
- "dev": true,
- "requires": {
- "colors": "1.4.0",
- "string-width": "^4.2.0"
- }
- },
- "commander": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
- "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "watchpack": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
- "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
- "dev": true,
- "requires": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- }
- },
- "ws": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.4.2.tgz",
- "integrity": "sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==",
- "dev": true
- }
- }
- },
- "@storybook/csf": {
- "version": "0.0.2--canary.87bc651.0",
- "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.2--canary.87bc651.0.tgz",
- "integrity": "sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.15"
- }
- },
- "@storybook/csf-tools": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.4.13.tgz",
- "integrity": "sha512-eEYQdr/N4bsiQFxNEUkfQ/KyqdnUecwFS7V1k16/m/dP7cfinwW2Yo+9t77uWe3Qmzj9RbM6jrdWxXEUZ6MwvQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.10",
- "@babel/generator": "^7.12.11",
- "@babel/parser": "^7.12.11",
- "@babel/plugin-transform-react-jsx": "^7.12.12",
- "@babel/preset-env": "^7.12.11",
- "@babel/traverse": "^7.12.11",
- "@babel/types": "^7.12.11",
- "@mdx-js/mdx": "^1.6.22",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "core-js": "^3.8.2",
- "fs-extra": "^9.0.1",
- "global": "^4.4.0",
- "js-string-escape": "^1.0.1",
- "lodash": "^4.17.21",
- "prettier": "<=2.3.0",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/compat-data": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
- "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz",
- "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.7",
- "@babel/helper-compilation-targets": "^7.16.7",
- "@babel/helper-module-transforms": "^7.16.7",
- "@babel/helpers": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
- "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.16.4",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.17.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
- "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
- "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz",
- "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "@babel/highlight": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
- "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- }
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- },
- "dependencies": {
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- }
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "browserslist": {
- "version": "4.19.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
- "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001286",
- "electron-to-chromium": "^1.4.17",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001300",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
- "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
- "dev": true
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "electron-to-chromium": {
- "version": "1.4.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz",
- "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@storybook/manager-webpack4": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/manager-webpack4/-/manager-webpack4-6.4.13.tgz",
- "integrity": "sha512-aUUIvSf1nUSuPEdLFcbXbEbm+WlBrpX+Ce+Ee5zuMpggfiMeq4H4UB5QuluB8oLUcJA/ZoQZ9m4pPfUZDH0O0w==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.12.10",
- "@babel/plugin-transform-template-literals": "^7.12.1",
- "@babel/preset-react": "^7.12.10",
- "@storybook/addons": "6.4.13",
- "@storybook/core-client": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/node-logger": "6.4.13",
- "@storybook/theming": "6.4.13",
- "@storybook/ui": "6.4.13",
- "@types/node": "^14.0.10",
- "@types/webpack": "^4.41.26",
- "babel-loader": "^8.0.0",
- "case-sensitive-paths-webpack-plugin": "^2.3.0",
- "chalk": "^4.1.0",
- "core-js": "^3.8.2",
- "css-loader": "^3.6.0",
- "express": "^4.17.1",
- "file-loader": "^6.2.0",
- "file-system-cache": "^1.0.5",
- "find-up": "^5.0.0",
- "fs-extra": "^9.0.1",
- "html-webpack-plugin": "^4.0.0",
- "node-fetch": "^2.6.1",
- "pnp-webpack-plugin": "1.6.4",
- "read-pkg-up": "^7.0.1",
- "regenerator-runtime": "^0.13.7",
- "resolve-from": "^5.0.0",
- "style-loader": "^1.3.0",
- "telejson": "^5.3.2",
- "terser-webpack-plugin": "^4.2.3",
- "ts-dedent": "^2.0.0",
- "url-loader": "^4.1.1",
- "util-deprecate": "^1.0.2",
- "webpack": "4",
- "webpack-dev-middleware": "^3.7.3",
- "webpack-virtual-modules": "^0.2.2"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
- "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==",
- "dev": true,
- "requires": {
- "@babel/highlight": "^7.16.7"
- }
- },
- "@babel/compat-data": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.8.tgz",
- "integrity": "sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==",
- "dev": true
- },
- "@babel/core": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz",
- "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.7",
- "@babel/helper-compilation-targets": "^7.16.7",
- "@babel/helper-module-transforms": "^7.16.7",
- "@babel/helpers": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.2",
- "json5": "^2.1.2",
- "semver": "^6.3.0",
- "source-map": "^0.5.0"
- }
- },
- "@babel/generator": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz",
- "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.8",
- "jsesc": "^2.5.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-compilation-targets": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz",
- "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==",
- "dev": true,
- "requires": {
- "@babel/compat-data": "^7.16.4",
- "@babel/helper-validator-option": "^7.16.7",
- "browserslist": "^4.17.5",
- "semver": "^6.3.0"
- }
- },
- "@babel/helper-function-name": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz",
- "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==",
- "dev": true,
- "requires": {
- "@babel/helper-get-function-arity": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-get-function-arity": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz",
- "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-hoist-variables": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz",
- "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-imports": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz",
- "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-module-transforms": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz",
- "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==",
- "dev": true,
- "requires": {
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-module-imports": "^7.16.7",
- "@babel/helper-simple-access": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/helper-validator-identifier": "^7.16.7",
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-simple-access": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz",
- "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-split-export-declaration": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz",
- "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==",
- "dev": true,
- "requires": {
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/helper-validator-identifier": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
- "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==",
- "dev": true
- },
- "@babel/helper-validator-option": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz",
- "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==",
- "dev": true
- },
- "@babel/helpers": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz",
- "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==",
- "dev": true,
- "requires": {
- "@babel/template": "^7.16.7",
- "@babel/traverse": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/highlight": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz",
- "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "chalk": "^2.0.0",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- }
- }
- },
- "@babel/parser": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz",
- "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==",
- "dev": true
- },
- "@babel/template": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz",
- "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/parser": "^7.16.7",
- "@babel/types": "^7.16.7"
- }
- },
- "@babel/traverse": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz",
- "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.16.7",
- "@babel/generator": "^7.16.8",
- "@babel/helper-environment-visitor": "^7.16.7",
- "@babel/helper-function-name": "^7.16.7",
- "@babel/helper-hoist-variables": "^7.16.7",
- "@babel/helper-split-export-declaration": "^7.16.7",
- "@babel/parser": "^7.16.8",
- "@babel/types": "^7.16.8",
- "debug": "^4.1.0",
- "globals": "^11.1.0"
- }
- },
- "@babel/types": {
- "version": "7.16.8",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz",
- "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==",
- "dev": true,
- "requires": {
- "@babel/helper-validator-identifier": "^7.16.7",
- "to-fast-properties": "^2.0.0"
- }
- },
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "browserslist": {
- "version": "4.19.1",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
- "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
- "dev": true,
- "requires": {
- "caniuse-lite": "^1.0.30001286",
- "electron-to-chromium": "^1.4.17",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001300",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001300.tgz",
- "integrity": "sha512-cVjiJHWGcNlJi8TZVKNMnvMid3Z3TTdDHmLDzlOdIiZq138Exvo0G+G0wTdVYolxKb4AYwC+38pxodiInVtJSA==",
- "dev": true
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "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==",
- "dev": true,
- "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==",
- "dev": true
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "css-loader": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
- "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==",
- "dev": true,
- "requires": {
- "camelcase": "^5.3.1",
- "cssesc": "^3.0.0",
- "icss-utils": "^4.1.1",
- "loader-utils": "^1.2.3",
- "normalize-path": "^3.0.0",
- "postcss": "^7.0.32",
- "postcss-modules-extract-imports": "^2.0.0",
- "postcss-modules-local-by-default": "^3.0.2",
- "postcss-modules-scope": "^2.2.0",
- "postcss-modules-values": "^3.0.0",
- "postcss-value-parser": "^4.1.0",
- "schema-utils": "^2.7.0",
- "semver": "^6.3.0"
- }
- },
- "electron-to-chromium": {
- "version": "1.4.47",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.47.tgz",
- "integrity": "sha512-ZHc8i3/cgeCRK/vC7W2htAG6JqUmOUgDNn/f9yY9J8UjfLjwzwOVEt4MWmgJAdvmxyrsR5KIFA/6+kUHGY0eUA==",
- "dev": true
- },
- "file-loader": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
- "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
- "dev": true,
- "requires": {
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "loader-utils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
- "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- }
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "dev": true,
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.0"
- }
- }
- }
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
- "dev": true
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "@storybook/node-logger": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/node-logger/-/node-logger-6.4.13.tgz",
- "integrity": "sha512-L0WJjJ3MTkdSpCaC1xSJ1/SJzblQ8E3tYKSI3M3890711gfxtSM/9CfuatQ6ibTXcm5d8bW6TUJayTD4I8vUPg==",
- "dev": true,
- "requires": {
- "@types/npmlog": "^4.1.2",
- "chalk": "^4.1.0",
- "core-js": "^3.8.2",
- "npmlog": "^5.0.1",
- "pretty-hrtime": "^1.0.3"
- },
- "dependencies": {
- "are-we-there-yet": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz",
- "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==",
- "dev": true,
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^3.6.0"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "gauge": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz",
- "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==",
- "dev": true,
- "requires": {
- "aproba": "^1.0.3 || ^2.0.0",
- "color-support": "^1.1.2",
- "console-control-strings": "^1.0.0",
- "has-unicode": "^2.0.1",
- "object-assign": "^4.1.1",
- "signal-exit": "^3.0.0",
- "string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "wide-align": "^1.1.2"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "npmlog": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz",
- "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==",
- "dev": true,
- "requires": {
- "are-we-there-yet": "^2.0.0",
- "console-control-strings": "^1.1.0",
- "gauge": "^3.0.0",
- "set-blocking": "^2.0.0"
- }
- },
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "@storybook/postinstall": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/postinstall/-/postinstall-6.4.13.tgz",
- "integrity": "sha512-7SzFt0BDFOI0vFKc0Ba5slkQaur3AEN9211U7pBbzgp6HxBjiTT5fqLET+dvk30ke8YtOauj0LZ+uHx9TNYrBA==",
- "dev": true,
- "requires": {
- "core-js": "^3.8.2"
- }
- },
- "@storybook/preset-create-react-app": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/@storybook/preset-create-react-app/-/preset-create-react-app-3.2.0.tgz",
- "integrity": "sha512-lLoWCGr5cV+JNDRKYHC2gD+P2eyBqdN8qhmBa+PxDgPSNKfgUf9Wnoh+C7WTG5q2DEeR9SvUpQpZomX9DDQa4Q==",
- "dev": true,
- "requires": {
- "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
- "@types/babel__core": "^7.1.7",
- "@types/webpack": "^4.41.13",
- "babel-plugin-react-docgen": "^4.1.0",
- "pnp-webpack-plugin": "^1.6.4",
- "react-docgen-typescript-plugin": "^1.0.0",
- "semver": "^7.3.5"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "dev": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@storybook/preview-web": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/preview-web/-/preview-web-6.4.13.tgz",
- "integrity": "sha512-z21N09iWrzi2sX5+06aNvxPVp0rzntO7seM7zIPxqpFiEsAoPodkVJka3YyJpgK3S2JtgipmIgvLJeLXENLr3g==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/channel-postmessage": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/store": "6.4.13",
- "ansi-to-html": "^0.6.11",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "qs": "^6.10.0",
- "regenerator-runtime": "^0.13.7",
- "synchronous-promise": "^2.0.15",
- "ts-dedent": "^2.0.0",
- "unfetch": "^4.2.0",
- "util-deprecate": "^1.0.2"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- }
- }
- },
- "@storybook/react": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/react/-/react-6.4.13.tgz",
- "integrity": "sha512-bmHGeAAad0qoEfselx3qvWlPf1fWccDgki3TneFWYTSoybZOuu0PWJp+M7kqWMxcyvdwQImjA9F+vCc7CUuF9w==",
- "dev": true,
- "requires": {
- "@babel/preset-flow": "^7.12.1",
- "@babel/preset-react": "^7.12.10",
- "@pmmmwh/react-refresh-webpack-plugin": "^0.5.1",
- "@storybook/addons": "6.4.13",
- "@storybook/core": "6.4.13",
- "@storybook/core-common": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "@storybook/node-logger": "6.4.13",
- "@storybook/react-docgen-typescript-plugin": "1.0.2-canary.253f8c1.0",
- "@storybook/semver": "^7.3.2",
- "@storybook/store": "6.4.13",
- "@types/webpack-env": "^1.16.0",
- "babel-plugin-add-react-displayname": "^0.0.5",
- "babel-plugin-named-asset-import": "^0.3.1",
- "babel-plugin-react-docgen": "^4.2.1",
- "core-js": "^3.8.2",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "prop-types": "^15.7.2",
- "react-refresh": "^0.11.0",
- "read-pkg-up": "^7.0.1",
- "regenerator-runtime": "^0.13.7",
- "ts-dedent": "^2.0.0",
- "webpack": "4"
- },
- "dependencies": {
- "@pmmmwh/react-refresh-webpack-plugin": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.4.tgz",
- "integrity": "sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==",
- "dev": true,
- "requires": {
- "ansi-html-community": "^0.0.8",
- "common-path-prefix": "^3.0.0",
- "core-js-pure": "^3.8.1",
- "error-stack-parser": "^2.0.6",
- "find-up": "^5.0.0",
- "html-entities": "^2.1.0",
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0",
- "source-map": "^0.7.3"
- }
- },
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
- "dev": true
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "html-entities": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
- "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
- "dev": true
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "react-refresh": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
- "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
- "dev": true
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- },
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "dev": true
- }
- }
- },
- "@storybook/react-docgen-typescript-plugin": {
- "version": "1.0.2-canary.253f8c1.0",
- "resolved": "https://registry.npmjs.org/@storybook/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.2-canary.253f8c1.0.tgz",
- "integrity": "sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1",
- "endent": "^2.0.1",
- "find-cache-dir": "^3.3.1",
- "flat-cache": "^3.0.4",
- "micromatch": "^4.0.2",
- "react-docgen-typescript": "^2.0.0",
- "tslib": "^2.0.0"
- },
- "dependencies": {
- "find-cache-dir": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
- "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- },
- "react-docgen-typescript": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz",
- "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==",
- "dev": true
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "tslib": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
- "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
- "dev": true
- }
- }
- },
- "@storybook/router": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.4.13.tgz",
- "integrity": "sha512-6KbIpSL8QhGglzGb+tWTvAF/2EVpmgwlU5VP6Xs3GANcOc3VeXWl1fcJD6CNPp2DHwjkblW+21dcoHqfljnTmg==",
- "dev": true,
- "requires": {
- "@storybook/client-logger": "6.4.13",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "history": "5.0.0",
- "lodash": "^4.17.21",
- "memoizerific": "^1.11.3",
- "qs": "^6.10.0",
- "react-router": "^6.0.0",
- "react-router-dom": "^6.0.0",
- "ts-dedent": "^2.0.0"
- },
- "dependencies": {
- "history": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/history/-/history-5.0.0.tgz",
- "integrity": "sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.7.6"
- }
- },
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "react-router": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.2.1.tgz",
- "integrity": "sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==",
- "dev": true,
- "requires": {
- "history": "^5.2.0"
- },
- "dependencies": {
- "history": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
- "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.7.6"
- }
- }
- }
- },
- "react-router-dom": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.2.1.tgz",
- "integrity": "sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==",
- "dev": true,
- "requires": {
- "history": "^5.2.0",
- "react-router": "6.2.1"
- },
- "dependencies": {
- "history": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/history/-/history-5.2.0.tgz",
- "integrity": "sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.7.6"
- }
- }
- }
- }
- }
- },
- "@storybook/semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==",
- "dev": true,
- "requires": {
- "core-js": "^3.6.5",
- "find-up": "^4.1.0"
- }
- },
- "@storybook/source-loader": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/source-loader/-/source-loader-6.4.13.tgz",
- "integrity": "sha512-3M2VRt/ABGpm2G9MxkWAufvacPFDdHl+gvkNOq4lRhFw8uAh78xoXb1n0heOOuYGtJbw1+UHNOh4ahZGCWYxJg==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "core-js": "^3.8.2",
- "estraverse": "^5.2.0",
- "global": "^4.4.0",
- "loader-utils": "^2.0.0",
- "lodash": "^4.17.21",
- "prettier": "<=2.3.0",
- "regenerator-runtime": "^0.13.7"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true
- }
- }
- },
- "@storybook/store": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/store/-/store-6.4.13.tgz",
- "integrity": "sha512-VUDYwn1PHTa92kaJFCWqP+QS5wsHO9us2prhHnD7k9qvvQrbxD2DewtGxdT7cRHbZI8jY5CiqMVKilZRaXSM3Q==",
- "dev": true,
- "requires": {
- "@storybook/addons": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/csf": "0.0.2--canary.87bc651.0",
- "core-js": "^3.8.2",
- "fast-deep-equal": "^3.1.3",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "memoizerific": "^1.11.3",
- "regenerator-runtime": "^0.13.7",
- "slash": "^3.0.0",
- "stable": "^0.1.8",
- "synchronous-promise": "^2.0.15",
- "ts-dedent": "^2.0.0",
- "util-deprecate": "^1.0.2"
- }
- },
- "@storybook/theming": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.4.13.tgz",
- "integrity": "sha512-oWRoNnvO4QnRnplZ74DVdU4k91eqw8y0Xqn6lzZBeC8hq6mYWldgfj1LZ24gJhVtEIa7ZKoyujGUygHaH8WXHw==",
- "dev": true,
- "requires": {
- "@emotion/core": "^10.1.1",
- "@emotion/is-prop-valid": "^0.8.6",
- "@emotion/styled": "^10.0.27",
- "@storybook/client-logger": "6.4.13",
- "core-js": "^3.8.2",
- "deep-object-diff": "^1.1.0",
- "emotion-theming": "^10.0.27",
- "global": "^4.4.0",
- "memoizerific": "^1.11.3",
- "polished": "^4.0.5",
- "resolve-from": "^5.0.0",
- "ts-dedent": "^2.0.0"
- },
- "dependencies": {
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- }
- }
- },
- "@storybook/ui": {
- "version": "6.4.13",
- "resolved": "https://registry.npmjs.org/@storybook/ui/-/ui-6.4.13.tgz",
- "integrity": "sha512-EvpWk2iHjfiWkuMuzYz5fXl4r7S9Q80EtFFVkaBEZfIoKjvIkxppGQ3kz892ZdXzuazzvni2qcb7OJA9S7AgLw==",
- "dev": true,
- "requires": {
- "@emotion/core": "^10.1.1",
- "@storybook/addons": "6.4.13",
- "@storybook/api": "6.4.13",
- "@storybook/channels": "6.4.13",
- "@storybook/client-logger": "6.4.13",
- "@storybook/components": "6.4.13",
- "@storybook/core-events": "6.4.13",
- "@storybook/router": "6.4.13",
- "@storybook/semver": "^7.3.2",
- "@storybook/theming": "6.4.13",
- "copy-to-clipboard": "^3.3.1",
- "core-js": "^3.8.2",
- "core-js-pure": "^3.8.2",
- "downshift": "^6.0.15",
- "emotion-theming": "^10.0.27",
- "fuse.js": "^3.6.1",
- "global": "^4.4.0",
- "lodash": "^4.17.21",
- "markdown-to-jsx": "^7.1.3",
- "memoizerific": "^1.11.3",
- "polished": "^4.0.5",
- "qs": "^6.10.0",
- "react-draggable": "^4.4.3",
- "react-helmet-async": "^1.0.7",
- "react-sizeme": "^3.0.1",
- "regenerator-runtime": "^0.13.7",
- "resolve-from": "^5.0.0",
- "store2": "^2.12.0"
- },
- "dependencies": {
- "qs": {
- "version": "6.10.3",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz",
- "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==",
- "dev": true,
- "requires": {
- "side-channel": "^1.0.4"
- }
- },
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
- "dev": true
- }
- }
- },
- "@surma/rollup-plugin-off-main-thread": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-1.4.2.tgz",
- "integrity": "sha512-yBMPqmd1yEJo/280PAMkychuaALyQ9Lkb5q1ck3mjJrFuEobIfhnQ4J3mbvBoISmR3SWMWV+cGB/I0lCQee79A==",
- "requires": {
- "ejs": "^2.6.1",
- "magic-string": "^0.25.0"
- }
- },
- "@svgr/babel-plugin-add-jsx-attribute": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz",
- "integrity": "sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg=="
- },
- "@svgr/babel-plugin-remove-jsx-attribute": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz",
- "integrity": "sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg=="
- },
- "@svgr/babel-plugin-remove-jsx-empty-expression": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz",
- "integrity": "sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA=="
- },
- "@svgr/babel-plugin-replace-jsx-attribute-value": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz",
- "integrity": "sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ=="
- },
- "@svgr/babel-plugin-svg-dynamic-title": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz",
- "integrity": "sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg=="
- },
- "@svgr/babel-plugin-svg-em-dimensions": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz",
- "integrity": "sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw=="
- },
- "@svgr/babel-plugin-transform-react-native-svg": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz",
- "integrity": "sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q=="
- },
- "@svgr/babel-plugin-transform-svg-component": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz",
- "integrity": "sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ=="
- },
- "@svgr/babel-preset": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-5.5.0.tgz",
- "integrity": "sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==",
- "requires": {
- "@svgr/babel-plugin-add-jsx-attribute": "^5.4.0",
- "@svgr/babel-plugin-remove-jsx-attribute": "^5.4.0",
- "@svgr/babel-plugin-remove-jsx-empty-expression": "^5.0.1",
- "@svgr/babel-plugin-replace-jsx-attribute-value": "^5.0.1",
- "@svgr/babel-plugin-svg-dynamic-title": "^5.4.0",
- "@svgr/babel-plugin-svg-em-dimensions": "^5.4.0",
- "@svgr/babel-plugin-transform-react-native-svg": "^5.4.0",
- "@svgr/babel-plugin-transform-svg-component": "^5.5.0"
- }
- },
- "@svgr/core": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/core/-/core-5.5.0.tgz",
- "integrity": "sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==",
- "requires": {
- "@svgr/plugin-jsx": "^5.5.0",
- "camelcase": "^6.2.0",
- "cosmiconfig": "^7.0.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
- "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg=="
- }
- }
- },
- "@svgr/hast-util-to-babel-ast": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz",
- "integrity": "sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==",
- "requires": {
- "@babel/types": "^7.12.6"
- }
- },
- "@svgr/plugin-jsx": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz",
- "integrity": "sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==",
- "requires": {
- "@babel/core": "^7.12.3",
- "@svgr/babel-preset": "^5.5.0",
- "@svgr/hast-util-to-babel-ast": "^5.5.0",
- "svg-parser": "^2.0.2"
- }
- },
- "@svgr/plugin-svgo": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz",
- "integrity": "sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==",
- "requires": {
- "cosmiconfig": "^7.0.0",
- "deepmerge": "^4.2.2",
- "svgo": "^1.2.2"
- }
- },
- "@svgr/webpack": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz",
- "integrity": "sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==",
- "requires": {
- "@babel/core": "^7.12.3",
- "@babel/plugin-transform-react-constant-elements": "^7.12.1",
- "@babel/preset-env": "^7.12.1",
- "@babel/preset-react": "^7.12.5",
- "@svgr/core": "^5.5.0",
- "@svgr/plugin-jsx": "^5.5.0",
- "@svgr/plugin-svgo": "^5.5.0",
- "loader-utils": "^2.0.0"
- }
- },
- "@testing-library/dom": {
- "version": "7.29.6",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.6.tgz",
- "integrity": "sha512-vzTsAXa439ptdvav/4lsKRcGpAQX7b6wBIqia7+iNzqGJ5zjswApxA6jDAsexrc6ue9krWcbh8o+LYkBXW+GCQ==",
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/runtime": "^7.12.5",
- "@types/aria-query": "^4.2.0",
- "aria-query": "^4.2.2",
- "chalk": "^4.1.0",
- "dom-accessibility-api": "^0.5.4",
- "lz-string": "^1.4.4",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "@testing-library/jest-dom": {
- "version": "5.11.9",
- "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz",
- "integrity": "sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==",
- "requires": {
- "@babel/runtime": "^7.9.2",
- "@types/testing-library__jest-dom": "^5.9.1",
- "aria-query": "^4.2.2",
- "chalk": "^3.0.0",
- "css": "^3.0.0",
- "css.escape": "^1.5.1",
- "lodash": "^4.17.15",
- "redent": "^3.0.0"
- }
- },
- "@testing-library/react": {
- "version": "11.2.5",
- "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.5.tgz",
- "integrity": "sha512-yEx7oIa/UWLe2F2dqK0FtMF9sJWNXD+2PPtp39BvE0Kh9MJ9Kl0HrZAgEuhUJR+Lx8Di6Xz+rKwSdEPY2UV8ZQ==",
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@testing-library/dom": "^7.28.1"
- }
- },
- "@testing-library/user-event": {
- "version": "12.7.3",
- "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-12.7.3.tgz",
- "integrity": "sha512-IdSHkWfbeSSJRFlldvHDWfVX0U18TbXIvLSGII+JbqkJrsflFr4OWlQIua0TvcVVJNna3BNrNvRSvpQ0yvSXlA==",
- "requires": {
- "@babel/runtime": "^7.12.5"
- }
- },
- "@tootallnate/once": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
- "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
- },
- "@types/anymatch": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz",
- "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA=="
- },
- "@types/aria-query": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz",
- "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg=="
- },
- "@types/babel__core": {
- "version": "7.1.12",
- "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz",
- "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==",
- "requires": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0",
- "@types/babel__generator": "*",
- "@types/babel__template": "*",
- "@types/babel__traverse": "*"
- }
- },
- "@types/babel__generator": {
- "version": "7.6.2",
- "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz",
- "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==",
- "requires": {
- "@babel/types": "^7.0.0"
- }
- },
- "@types/babel__template": {
- "version": "7.4.0",
- "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz",
- "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==",
- "requires": {
- "@babel/parser": "^7.1.0",
- "@babel/types": "^7.0.0"
- }
- },
- "@types/babel__traverse": {
- "version": "7.11.0",
- "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz",
- "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==",
- "requires": {
- "@babel/types": "^7.3.0"
- }
- },
- "@types/classnames": {
- "version": "2.2.11",
- "resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.2.11.tgz",
- "integrity": "sha512-2koNhpWm3DgWRp5tpkiJ8JGc1xTn2q0l+jUNUE7oMKXUf5NpI9AIdC4kbjGNFBdHtcxBD18LAksoudAVhFKCjw=="
- },
- "@types/color-convert": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.0.tgz",
- "integrity": "sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==",
- "dev": true,
- "requires": {
- "@types/color-name": "*"
- }
- },
- "@types/color-name": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
- "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
- "dev": true
- },
- "@types/eslint": {
- "version": "7.28.2",
- "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.28.2.tgz",
- "integrity": "sha512-KubbADPkfoU75KgKeKLsFHXnU4ipH7wYg0TRT33NK3N3yiu7jlFAAoygIWBV+KbuHx/G+AvuGX6DllnK35gfJA==",
- "requires": {
- "@types/estree": "*",
- "@types/json-schema": "*"
- }
- },
- "@types/estree": {
- "version": "0.0.50",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz",
- "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw=="
- },
- "@types/glob": {
- "version": "7.1.3",
- "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
- "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
- "requires": {
- "@types/minimatch": "*",
- "@types/node": "*"
- }
- },
- "@types/graceful-fs": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz",
- "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/hast": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
- "integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
- "dev": true,
- "requires": {
- "@types/unist": "*"
- }
- },
- "@types/hoist-non-react-statics": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
- "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
- "requires": {
- "@types/react": "*",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "@types/html-minifier-terser": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
- "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA=="
- },
- "@types/invariant": {
- "version": "2.2.34",
- "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz",
- "integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg=="
- },
- "@types/is-function": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@types/is-function/-/is-function-1.0.1.tgz",
- "integrity": "sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==",
- "dev": true
- },
- "@types/istanbul-lib-coverage": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
- "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw=="
- },
- "@types/istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
- "requires": {
- "@types/istanbul-lib-coverage": "*"
- }
- },
- "@types/istanbul-reports": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
- "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
- "requires": {
- "@types/istanbul-lib-report": "*"
- }
- },
- "@types/jest": {
- "version": "26.0.20",
- "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz",
- "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==",
- "requires": {
- "jest-diff": "^26.0.0",
- "pretty-format": "^26.0.0"
- }
- },
- "@types/jest-specific-snapshot": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/@types/jest-specific-snapshot/-/jest-specific-snapshot-0.5.5.tgz",
- "integrity": "sha512-AaPPw2tE8ewfjD6qGLkEd4DOfM6pPOK7ob/RSOe1Z8Oo70r9Jgo0SlWyfxslPAOvLfQukQtiVPm6DcnjSoZU5A==",
- "dev": true,
- "requires": {
- "@types/jest": "*"
- }
- },
- "@types/json-schema": {
- "version": "7.0.7",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz",
- "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA=="
- },
- "@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
- },
- "@types/mdast": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
- "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
- "requires": {
- "@types/unist": "*"
- }
- },
- "@types/minimatch": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
- "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA=="
- },
- "@types/minimist": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz",
- "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ=="
- },
- "@types/node": {
- "version": "14.14.31",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.31.tgz",
- "integrity": "sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g=="
- },
- "@types/node-fetch": {
- "version": "2.5.12",
- "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz",
- "integrity": "sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==",
- "dev": true,
- "requires": {
- "@types/node": "*",
- "form-data": "^3.0.0"
- },
- "dependencies": {
- "form-data": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
- "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
- "dev": true,
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- }
- }
- },
- "@types/normalize-package-data": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
- "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
- },
- "@types/npmlog": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/@types/npmlog/-/npmlog-4.1.4.tgz",
- "integrity": "sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==",
- "dev": true
- },
- "@types/overlayscrollbars": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.1.tgz",
- "integrity": "sha512-V25YHbSoKQN35UasHf0EKD9U2vcmexRSp78qa8UglxFH8H3D+adEa9zGZwrqpH4TdvqeMrgMqVqsLB4woAryrQ==",
- "dev": true
- },
- "@types/parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
- },
- "@types/parse5": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
- "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==",
- "dev": true
- },
- "@types/prettier": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.1.tgz",
- "integrity": "sha512-DxZZbyMAM9GWEzXL+BMZROWz9oo6A9EilwwOMET2UVu2uZTqMWS5S69KVtuVKaRjCUpcrOXRalet86/OpG4kqw=="
- },
- "@types/pretty-hrtime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz",
- "integrity": "sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==",
- "dev": true
- },
- "@types/prop-types": {
- "version": "15.7.3",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
- "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
- },
- "@types/q": {
- "version": "1.5.5",
- "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz",
- "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ=="
- },
- "@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
- "dev": true
- },
- "@types/react": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz",
- "integrity": "sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==",
- "requires": {
- "@types/prop-types": "*",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
- "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
- }
- }
- },
- "@types/react-redux": {
- "version": "7.1.16",
- "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
- "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
- "requires": {
- "@types/hoist-non-react-statics": "^3.3.0",
- "@types/react": "*",
- "hoist-non-react-statics": "^3.3.0",
- "redux": "^4.0.0"
- }
- },
- "@types/react-syntax-highlighter": {
- "version": "11.0.5",
- "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.5.tgz",
- "integrity": "sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-table": {
- "version": "6.8.7",
- "resolved": "https://registry.npmjs.org/@types/react-table/-/react-table-6.8.7.tgz",
- "integrity": "sha512-1U0xl47jk0BzE+HNHgxZYSLvtybSvnlLhOpW9Mfqf9iuRm/fGqgRab3TKivPCY6Tl7WPFM2hWEJ1GnsuSFc9AQ==",
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/react-transition-group": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
- "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==",
- "requires": {
- "@types/react": "*"
- }
- },
- "@types/resolve": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
- "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
- "requires": {
- "@types/node": "*"
- }
- },
- "@types/sinonjs__fake-timers": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.4.tgz",
- "integrity": "sha512-IFQTJARgMUBF+xVd2b+hIgXWrZEjND3vJtRCvIelcFB5SIXfjV4bOHbHJ0eXKh+0COrBRc8MqteKAz/j88rE0A==",
- "dev": true
- },
- "@types/sizzle": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz",
- "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==",
- "dev": true
- },
- "@types/source-list-map": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
- "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA=="
- },
- "@types/stack-utils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz",
- "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw=="
- },
- "@types/tapable": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz",
- "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA=="
- },
- "@types/testing-library__jest-dom": {
- "version": "5.9.5",
- "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz",
- "integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==",
- "requires": {
- "@types/jest": "*"
- }
- },
- "@types/uglify-js": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.12.0.tgz",
- "integrity": "sha512-sYAF+CF9XZ5cvEBkI7RtrG9g2GtMBkviTnBxYYyq+8BWvO4QtXfwwR6a2LFwCi4evMKZfpv6U43ViYvv17Wz3Q==",
- "requires": {
- "source-map": "^0.6.1"
- }
- },
- "@types/unist": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
- "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ=="
- },
- "@types/warning": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz",
- "integrity": "sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI="
- },
- "@types/webpack": {
- "version": "4.41.26",
- "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.26.tgz",
- "integrity": "sha512-7ZyTfxjCRwexh+EJFwRUM+CDB2XvgHl4vfuqf1ZKrgGvcS5BrNvPQqJh3tsZ0P6h6Aa1qClVHaJZszLPzpqHeA==",
- "requires": {
- "@types/anymatch": "*",
- "@types/node": "*",
- "@types/tapable": "*",
- "@types/uglify-js": "*",
- "@types/webpack-sources": "*",
- "source-map": "^0.6.0"
- }
- },
- "@types/webpack-env": {
- "version": "1.16.3",
- "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.3.tgz",
- "integrity": "sha512-9gtOPPkfyNoEqCQgx4qJKkuNm/x0R2hKR7fdl7zvTJyHnIisuE/LfvXOsYWL0o3qq6uiBnKZNNNzi3l0y/X+xw==",
- "dev": true
- },
- "@types/webpack-sources": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz",
- "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==",
- "requires": {
- "@types/node": "*",
- "@types/source-list-map": "*",
- "source-map": "^0.7.3"
- },
- "dependencies": {
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- }
- }
- },
- "@types/yargs": {
- "version": "15.0.13",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz",
- "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==",
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "@types/yargs-parser": {
- "version": "20.2.0",
- "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz",
- "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA=="
- },
- "@types/yauzl": {
- "version": "2.9.2",
- "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz",
- "integrity": "sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==",
- "dev": true,
- "optional": true,
- "requires": {
- "@types/node": "*"
- }
- },
- "@typescript-eslint/eslint-plugin": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
- "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
- "requires": {
- "@typescript-eslint/experimental-utils": "4.33.0",
- "@typescript-eslint/scope-manager": "4.33.0",
- "debug": "^4.3.1",
- "functional-red-black-tree": "^1.0.1",
- "ignore": "^5.1.8",
- "regexpp": "^3.1.0",
- "semver": "^7.3.5",
- "tsutils": "^3.21.0"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/experimental-utils": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
- "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
- "requires": {
- "@types/json-schema": "^7.0.7",
- "@typescript-eslint/scope-manager": "4.33.0",
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/typescript-estree": "4.33.0",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^3.0.0"
- },
- "dependencies": {
- "eslint-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
- "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
- "requires": {
- "eslint-visitor-keys": "^2.0.0"
- }
- }
- }
- },
- "@typescript-eslint/parser": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
- "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
- "requires": {
- "@typescript-eslint/scope-manager": "4.33.0",
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/typescript-estree": "4.33.0",
- "debug": "^4.3.1"
- }
- },
- "@typescript-eslint/scope-manager": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
- "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/visitor-keys": "4.33.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
- "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ=="
- },
- "@typescript-eslint/typescript-estree": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
- "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "@typescript-eslint/visitor-keys": "4.33.0",
- "debug": "^4.3.1",
- "globby": "^11.0.3",
- "is-glob": "^4.0.1",
- "semver": "^7.3.5",
- "tsutils": "^3.21.0"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "4.33.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
- "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
- "requires": {
- "@typescript-eslint/types": "4.33.0",
- "eslint-visitor-keys": "^2.0.0"
- }
- },
- "@webassemblyjs/ast": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
- "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==",
- "requires": {
- "@webassemblyjs/helper-module-context": "1.9.0",
- "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
- "@webassemblyjs/wast-parser": "1.9.0"
- }
- },
- "@webassemblyjs/floating-point-hex-parser": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz",
- "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA=="
- },
- "@webassemblyjs/helper-api-error": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz",
- "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw=="
- },
- "@webassemblyjs/helper-buffer": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz",
- "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA=="
- },
- "@webassemblyjs/helper-code-frame": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz",
- "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==",
- "requires": {
- "@webassemblyjs/wast-printer": "1.9.0"
- }
- },
- "@webassemblyjs/helper-fsm": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz",
- "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw=="
- },
- "@webassemblyjs/helper-module-context": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz",
- "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0"
- }
- },
- "@webassemblyjs/helper-wasm-bytecode": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz",
- "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw=="
- },
- "@webassemblyjs/helper-wasm-section": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz",
- "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-buffer": "1.9.0",
- "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
- "@webassemblyjs/wasm-gen": "1.9.0"
- }
- },
- "@webassemblyjs/ieee754": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz",
- "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==",
- "requires": {
- "@xtuc/ieee754": "^1.2.0"
- }
- },
- "@webassemblyjs/leb128": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz",
- "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==",
- "requires": {
- "@xtuc/long": "4.2.2"
- }
- },
- "@webassemblyjs/utf8": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz",
- "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w=="
- },
- "@webassemblyjs/wasm-edit": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz",
- "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-buffer": "1.9.0",
- "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
- "@webassemblyjs/helper-wasm-section": "1.9.0",
- "@webassemblyjs/wasm-gen": "1.9.0",
- "@webassemblyjs/wasm-opt": "1.9.0",
- "@webassemblyjs/wasm-parser": "1.9.0",
- "@webassemblyjs/wast-printer": "1.9.0"
- }
- },
- "@webassemblyjs/wasm-gen": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz",
- "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
- "@webassemblyjs/ieee754": "1.9.0",
- "@webassemblyjs/leb128": "1.9.0",
- "@webassemblyjs/utf8": "1.9.0"
- }
- },
- "@webassemblyjs/wasm-opt": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz",
- "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-buffer": "1.9.0",
- "@webassemblyjs/wasm-gen": "1.9.0",
- "@webassemblyjs/wasm-parser": "1.9.0"
- }
- },
- "@webassemblyjs/wasm-parser": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz",
- "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-api-error": "1.9.0",
- "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
- "@webassemblyjs/ieee754": "1.9.0",
- "@webassemblyjs/leb128": "1.9.0",
- "@webassemblyjs/utf8": "1.9.0"
- }
- },
- "@webassemblyjs/wast-parser": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz",
- "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/floating-point-hex-parser": "1.9.0",
- "@webassemblyjs/helper-api-error": "1.9.0",
- "@webassemblyjs/helper-code-frame": "1.9.0",
- "@webassemblyjs/helper-fsm": "1.9.0",
- "@xtuc/long": "4.2.2"
- }
- },
- "@webassemblyjs/wast-printer": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz",
- "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/wast-parser": "1.9.0",
- "@xtuc/long": "4.2.2"
- }
- },
- "@xtuc/ieee754": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
- "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
- },
- "@xtuc/long": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
- "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
- },
- "abab": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz",
- "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
- },
- "abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
- },
- "accepts": {
- "version": "1.3.7",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
- "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
- "requires": {
- "mime-types": "~2.1.24",
- "negotiator": "0.6.2"
- }
- },
- "acorn": {
- "version": "7.4.1",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
- "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
- },
- "acorn-globals": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
- "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
- "requires": {
- "acorn": "^7.1.1",
- "acorn-walk": "^7.1.1"
- }
- },
- "acorn-jsx": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
- "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng=="
- },
- "acorn-walk": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
- "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="
- },
- "address": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/address/-/address-1.1.2.tgz",
- "integrity": "sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA=="
- },
- "adjust-sourcemap-loader": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz",
- "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==",
- "requires": {
- "loader-utils": "^2.0.0",
- "regex-parser": "^2.2.11"
- }
- },
- "agent-base": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
- "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
- "requires": {
- "debug": "4"
- }
- },
- "aggregate-error": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
- "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
- "requires": {
- "clean-stack": "^2.0.0",
- "indent-string": "^4.0.0"
- }
- },
- "airbnb-js-shims": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/airbnb-js-shims/-/airbnb-js-shims-2.2.1.tgz",
- "integrity": "sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==",
- "dev": true,
- "requires": {
- "array-includes": "^3.0.3",
- "array.prototype.flat": "^1.2.1",
- "array.prototype.flatmap": "^1.2.1",
- "es5-shim": "^4.5.13",
- "es6-shim": "^0.35.5",
- "function.prototype.name": "^1.1.0",
- "globalthis": "^1.0.0",
- "object.entries": "^1.1.0",
- "object.fromentries": "^2.0.0 || ^1.0.0",
- "object.getownpropertydescriptors": "^2.0.3",
- "object.values": "^1.1.0",
- "promise.allsettled": "^1.0.0",
- "promise.prototype.finally": "^3.1.0",
- "string.prototype.matchall": "^4.0.0 || ^3.0.1",
- "string.prototype.padend": "^3.0.0",
- "string.prototype.padstart": "^3.0.0",
- "symbol.prototype.description": "^1.0.0"
- }
- },
- "ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- }
- },
- "ajv-errors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
- "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ=="
- },
- "ajv-keywords": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
- "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
- },
- "alphanum-sort": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
- "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
- },
- "amdefine": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
- },
- "ansi-align": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
- "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==",
- "dev": true,
- "requires": {
- "string-width": "^4.1.0"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "ansi-colors": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
- "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
- },
- "ansi-escapes": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
- "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
- "requires": {
- "type-fest": "^0.11.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
- "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ=="
- }
- }
- },
- "ansi-html": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
- "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4="
- },
- "ansi-html-community": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
- "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
- "dev": true
- },
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "ansi-to-html": {
- "version": "0.6.15",
- "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.6.15.tgz",
- "integrity": "sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==",
- "dev": true,
- "requires": {
- "entities": "^2.0.0"
- }
- },
- "anymatch": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
- "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "requires": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- }
- },
- "app-root-dir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz",
- "integrity": "sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=",
- "dev": true
- },
- "append-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
- "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
- "dev": true,
- "requires": {
- "buffer-equal": "^1.0.0"
- }
- },
- "aproba": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
- "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
- },
- "arch": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz",
- "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==",
- "dev": true
- },
- "are-we-there-yet": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
- "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
- "requires": {
- "delegates": "^1.0.0",
- "readable-stream": "^2.0.6"
- }
- },
- "argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "requires": {
- "sprintf-js": "~1.0.2"
- }
- },
- "aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
- "requires": {
- "@babel/runtime": "^7.10.2",
- "@babel/runtime-corejs3": "^7.10.2"
- }
- },
- "arity-n": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
- "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U="
- },
- "arr-diff": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
- "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA="
- },
- "arr-flatten": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
- },
- "arr-union": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
- "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ="
- },
- "array-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
- "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
- "dev": true
- },
- "array-flatten": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
- "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
- },
- "array-includes": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz",
- "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.2",
- "get-intrinsic": "^1.1.1",
- "is-string": "^1.0.5"
- }
- },
- "array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
- },
- "array-uniq": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
- },
- "array-unique": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
- "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg="
- },
- "array.prototype.flat": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz",
- "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "array.prototype.flatmap": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz",
- "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.1",
- "function-bind": "^1.1.1"
- }
- },
- "array.prototype.map": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/array.prototype.map/-/array.prototype.map-1.0.4.tgz",
- "integrity": "sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "es-array-method-boxes-properly": "^1.0.0",
- "is-string": "^1.0.7"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "arrify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
- "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
- },
- "asn1": {
- "version": "0.2.4",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
- "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
- "requires": {
- "safer-buffer": "~2.1.0"
- }
- },
- "asn1.js": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
- "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
- "requires": {
- "bn.js": "^4.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "safer-buffer": "^2.1.0"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "assert": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
- "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
- "requires": {
- "object-assign": "^4.1.1",
- "util": "0.10.3"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
- "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
- },
- "util": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
- "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
- "requires": {
- "inherits": "2.0.1"
- }
- }
- }
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
- },
- "assign-symbols": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
- "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
- },
- "ast-types": {
- "version": "0.14.2",
- "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz",
- "integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==",
- "dev": true,
- "requires": {
- "tslib": "^2.0.1"
- },
- "dependencies": {
- "tslib": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
- "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
- "dev": true
- }
- }
- },
- "ast-types-flow": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0="
- },
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
- },
- "async": {
- "version": "2.6.3",
- "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
- "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
- "requires": {
- "lodash": "^4.17.14"
- }
- },
- "async-each": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
- "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ=="
- },
- "async-foreach": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
- "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI="
- },
- "async-limiter": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
- "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "at-least-node": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
- "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
- },
- "atob": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
- "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
- },
- "autoprefixer": {
- "version": "9.8.6",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
- "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
- "requires": {
- "browserslist": "^4.12.0",
- "caniuse-lite": "^1.0.30001109",
- "colorette": "^1.2.1",
- "normalize-range": "^0.1.2",
- "num2fraction": "^1.2.2",
- "postcss": "^7.0.32",
- "postcss-value-parser": "^4.1.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- },
- "dependencies": {
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- }
- }
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- }
- }
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
- },
- "aws4": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
- "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
- },
- "axe-core": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.4.tgz",
- "integrity": "sha512-4Hk6iSA/H90rtiPoCpSkeJxNWCPBf7szwVvaUqrPdxo0j2Y04suHK9jPKXaE3WI7OET6wBSwsWw7FDc1DBq7iQ=="
- },
- "axios": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
- "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
- "requires": {
- "follow-redirects": "^1.14.4"
- }
- },
- "axobject-query": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
- "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA=="
- },
- "babel-eslint": {
- "version": "10.1.0",
- "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz",
- "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@babel/parser": "^7.7.0",
- "@babel/traverse": "^7.7.0",
- "@babel/types": "^7.7.0",
- "eslint-visitor-keys": "^1.0.0",
- "resolve": "^1.12.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "babel-extract-comments": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/babel-extract-comments/-/babel-extract-comments-1.0.0.tgz",
- "integrity": "sha512-qWWzi4TlddohA91bFwgt6zO/J0X+io7Qp184Fw0m2JYRSTZnJbFR8+07KmzudHCZgOiKRCrjhylwv9Xd8gfhVQ==",
- "requires": {
- "babylon": "^6.18.0"
- }
- },
- "babel-jest": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz",
- "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==",
- "requires": {
- "@jest/transform": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/babel__core": "^7.1.7",
- "babel-plugin-istanbul": "^6.0.0",
- "babel-preset-jest": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "slash": "^3.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "babel-loader": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz",
- "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==",
- "requires": {
- "find-cache-dir": "^2.1.0",
- "loader-utils": "^1.4.0",
- "mkdirp": "^0.5.3",
- "pify": "^4.0.1",
- "schema-utils": "^2.6.5"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- }
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- }
- }
- },
- "babel-plugin-add-react-displayname": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz",
- "integrity": "sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=",
- "dev": true
- },
- "babel-plugin-apply-mdx-type-prop": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/babel-plugin-apply-mdx-type-prop/-/babel-plugin-apply-mdx-type-prop-1.6.22.tgz",
- "integrity": "sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "7.10.4",
- "@mdx-js/util": "1.6.22"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
- "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
- "dev": true
- }
- }
- },
- "babel-plugin-dynamic-import-node": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
- "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==",
- "requires": {
- "object.assign": "^4.1.0"
- }
- },
- "babel-plugin-emotion": {
- "version": "10.2.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz",
- "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==",
- "dev": true,
- "requires": {
- "@babel/helper-module-imports": "^7.0.0",
- "@emotion/hash": "0.8.0",
- "@emotion/memoize": "0.7.4",
- "@emotion/serialize": "^0.11.16",
- "babel-plugin-macros": "^2.0.0",
- "babel-plugin-syntax-jsx": "^6.18.0",
- "convert-source-map": "^1.5.0",
- "escape-string-regexp": "^1.0.5",
- "find-root": "^1.1.0",
- "source-map": "^0.5.7"
- },
- "dependencies": {
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- }
- }
- },
- "babel-plugin-extract-import-names": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz",
- "integrity": "sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "7.10.4"
- },
- "dependencies": {
- "@babel/helper-plugin-utils": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
- "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
- "dev": true
- }
- }
- },
- "babel-plugin-istanbul": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz",
- "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "@istanbuljs/load-nyc-config": "^1.0.0",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-instrument": "^4.0.0",
- "test-exclude": "^6.0.0"
- }
- },
- "babel-plugin-jest-hoist": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz",
- "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==",
- "requires": {
- "@babel/template": "^7.3.3",
- "@babel/types": "^7.3.3",
- "@types/babel__core": "^7.0.0",
- "@types/babel__traverse": "^7.0.6"
- }
- },
- "babel-plugin-macros": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz",
- "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==",
- "requires": {
- "@babel/runtime": "^7.7.2",
- "cosmiconfig": "^6.0.0",
- "resolve": "^1.12.0"
- },
- "dependencies": {
- "cosmiconfig": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
- "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.1.0",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.7.2"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- }
- }
- },
- "babel-plugin-named-asset-import": {
- "version": "0.3.7",
- "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.7.tgz",
- "integrity": "sha512-squySRkf+6JGnvjoUtDEjSREJEBirnXi9NqP6rjSYsylxQxqBTz+pkmf395i9E2zsvmYUaI40BHo6SqZUdydlw=="
- },
- "babel-plugin-polyfill-corejs2": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.1.6.tgz",
- "integrity": "sha512-1PfghLDuzX5lFY6XXO0hrfxwYf0LD9YajMWeQBGNaPNLQ35paV7YB4hlFW+HfwFS5kcp4rtPI/237xLfQ1ah8A==",
- "requires": {
- "@babel/compat-data": "^7.13.0",
- "@babel/helper-define-polyfill-provider": "^0.1.2",
- "semver": "^6.1.1"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "babel-plugin-polyfill-corejs3": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.1.4.tgz",
- "integrity": "sha512-ysSzFn/qM8bvcDAn4mC7pKk85Y5dVaoa9h4u0mHxOEpDzabsseONhUpR7kHxpUinfj1bjU7mUZqD23rMZBoeSg==",
- "requires": {
- "@babel/helper-define-polyfill-provider": "^0.1.2",
- "core-js-compat": "^3.8.1"
- }
- },
- "babel-plugin-polyfill-regenerator": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.1.3.tgz",
- "integrity": "sha512-hRjTJQiOYt/wBKEc+8V8p9OJ9799blAJcuKzn1JXh3pApHoWl1Emxh2BHc6MC7Qt6bbr3uDpNxaYQnATLIudEg==",
- "requires": {
- "@babel/helper-define-polyfill-provider": "^0.1.2"
- }
- },
- "babel-plugin-react-docgen": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz",
- "integrity": "sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==",
- "dev": true,
- "requires": {
- "ast-types": "^0.14.2",
- "lodash": "^4.17.15",
- "react-docgen": "^5.0.0"
- }
- },
- "babel-plugin-syntax-jsx": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
- "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
- "dev": true
- },
- "babel-plugin-syntax-object-rest-spread": {
- "version": "6.13.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
- "integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U="
- },
- "babel-plugin-transform-object-rest-spread": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
- "integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
- "requires": {
- "babel-plugin-syntax-object-rest-spread": "^6.8.0",
- "babel-runtime": "^6.26.0"
- }
- },
- "babel-plugin-transform-react-remove-prop-types": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz",
- "integrity": "sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA=="
- },
- "babel-preset-current-node-syntax": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
- "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
- "requires": {
- "@babel/plugin-syntax-async-generators": "^7.8.4",
- "@babel/plugin-syntax-bigint": "^7.8.3",
- "@babel/plugin-syntax-class-properties": "^7.8.3",
- "@babel/plugin-syntax-import-meta": "^7.8.3",
- "@babel/plugin-syntax-json-strings": "^7.8.3",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
- "@babel/plugin-syntax-numeric-separator": "^7.8.3",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
- "@babel/plugin-syntax-optional-chaining": "^7.8.3",
- "@babel/plugin-syntax-top-level-await": "^7.8.3"
- }
- },
- "babel-preset-jest": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz",
- "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==",
- "requires": {
- "babel-plugin-jest-hoist": "^26.6.2",
- "babel-preset-current-node-syntax": "^1.0.0"
- }
- },
- "babel-preset-react-app": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/babel-preset-react-app/-/babel-preset-react-app-10.0.0.tgz",
- "integrity": "sha512-itL2z8v16khpuKutx5IH8UdCdSTuzrOhRFTEdIhveZ2i1iBKDrVE0ATa4sFVy+02GLucZNVBWtoarXBy0Msdpg==",
- "requires": {
- "@babel/core": "7.12.3",
- "@babel/plugin-proposal-class-properties": "7.12.1",
- "@babel/plugin-proposal-decorators": "7.12.1",
- "@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1",
- "@babel/plugin-proposal-numeric-separator": "7.12.1",
- "@babel/plugin-proposal-optional-chaining": "7.12.1",
- "@babel/plugin-transform-flow-strip-types": "7.12.1",
- "@babel/plugin-transform-react-display-name": "7.12.1",
- "@babel/plugin-transform-runtime": "7.12.1",
- "@babel/preset-env": "7.12.1",
- "@babel/preset-react": "7.12.1",
- "@babel/preset-typescript": "7.12.1",
- "@babel/runtime": "7.12.1",
- "babel-plugin-macros": "2.8.0",
- "babel-plugin-transform-react-remove-prop-types": "0.4.24"
- },
- "dependencies": {
- "@babel/plugin-proposal-class-properties": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz",
- "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==",
- "requires": {
- "@babel/helper-create-class-features-plugin": "^7.12.1",
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-nullish-coalescing-operator": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz",
- "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
- }
- },
- "@babel/plugin-proposal-numeric-separator": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.1.tgz",
- "integrity": "sha512-MR7Ok+Af3OhNTCxYVjJZHS0t97ydnJZt/DbR4WISO39iDnhiD8XHrY12xuSJ90FFEGjir0Fzyyn7g/zY6hxbxA==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4"
- }
- },
- "@babel/plugin-proposal-optional-chaining": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz",
- "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1",
- "@babel/plugin-syntax-optional-chaining": "^7.8.0"
- }
- },
- "@babel/plugin-transform-react-display-name": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.12.1.tgz",
- "integrity": "sha512-cAzB+UzBIrekfYxyLlFqf/OagTvHLcVBb5vpouzkYkBclRPraiygVnafvAoipErZLI8ANv8Ecn6E/m5qPXD26w==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "@babel/preset-env": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.1.tgz",
- "integrity": "sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg==",
- "requires": {
- "@babel/compat-data": "^7.12.1",
- "@babel/helper-compilation-targets": "^7.12.1",
- "@babel/helper-module-imports": "^7.12.1",
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/helper-validator-option": "^7.12.1",
- "@babel/plugin-proposal-async-generator-functions": "^7.12.1",
- "@babel/plugin-proposal-class-properties": "^7.12.1",
- "@babel/plugin-proposal-dynamic-import": "^7.12.1",
- "@babel/plugin-proposal-export-namespace-from": "^7.12.1",
- "@babel/plugin-proposal-json-strings": "^7.12.1",
- "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1",
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1",
- "@babel/plugin-proposal-numeric-separator": "^7.12.1",
- "@babel/plugin-proposal-object-rest-spread": "^7.12.1",
- "@babel/plugin-proposal-optional-catch-binding": "^7.12.1",
- "@babel/plugin-proposal-optional-chaining": "^7.12.1",
- "@babel/plugin-proposal-private-methods": "^7.12.1",
- "@babel/plugin-proposal-unicode-property-regex": "^7.12.1",
- "@babel/plugin-syntax-async-generators": "^7.8.0",
- "@babel/plugin-syntax-class-properties": "^7.12.1",
- "@babel/plugin-syntax-dynamic-import": "^7.8.0",
- "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
- "@babel/plugin-syntax-json-strings": "^7.8.0",
- "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
- "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
- "@babel/plugin-syntax-numeric-separator": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
- "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
- "@babel/plugin-syntax-optional-chaining": "^7.8.0",
- "@babel/plugin-syntax-top-level-await": "^7.12.1",
- "@babel/plugin-transform-arrow-functions": "^7.12.1",
- "@babel/plugin-transform-async-to-generator": "^7.12.1",
- "@babel/plugin-transform-block-scoped-functions": "^7.12.1",
- "@babel/plugin-transform-block-scoping": "^7.12.1",
- "@babel/plugin-transform-classes": "^7.12.1",
- "@babel/plugin-transform-computed-properties": "^7.12.1",
- "@babel/plugin-transform-destructuring": "^7.12.1",
- "@babel/plugin-transform-dotall-regex": "^7.12.1",
- "@babel/plugin-transform-duplicate-keys": "^7.12.1",
- "@babel/plugin-transform-exponentiation-operator": "^7.12.1",
- "@babel/plugin-transform-for-of": "^7.12.1",
- "@babel/plugin-transform-function-name": "^7.12.1",
- "@babel/plugin-transform-literals": "^7.12.1",
- "@babel/plugin-transform-member-expression-literals": "^7.12.1",
- "@babel/plugin-transform-modules-amd": "^7.12.1",
- "@babel/plugin-transform-modules-commonjs": "^7.12.1",
- "@babel/plugin-transform-modules-systemjs": "^7.12.1",
- "@babel/plugin-transform-modules-umd": "^7.12.1",
- "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1",
- "@babel/plugin-transform-new-target": "^7.12.1",
- "@babel/plugin-transform-object-super": "^7.12.1",
- "@babel/plugin-transform-parameters": "^7.12.1",
- "@babel/plugin-transform-property-literals": "^7.12.1",
- "@babel/plugin-transform-regenerator": "^7.12.1",
- "@babel/plugin-transform-reserved-words": "^7.12.1",
- "@babel/plugin-transform-shorthand-properties": "^7.12.1",
- "@babel/plugin-transform-spread": "^7.12.1",
- "@babel/plugin-transform-sticky-regex": "^7.12.1",
- "@babel/plugin-transform-template-literals": "^7.12.1",
- "@babel/plugin-transform-typeof-symbol": "^7.12.1",
- "@babel/plugin-transform-unicode-escapes": "^7.12.1",
- "@babel/plugin-transform-unicode-regex": "^7.12.1",
- "@babel/preset-modules": "^0.1.3",
- "@babel/types": "^7.12.1",
- "core-js-compat": "^3.6.2",
- "semver": "^5.5.0"
- }
- },
- "@babel/preset-react": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.12.1.tgz",
- "integrity": "sha512-euCExymHCi0qB9u5fKw7rvlw7AZSjw/NaB9h7EkdTt5+yHRrXdiRTh7fkG3uBPpJg82CqLfp1LHLqWGSCrab+g==",
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-transform-react-display-name": "^7.12.1",
- "@babel/plugin-transform-react-jsx": "^7.12.1",
- "@babel/plugin-transform-react-jsx-development": "^7.12.1",
- "@babel/plugin-transform-react-jsx-self": "^7.12.1",
- "@babel/plugin-transform-react-jsx-source": "^7.12.1",
- "@babel/plugin-transform-react-pure-annotations": "^7.12.1"
- }
- },
- "@babel/runtime": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz",
- "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==",
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- }
- }
- },
- "babel-runtime": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
- "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "requires": {
- "core-js": "^2.4.0",
- "regenerator-runtime": "^0.11.0"
- },
- "dependencies": {
- "core-js": {
- "version": "2.6.12",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
- "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
- },
- "regenerator-runtime": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
- "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
- }
- }
- },
- "babylon": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
- },
- "bail": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
- "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ=="
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "base": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
- "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
- "requires": {
- "cache-base": "^1.0.1",
- "class-utils": "^0.3.5",
- "component-emitter": "^1.2.1",
- "define-property": "^1.0.0",
- "isobject": "^3.0.1",
- "mixin-deep": "^1.2.0",
- "pascalcase": "^0.1.1"
- },
- "dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "requires": {
- "is-descriptor": "^1.0.0"
- }
- },
- "is-accessor-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
- "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-data-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
- "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-descriptor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
- "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
- "requires": {
- "is-accessor-descriptor": "^1.0.0",
- "is-data-descriptor": "^1.0.0",
- "kind-of": "^6.0.2"
- }
- }
- }
- },
- "base64-arraybuffer": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
- "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ=="
- },
- "base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
- },
- "batch": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
- "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
- },
- "batch-processor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz",
- "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=",
- "dev": true
- },
- "bcrypt-pbkdf": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
- "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
- "requires": {
- "tweetnacl": "^0.14.3"
- }
- },
- "better-opn": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-2.1.1.tgz",
- "integrity": "sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==",
- "dev": true,
- "requires": {
- "open": "^7.0.3"
- }
- },
- "bfj": {
- "version": "7.0.2",
- "resolved": "https://registry.npmjs.org/bfj/-/bfj-7.0.2.tgz",
- "integrity": "sha512-+e/UqUzwmzJamNF50tBV6tZPTORow7gQ96iFow+8b562OdMpEK0BcJEq2OSPEDmAbSMBQ7PKZ87ubFkgxpYWgw==",
- "requires": {
- "bluebird": "^3.5.5",
- "check-types": "^11.1.1",
- "hoopy": "^0.1.4",
- "tryer": "^1.0.1"
- }
- },
- "big.js": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
- "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
- },
- "binary-extensions": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
- "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
- },
- "blob-util": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz",
- "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==",
- "dev": true
- },
- "bluebird": {
- "version": "3.7.2",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
- "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
- },
- "blueimp-canvas-to-blob": {
- "version": "3.28.0",
- "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.28.0.tgz",
- "integrity": "sha512-5q+YHzgGsuHQ01iouGgJaPJXod2AzTxJXmVv90PpGrRxU7G7IqgPqWXz+PBmt3520jKKi6irWbNV87DicEa7wg=="
- },
- "bn.js": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
- "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw=="
- },
- "body-parser": {
- "version": "1.19.0",
- "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
- "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
- "requires": {
- "bytes": "3.1.0",
- "content-type": "~1.0.4",
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "http-errors": "1.7.2",
- "iconv-lite": "0.4.24",
- "on-finished": "~2.3.0",
- "qs": "6.7.0",
- "raw-body": "2.4.0",
- "type-is": "~1.6.17"
- },
- "dependencies": {
- "bytes": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
- "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "qs": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
- "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
- }
- }
- },
- "bonjour": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
- "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
- "requires": {
- "array-flatten": "^2.1.0",
- "deep-equal": "^1.0.1",
- "dns-equal": "^1.0.0",
- "dns-txt": "^2.0.2",
- "multicast-dns": "^6.0.1",
- "multicast-dns-service-types": "^1.1.0"
- }
- },
- "boolbase": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
- "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
- },
- "bootstrap": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.0.tgz",
- "integrity": "sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw=="
- },
- "boxen": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz",
- "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==",
- "dev": true,
- "requires": {
- "ansi-align": "^3.0.0",
- "camelcase": "^6.2.0",
- "chalk": "^4.1.0",
- "cli-boxes": "^2.2.1",
- "string-width": "^4.2.2",
- "type-fest": "^0.20.2",
- "widest-line": "^3.1.0",
- "wrap-ansi": "^7.0.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
- "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
- "dev": true
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "requires": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "requires": {
- "fill-range": "^7.0.1"
- }
- },
- "broccoli-plugin": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz",
- "integrity": "sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ==",
- "dev": true,
- "requires": {
- "promise-map-series": "^0.2.1",
- "quick-temp": "^0.1.3",
- "rimraf": "^2.3.4",
- "symlink-or-copy": "^1.1.8"
- },
- "dependencies": {
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "brorand": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
- "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
- },
- "browser-process-hrtime": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
- "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
- },
- "browser-resolve": {
- "version": "1.11.3",
- "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
- "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
- "dev": true,
- "requires": {
- "resolve": "1.1.7"
- },
- "dependencies": {
- "resolve": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
- "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
- "dev": true
- }
- }
- },
- "browserify-aes": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
- "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
- "requires": {
- "buffer-xor": "^1.0.3",
- "cipher-base": "^1.0.0",
- "create-hash": "^1.1.0",
- "evp_bytestokey": "^1.0.3",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "browserify-cipher": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
- "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
- "requires": {
- "browserify-aes": "^1.0.4",
- "browserify-des": "^1.0.0",
- "evp_bytestokey": "^1.0.0"
- }
- },
- "browserify-des": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
- "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
- "requires": {
- "cipher-base": "^1.0.1",
- "des.js": "^1.0.0",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.1.2"
- }
- },
- "browserify-rsa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz",
- "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==",
- "requires": {
- "bn.js": "^5.0.0",
- "randombytes": "^2.0.1"
- }
- },
- "browserify-sign": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
- "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
- "requires": {
- "bn.js": "^5.1.1",
- "browserify-rsa": "^4.0.1",
- "create-hash": "^1.2.0",
- "create-hmac": "^1.1.7",
- "elliptic": "^6.5.3",
- "inherits": "^2.0.4",
- "parse-asn1": "^5.1.5",
- "readable-stream": "^3.6.0",
- "safe-buffer": "^5.2.0"
- },
- "dependencies": {
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- }
- }
- },
- "browserify-zlib": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
- "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
- "requires": {
- "pako": "~1.0.5"
- }
- },
- "browserslist": {
- "version": "4.14.2",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.2.tgz",
- "integrity": "sha512-HI4lPveGKUR0x2StIz+2FXfDk9SfVMrxn6PLh1JeGUwcuoDkdKZebWiyLRJ68iIPDpMI4JLVDf7S7XzslgWOhw==",
- "requires": {
- "caniuse-lite": "^1.0.30001125",
- "electron-to-chromium": "^1.3.564",
- "escalade": "^3.0.2",
- "node-releases": "^1.1.61"
- }
- },
- "bser": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
- "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
- "requires": {
- "node-int64": "^0.4.0"
- }
- },
- "buffer": {
- "version": "4.9.2",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
- "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
- "requires": {
- "base64-js": "^1.0.2",
- "ieee754": "^1.1.4",
- "isarray": "^1.0.0"
- }
- },
- "buffer-crc32": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
- "dev": true
- },
- "buffer-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
- "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
- "dev": true
- },
- "buffer-equal-constant-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
- "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
- },
- "buffer-from": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
- "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
- },
- "buffer-indexof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
- "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
- },
- "buffer-xor": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
- "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
- },
- "builtin-modules": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
- "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA=="
- },
- "builtin-status-codes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
- "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
- },
- "bytes": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
- "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
- },
- "c8": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/c8/-/c8-7.8.0.tgz",
- "integrity": "sha512-x2Bx+IIEd608B1LmjiNQ/kizRPkCWo5XzuV57J9afPjAHSnYXALwbCSOkQ7cSaNXBNblfqcvdycj+klmL+j6yA==",
- "dev": true,
- "requires": {
- "@bcoe/v8-coverage": "^0.2.3",
- "@istanbuljs/schema": "^0.1.2",
- "find-up": "^5.0.0",
- "foreground-child": "^2.0.0",
- "istanbul-lib-coverage": "^3.0.0",
- "istanbul-lib-report": "^3.0.0",
- "istanbul-reports": "^3.0.2",
- "rimraf": "^3.0.0",
- "test-exclude": "^6.0.0",
- "v8-to-istanbul": "^8.0.0",
- "yargs": "^16.2.0",
- "yargs-parser": "^20.2.7"
- },
- "dependencies": {
- "cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "dev": true,
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "requires": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "requires": {
- "p-locate": "^5.0.0"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "requires": {
- "p-limit": "^3.0.2"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz",
- "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "v8-to-istanbul": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.0.0.tgz",
- "integrity": "sha512-LkmXi8UUNxnCC+JlH7/fsfsKr5AU110l+SYGJimWNkWhxbN5EyeOtm1MJ0hhvqMMOhGwBj1Fp70Yv9i+hX0QAg==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0",
- "source-map": "^0.7.3"
- }
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "y18n": {
- "version": "5.0.8",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
- "dev": true
- },
- "yargs": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
- "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
- "dev": true,
- "requires": {
- "cliui": "^7.0.2",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.0",
- "y18n": "^5.0.5",
- "yargs-parser": "^20.2.2"
- }
- },
- "yargs-parser": {
- "version": "20.2.9",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
- "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
- "dev": true
- }
- }
- },
- "cacache": {
- "version": "15.0.5",
- "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz",
- "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==",
- "requires": {
- "@npmcli/move-file": "^1.0.1",
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "glob": "^7.1.4",
- "infer-owner": "^1.0.4",
- "lru-cache": "^6.0.0",
- "minipass": "^3.1.1",
- "minipass-collect": "^1.0.2",
- "minipass-flush": "^1.0.5",
- "minipass-pipeline": "^1.2.2",
- "mkdirp": "^1.0.3",
- "p-map": "^4.0.0",
- "promise-inflight": "^1.0.1",
- "rimraf": "^3.0.2",
- "ssri": "^8.0.0",
- "tar": "^6.0.2",
- "unique-filename": "^1.1.1"
- },
- "dependencies": {
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
- },
- "ssri": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
- "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
- "requires": {
- "minipass": "^3.1.1"
- }
- }
- }
- },
- "cache-base": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
- "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
- "requires": {
- "collection-visit": "^1.0.0",
- "component-emitter": "^1.2.1",
- "get-value": "^2.0.6",
- "has-value": "^1.0.0",
- "isobject": "^3.0.1",
- "set-value": "^2.0.0",
- "to-object-path": "^0.3.0",
- "union-value": "^1.0.0",
- "unset-value": "^1.0.0"
- },
- "dependencies": {
- "set-value": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
- "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==",
- "requires": {
- "is-plain-object": "^2.0.4",
- "is-primitive": "^3.0.1"
- }
- }
- }
- },
- "cachedir": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz",
- "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==",
- "dev": true
- },
- "call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "requires": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- }
- },
- "call-me-maybe": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
- "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
- "dev": true
- },
- "caller-callsite": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
- "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
- "requires": {
- "callsites": "^2.0.0"
- },
- "dependencies": {
- "callsites": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
- "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
- }
- }
- },
- "caller-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
- "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
- "requires": {
- "caller-callsite": "^2.0.0"
- }
- },
- "callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
- },
- "camel-case": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz",
- "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==",
- "requires": {
- "pascal-case": "^3.1.2",
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "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==",
- "dev": true
- },
- "camelcase-keys": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
- "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
- "requires": {
- "camelcase": "^5.3.1",
- "map-obj": "^4.0.0",
- "quick-lru": "^4.0.1"
- }
- },
- "caniuse-api": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
- "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
- "requires": {
- "browserslist": "^4.0.0",
- "caniuse-lite": "^1.0.0",
- "lodash.memoize": "^4.1.2",
- "lodash.uniq": "^4.5.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- },
- "dependencies": {
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- }
- }
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- }
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001191",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001191.tgz",
- "integrity": "sha512-xJJqzyd+7GCJXkcoBiQ1GuxEiOBCLQ0aVW9HMekifZsAVGdj5eJ4mFB9fEhSHipq9IOk/QXFJUiIr9lZT+EsGw=="
- },
- "capture-exit": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
- "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==",
- "requires": {
- "rsvp": "^4.8.4"
- }
- },
- "case-sensitive-paths-webpack-plugin": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.3.0.tgz",
- "integrity": "sha512-/4YgnZS8y1UXXmC02xD5rRrBEu6T5ub+mQHLNRj0fzTRbgdBYhsNo2V5EqwgqrExjxsjtF/OpAKAMkKsxbD5XQ=="
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
- },
- "ccount": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.1.0.tgz",
- "integrity": "sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==",
- "dev": true
- },
- "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"
- }
- },
- "char-regex": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
- "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="
- },
- "character-entities": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
- "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw=="
- },
- "character-entities-legacy": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
- "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
- },
- "character-reference-invalid": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
- "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg=="
- },
- "chart.js": {
- "version": "2.9.4",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz",
- "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==",
- "requires": {
- "chartjs-color": "^2.1.0",
- "moment": "^2.10.2"
- }
- },
- "chartjs-color": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz",
- "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==",
- "requires": {
- "chartjs-color-string": "^0.6.0",
- "color-convert": "^1.9.3"
- },
- "dependencies": {
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- }
- }
- },
- "chartjs-color-string": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
- "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
- "requires": {
- "color-name": "^1.0.0"
- }
- },
- "chartkick": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/chartkick/-/chartkick-3.2.1.tgz",
- "integrity": "sha512-zV0kUeZNqrX28AmPt10QEDXHKadbVFOTAFkCMyJifHzGFkKzGCDXxVR8orZ0fC1HbePzRn5w6kLCOVxDQbMUCg=="
- },
- "check-more-types": {
- "version": "2.24.0",
- "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz",
- "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=",
- "dev": true
- },
- "check-types": {
- "version": "11.1.2",
- "resolved": "https://registry.npmjs.org/check-types/-/check-types-11.1.2.tgz",
- "integrity": "sha512-tzWzvgePgLORb9/3a0YenggReLKAIb2owL03H2Xdoe5pKcUyWRSEQ8xfCar8t2SIAuEDwtmx2da1YB52YuHQMQ=="
- },
- "cheerio": {
- "version": "1.0.0-rc.10",
- "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz",
- "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==",
- "dev": true,
- "requires": {
- "cheerio-select": "^1.5.0",
- "dom-serializer": "^1.3.2",
- "domhandler": "^4.2.0",
- "htmlparser2": "^6.1.0",
- "parse5": "^6.0.1",
- "parse5-htmlparser2-tree-adapter": "^6.0.1",
- "tslib": "^2.2.0"
- },
- "dependencies": {
- "dom-serializer": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz",
- "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==",
- "dev": true,
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.2.0",
- "entities": "^2.0.0"
- }
- },
- "domhandler": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz",
- "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==",
- "dev": true,
- "requires": {
- "domelementtype": "^2.2.0"
- },
- "dependencies": {
- "domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
- "dev": true
- }
- }
- },
- "domutils": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
- "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
- "dev": true,
- "requires": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0"
- },
- "dependencies": {
- "domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
- "dev": true
- }
- }
- },
- "htmlparser2": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
- "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
- "dev": true,
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "domutils": "^2.5.2",
- "entities": "^2.0.0"
- }
- },
- "tslib": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
- "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
- "dev": true
- }
- }
- },
- "cheerio-select": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz",
- "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==",
- "dev": true,
- "requires": {
- "css-select": "^4.1.3",
- "css-what": "^5.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0",
- "domutils": "^2.7.0"
- },
- "dependencies": {
- "css-select": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
- "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==",
- "dev": true,
- "requires": {
- "boolbase": "^1.0.0",
- "css-what": "^5.0.0",
- "domhandler": "^4.2.0",
- "domutils": "^2.6.0",
- "nth-check": "^2.0.0"
- },
- "dependencies": {
- "nth-check": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
- "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
- "dev": true,
- "requires": {
- "boolbase": "^1.0.0"
- }
- }
- }
- },
- "css-what": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
- "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==",
- "dev": true
- },
- "domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==",
- "dev": true
- },
- "domhandler": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz",
- "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==",
- "dev": true,
- "requires": {
- "domelementtype": "^2.2.0"
- }
- },
- "domutils": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
- "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
- "dev": true,
- "requires": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0"
- }
- },
- "nth-check": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
- "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
- "requires": {
- "boolbase": "^1.0.0"
- }
- }
- }
- },
- "chokidar": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
- "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
- "requires": {
- "anymatch": "~3.1.1",
- "braces": "~3.0.2",
- "fsevents": "~2.3.1",
- "glob-parent": "~5.1.0",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.5.0"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "requires": {
- "is-glob": "^4.0.3"
- },
- "dependencies": {
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- }
- }
- }
- }
- },
- "chownr": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
- },
- "chromatic": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/chromatic/-/chromatic-6.0.4.tgz",
- "integrity": "sha512-kMoopZ9+7F/pumCgNoyTRHumVU0+alnccmt6n0inQcbcIc1REJ0ZHyjT47LBSwnQLjo/Vz0dGU7mFEc84bkNrQ==",
- "dev": true
- },
- "chrome-trace-event": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
- "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
- "requires": {
- "tslib": "^1.9.0"
- }
- },
- "ci-info": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
- },
- "cipher-base": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
- "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
- "requires": {
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "cjs-module-lexer": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz",
- "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw=="
- },
- "class-utils": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
- "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
- "requires": {
- "arr-union": "^3.1.0",
- "define-property": "^0.2.5",
- "isobject": "^3.0.0",
- "static-extend": "^0.1.1"
- },
- "dependencies": {
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- }
- }
- },
- "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",
- "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
- "requires": {
- "source-map": "~0.6.0"
- }
- },
- "clean-stack": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
- "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
- },
- "cleave.js": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/cleave.js/-/cleave.js-1.6.0.tgz",
- "integrity": "sha512-ivqesy3j5hQVG3gywPfwKPbi/7ZSftY/UNp5uphnqjr25yI2CP8FS2ODQPzuLXXnNLi29e2+PgPkkiKUXLs/Nw=="
- },
- "cli-boxes": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
- "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
- "dev": true
- },
- "cli-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
- "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
- "dev": true,
- "requires": {
- "restore-cursor": "^3.1.0"
- }
- },
- "cli-table3": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.0.tgz",
- "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==",
- "dev": true,
- "requires": {
- "colors": "^1.1.2",
- "object-assign": "^4.1.0",
- "string-width": "^4.2.0"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "dev": true,
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "cliui": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
- "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
- "requires": {
- "string-width": "^3.1.0",
- "strip-ansi": "^5.2.0",
- "wrap-ansi": "^5.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "requires": {
- "ansi-regex": "^4.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
- "dev": true
- },
- "clone-buffer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
- "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
- "dev": true
- },
- "clone-deep": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
- "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
- "dev": true,
- "requires": {
- "is-plain-object": "^2.0.4",
- "kind-of": "^6.0.2",
- "shallow-clone": "^3.0.0"
- }
- },
- "clone-stats": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
- "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
- "dev": true
- },
- "cloneable-readable": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
- "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.1",
- "process-nextick-args": "^2.0.0",
- "readable-stream": "^2.3.5"
- }
- },
- "clsx": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
- "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
- },
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
- },
- "coa": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
- "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
- "requires": {
- "@types/q": "^1.5.1",
- "chalk": "^2.4.1",
- "q": "^1.1.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "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"
- }
- }
- }
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
- },
- "collapse-white-space": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
- "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
- "dev": true
- },
- "collect-v8-coverage": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
- "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg=="
- },
- "collection-visit": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
- "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
- "requires": {
- "map-visit": "^1.0.0",
- "object-visit": "^1.0.0"
- }
- },
- "color": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
- "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
- "requires": {
- "color-convert": "^1.9.3",
- "color-string": "^1.6.0"
- },
- "dependencies": {
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- }
- }
- },
- "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=="
- },
- "color-string": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.6.0.tgz",
- "integrity": "sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==",
- "requires": {
- "color-name": "^1.0.0",
- "simple-swizzle": "^0.2.2"
- }
- },
- "color-support": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
- "dev": true
- },
- "colorette": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
- "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw=="
- },
- "colors": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
- "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
- "dev": true,
- "optional": true
- },
- "combined-stream": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
- "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "requires": {
- "delayed-stream": "~1.0.0"
- }
- },
- "comma-separated-tokens": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
- "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
- "dev": true
- },
- "commander": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
- "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
- },
- "common-path-prefix": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz",
- "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==",
- "dev": true
- },
- "common-tags": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
- "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw=="
- },
- "commondir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
- "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
- },
- "component-emitter": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
- "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
- },
- "compose-function": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz",
- "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=",
- "requires": {
- "arity-n": "^1.0.4"
- }
- },
- "compressible": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
- "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
- "requires": {
- "mime-db": ">= 1.43.0 < 2"
- }
- },
- "compression": {
- "version": "1.7.4",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
- "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
- "requires": {
- "accepts": "~1.3.5",
- "bytes": "3.0.0",
- "compressible": "~2.0.16",
- "debug": "2.6.9",
- "on-headers": "~1.0.2",
- "safe-buffer": "5.1.2",
- "vary": "~1.1.2"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "compressorjs": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.0.7.tgz",
- "integrity": "sha512-ca+H8CGrn0LG103//VQmXBbNdvzvHiW26LGdWncp4RmLNbNQjaaFWIUxMN9++hbhGobLtofkHoxzzXGisNyD3w==",
- "requires": {
- "blueimp-canvas-to-blob": "^3.28.0",
- "is-blob": "^2.1.0"
- }
- },
- "compute-scroll-into-view": {
- "version": "1.0.17",
- "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz",
- "integrity": "sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==",
- "dev": true
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "concat-stream": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
- "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
- "requires": {
- "buffer-from": "^1.0.0",
- "inherits": "^2.0.3",
- "readable-stream": "^2.2.2",
- "typedarray": "^0.0.6"
- }
- },
- "confusing-browser-globals": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz",
- "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA=="
- },
- "connect-history-api-fallback": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
- "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
- },
- "console-browserify": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
- "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="
- },
- "console-control-strings": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
- "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
- },
- "constants-browserify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
- "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U="
- },
- "content-disposition": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
- "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
- "requires": {
- "safe-buffer": "5.1.2"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "content-type": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
- "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
- },
- "convert-source-map": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
- "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
- "requires": {
- "safe-buffer": "~5.1.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "convert-units": {
- "version": "2.3.4",
- "resolved": "https://registry.npmjs.org/convert-units/-/convert-units-2.3.4.tgz",
- "integrity": "sha512-ERHfdA0UhHJp1IpwE6PnFJx8LqG7B1ZjJ20UvVCmopEnVCfER68Tbe3kvN63dLbYXDA2xFWRE6zd4Wsf0w7POg==",
- "requires": {
- "lodash.foreach": "2.3.x",
- "lodash.keys": "2.3.x"
- }
- },
- "cookie": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
- "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
- },
- "cookie-signature": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
- "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
- },
- "copy-concurrently": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
- "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
- "requires": {
- "aproba": "^1.1.1",
- "fs-write-stream-atomic": "^1.0.8",
- "iferr": "^0.1.5",
- "mkdirp": "^0.5.1",
- "rimraf": "^2.5.4",
- "run-queue": "^1.0.0"
- },
- "dependencies": {
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "copy-descriptor": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
- "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
- },
- "copy-to-clipboard": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
- "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
- "dev": true,
- "requires": {
- "toggle-selection": "^1.0.6"
- }
- },
- "core-js": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.9.0.tgz",
- "integrity": "sha512-PyFBJaLq93FlyYdsndE5VaueA9K5cNB7CGzeCj191YYLhkQM0gdZR2SKihM70oF0wdqKSKClv/tEBOpoRmdOVQ=="
- },
- "core-js-compat": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.9.0.tgz",
- "integrity": "sha512-YK6fwFjCOKWwGnjFUR3c544YsnA/7DoLL0ysncuOJ4pwbriAtOpvM2bygdlcXbvQCQZ7bBU9CL4t7tGl7ETRpQ==",
- "requires": {
- "browserslist": "^4.16.3",
- "semver": "7.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "semver": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
- "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
- }
- }
- },
- "core-js-pure": {
- "version": "3.9.0",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.9.0.tgz",
- "integrity": "sha512-3pEcmMZC9Cq0D4ZBh3pe2HLtqxpGNJBLXF/kZ2YzK17RbKp94w0HFbdbSx8H8kAlZG5k76hvLrkPm57Uyef+kg=="
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
- },
- "cosmiconfig": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
- "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
- "requires": {
- "@types/parse-json": "^4.0.0",
- "import-fresh": "^3.2.1",
- "parse-json": "^5.0.0",
- "path-type": "^4.0.0",
- "yaml": "^1.10.0"
- },
- "dependencies": {
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- }
- }
- },
- "cp-file": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
- "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "make-dir": "^3.0.0",
- "nested-error-stacks": "^2.0.0",
- "p-event": "^4.1.0"
- },
- "dependencies": {
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- }
- }
- },
- "cpy": {
- "version": "8.1.2",
- "resolved": "https://registry.npmjs.org/cpy/-/cpy-8.1.2.tgz",
- "integrity": "sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==",
- "dev": true,
- "requires": {
- "arrify": "^2.0.1",
- "cp-file": "^7.0.0",
- "globby": "^9.2.0",
- "has-glob": "^1.0.0",
- "junk": "^3.1.0",
- "nested-error-stacks": "^2.1.0",
- "p-all": "^2.1.0",
- "p-filter": "^2.1.0",
- "p-map": "^3.0.0"
- },
- "dependencies": {
- "@nodelib/fs.stat": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
- "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
- "dev": true
- },
- "array-union": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "dev": true,
- "requires": {
- "array-uniq": "^1.0.1"
- }
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "dir-glob": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
- "integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
- "dev": true,
- "requires": {
- "path-type": "^3.0.0"
- }
- },
- "fast-glob": {
- "version": "2.2.7",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
- "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==",
- "dev": true,
- "requires": {
- "@mrmlnc/readdir-enhanced": "^2.2.1",
- "@nodelib/fs.stat": "^1.1.2",
- "glob-parent": "^3.1.0",
- "is-glob": "^4.0.0",
- "merge2": "^1.2.3",
- "micromatch": "^3.1.10"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.3"
- },
- "dependencies": {
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.1"
- }
- }
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "requires": {
- "is-glob": "^4.0.3"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "globby": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
- "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
- "dev": true,
- "requires": {
- "@types/glob": "^7.1.1",
- "array-union": "^1.0.2",
- "dir-glob": "^2.2.2",
- "fast-glob": "^2.2.6",
- "glob": "^7.1.3",
- "ignore": "^4.0.3",
- "pify": "^4.0.1",
- "slash": "^2.0.0"
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
- "dev": true
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "dev": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "p-map": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz",
- "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==",
- "dev": true,
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "path-type": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
- "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
- "dev": true,
- "requires": {
- "pify": "^3.0.0"
- },
- "dependencies": {
- "pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
- "dev": true
- }
- }
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "dev": true
- },
- "slash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
- "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
- "dev": true
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "dev": true,
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
- "create-ecdh": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
- "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
- "requires": {
- "bn.js": "^4.1.0",
- "elliptic": "^6.5.3"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "create-hash": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
- "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
- "requires": {
- "cipher-base": "^1.0.1",
- "inherits": "^2.0.1",
- "md5.js": "^1.3.4",
- "ripemd160": "^2.0.1",
- "sha.js": "^2.4.0"
- }
- },
- "create-hmac": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
- "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
- "requires": {
- "cipher-base": "^1.0.3",
- "create-hash": "^1.1.0",
- "inherits": "^2.0.1",
- "ripemd160": "^2.0.0",
- "safe-buffer": "^5.0.1",
- "sha.js": "^2.4.8"
- }
- },
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "crypto-browserify": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
- "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
- "requires": {
- "browserify-cipher": "^1.0.0",
- "browserify-sign": "^4.0.0",
- "create-ecdh": "^4.0.0",
- "create-hash": "^1.1.0",
- "create-hmac": "^1.1.0",
- "diffie-hellman": "^5.0.0",
- "inherits": "^2.0.1",
- "pbkdf2": "^3.0.3",
- "public-encrypt": "^4.0.0",
- "randombytes": "^2.0.0",
- "randomfill": "^1.0.3"
- }
- },
- "crypto-random-string": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
- "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4="
- },
- "css": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
- "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==",
- "requires": {
- "inherits": "^2.0.4",
- "source-map": "^0.6.1",
- "source-map-resolve": "^0.6.0"
- }
- },
- "css-blank-pseudo": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz",
- "integrity": "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w==",
- "requires": {
- "postcss": "^7.0.5"
- }
- },
- "css-color-names": {
- "version": "0.0.4",
- "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
- "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA="
- },
- "css-declaration-sorter": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz",
- "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==",
- "requires": {
- "postcss": "^7.0.1",
- "timsort": "^0.3.0"
- }
- },
- "css-has-pseudo": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz",
- "integrity": "sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ==",
- "requires": {
- "postcss": "^7.0.6",
- "postcss-selector-parser": "^5.0.0-rc.4"
- },
- "dependencies": {
- "cssesc": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
- "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg=="
- },
- "postcss-selector-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
- "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
- "requires": {
- "cssesc": "^2.0.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "css-line-break": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz",
- "integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
- "requires": {
- "base64-arraybuffer": "^0.2.0"
- }
- },
- "css-loader": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.3.0.tgz",
- "integrity": "sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==",
- "requires": {
- "camelcase": "^6.0.0",
- "cssesc": "^3.0.0",
- "icss-utils": "^4.1.1",
- "loader-utils": "^2.0.0",
- "postcss": "^7.0.32",
- "postcss-modules-extract-imports": "^2.0.0",
- "postcss-modules-local-by-default": "^3.0.3",
- "postcss-modules-scope": "^2.2.0",
- "postcss-modules-values": "^3.0.0",
- "postcss-value-parser": "^4.1.0",
- "schema-utils": "^2.7.1",
- "semver": "^7.3.2"
- },
- "dependencies": {
- "camelcase": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
- "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg=="
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "css-mediaquery": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz",
- "integrity": "sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA="
- },
- "css-prefers-color-scheme": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz",
- "integrity": "sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg==",
- "requires": {
- "postcss": "^7.0.5"
- }
- },
- "css-select": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
- "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
- "requires": {
- "boolbase": "^1.0.0",
- "css-what": "^3.2.1",
- "domutils": "^1.7.0",
- "nth-check": "^1.0.2"
- },
- "dependencies": {
- "dom-serializer": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
- "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
- "requires": {
- "domelementtype": "^2.0.1",
- "entities": "^2.0.0"
- },
- "dependencies": {
- "domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
- }
- }
- },
- "domelementtype": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
- "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
- },
- "domutils": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
- "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
- "requires": {
- "dom-serializer": "0",
- "domelementtype": "1"
- }
- },
- "nth-check": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
- "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
- "requires": {
- "boolbase": "^1.0.0"
- }
- }
- }
- },
- "css-select-base-adapter": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
- "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w=="
- },
- "css-tree": {
- "version": "1.0.0-alpha.37",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
- "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
- "requires": {
- "mdn-data": "2.0.4",
- "source-map": "^0.6.1"
- }
- },
- "css-vendor": {
- "version": "2.0.8",
- "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
- "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
- "requires": {
- "@babel/runtime": "^7.8.3",
- "is-in-browser": "^1.0.2"
- }
- },
- "css-what": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
- "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ=="
- },
- "css.escape": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz",
- "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s="
- },
- "cssdb": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-4.4.0.tgz",
- "integrity": "sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ=="
- },
- "cssesc": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
- "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
- },
- "cssnano": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
- "integrity": "sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g==",
- "requires": {
- "cosmiconfig": "^5.0.0",
- "cssnano-preset-default": "^4.0.8",
- "is-resolvable": "^1.0.0",
- "postcss": "^7.0.0"
- },
- "dependencies": {
- "cosmiconfig": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
- "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "requires": {
- "import-fresh": "^2.0.0",
- "is-directory": "^0.3.1",
- "js-yaml": "^3.13.1",
- "parse-json": "^4.0.0"
- }
- },
- "import-fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
- "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
- "requires": {
- "caller-path": "^2.0.0",
- "resolve-from": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
- "requires": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- }
- },
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
- }
- }
- },
- "cssnano-preset-default": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz",
- "integrity": "sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ==",
- "requires": {
- "css-declaration-sorter": "^4.0.1",
- "cssnano-util-raw-cache": "^4.0.1",
- "postcss": "^7.0.0",
- "postcss-calc": "^7.0.1",
- "postcss-colormin": "^4.0.3",
- "postcss-convert-values": "^4.0.1",
- "postcss-discard-comments": "^4.0.2",
- "postcss-discard-duplicates": "^4.0.2",
- "postcss-discard-empty": "^4.0.1",
- "postcss-discard-overridden": "^4.0.1",
- "postcss-merge-longhand": "^4.0.11",
- "postcss-merge-rules": "^4.0.3",
- "postcss-minify-font-values": "^4.0.2",
- "postcss-minify-gradients": "^4.0.2",
- "postcss-minify-params": "^4.0.2",
- "postcss-minify-selectors": "^4.0.2",
- "postcss-normalize-charset": "^4.0.1",
- "postcss-normalize-display-values": "^4.0.2",
- "postcss-normalize-positions": "^4.0.2",
- "postcss-normalize-repeat-style": "^4.0.2",
- "postcss-normalize-string": "^4.0.2",
- "postcss-normalize-timing-functions": "^4.0.2",
- "postcss-normalize-unicode": "^4.0.1",
- "postcss-normalize-url": "^4.0.1",
- "postcss-normalize-whitespace": "^4.0.2",
- "postcss-ordered-values": "^4.1.2",
- "postcss-reduce-initial": "^4.0.3",
- "postcss-reduce-transforms": "^4.0.2",
- "postcss-svgo": "^4.0.3",
- "postcss-unique-selectors": "^4.0.1"
- }
- },
- "cssnano-util-get-arguments": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
- "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8="
- },
- "cssnano-util-get-match": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
- "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0="
- },
- "cssnano-util-raw-cache": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz",
- "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "cssnano-util-same-parent": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz",
- "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q=="
- },
- "csso": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz",
- "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==",
- "requires": {
- "css-tree": "^1.1.2"
- },
- "dependencies": {
- "css-tree": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
- "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
- "requires": {
- "mdn-data": "2.0.14",
- "source-map": "^0.6.1"
- }
- },
- "mdn-data": {
- "version": "2.0.14",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
- "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
- }
- }
- },
- "cssom": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
- "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
- },
- "cssstyle": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
- "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
- "requires": {
- "cssom": "~0.3.6"
- },
- "dependencies": {
- "cssom": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
- "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
- }
- }
- },
- "csstype": {
- "version": "2.6.16",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.16.tgz",
- "integrity": "sha512-61FBWoDHp/gRtsoDkq/B1nWrCUG/ok1E3tUrcNbZjsE9Cxd9yzUirjS3+nAATB8U4cTtaQmAHbNndoFz5L6C9Q=="
- },
- "cyclist": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
- "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
- },
- "cypress": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.7.0.tgz",
- "integrity": "sha512-b1bMC3VQydC6sXzBMFnSqcvwc9dTZMgcaOzT0vpSD+Gq1yFc+72JDWi55sfUK5eIeNLAtWOGy1NNb6UlhMvB+Q==",
- "dev": true,
- "requires": {
- "@cypress/request": "^2.88.6",
- "@cypress/xvfb": "^1.2.4",
- "@types/node": "^14.14.31",
- "@types/sinonjs__fake-timers": "^6.0.2",
- "@types/sizzle": "^2.3.2",
- "arch": "^2.2.0",
- "blob-util": "^2.0.2",
- "bluebird": "^3.7.2",
- "cachedir": "^2.3.0",
- "chalk": "^4.1.0",
- "check-more-types": "^2.24.0",
- "cli-cursor": "^3.1.0",
- "cli-table3": "~0.6.0",
- "commander": "^5.1.0",
- "common-tags": "^1.8.0",
- "dayjs": "^1.10.4",
- "debug": "^4.3.2",
- "enquirer": "^2.3.6",
- "eventemitter2": "^6.4.3",
- "execa": "4.1.0",
- "executable": "^4.1.1",
- "extract-zip": "2.0.1",
- "figures": "^3.2.0",
- "fs-extra": "^9.1.0",
- "getos": "^3.2.1",
- "is-ci": "^3.0.0",
- "is-installed-globally": "~0.4.0",
- "lazy-ass": "^1.6.0",
- "listr2": "^3.8.3",
- "lodash": "^4.17.21",
- "log-symbols": "^4.0.0",
- "minimist": "^1.2.5",
- "ospath": "^1.2.2",
- "pretty-bytes": "^5.6.0",
- "proxy-from-env": "1.0.0",
- "ramda": "~0.27.1",
- "request-progress": "^3.0.0",
- "supports-color": "^8.1.1",
- "tmp": "~0.2.1",
- "untildify": "^4.0.0",
- "url": "^0.11.0",
- "yauzl": "^2.10.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- }
- }
- },
- "ci-info": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz",
- "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==",
- "dev": true
- },
- "colorette": {
- "version": "2.0.16",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz",
- "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==",
- "dev": true
- },
- "commander": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
- "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
- "dev": true
- },
- "debug": {
- "version": "4.3.2",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
- "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
- "dev": true,
- "requires": {
- "ms": "2.1.2"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "execa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
- "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.0",
- "get-stream": "^5.0.0",
- "human-signals": "^1.1.1",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.0",
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2",
- "strip-final-newline": "^2.0.0"
- }
- },
- "get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "dev": true,
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "is-ci": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
- "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
- "dev": true,
- "requires": {
- "ci-info": "^3.2.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true
- },
- "listr2": {
- "version": "3.13.1",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.13.1.tgz",
- "integrity": "sha512-pk4YBDA2cxtpM8iLHbz6oEsfZieJKHf6Pt19NlKaHZZVpqHyVs/Wqr7RfBBCeAFCJchGO7WQHVkUPZTvJMHk8w==",
- "dev": true,
- "requires": {
- "cli-truncate": "^2.1.0",
- "colorette": "^2.0.16",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
- "rxjs": "^6.6.7",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
- }
- },
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "requires": {
- "path-key": "^3.0.0"
- }
- },
- "rxjs": {
- "version": "6.6.7",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
- "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
- "dev": true,
- "requires": {
- "tslib": "^1.9.0"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "supports-color": {
- "version": "8.1.1",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
- "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "d": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
- "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
- "requires": {
- "es5-ext": "^0.10.50",
- "type": "^1.0.1"
- }
- },
- "d3-ease": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz",
- "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ=="
- },
- "d3-timer": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz",
- "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw=="
- },
- "damerau-levenshtein": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz",
- "integrity": "sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw=="
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "data-urls": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
- "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
- "requires": {
- "abab": "^2.0.3",
- "whatwg-mimetype": "^2.3.0",
- "whatwg-url": "^8.0.0"
- }
- },
- "dayjs": {
- "version": "1.10.7",
- "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz",
- "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==",
- "dev": true
- },
- "de-indent": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
- "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
- "dev": true
- },
- "debug": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
- "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
- "requires": {
- "ms": "2.1.2"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
- }
- }
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
- },
- "decamelize-keys": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
- "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
- "requires": {
- "decamelize": "^1.1.0",
- "map-obj": "^1.0.0"
- },
- "dependencies": {
- "map-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
- "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
- }
- }
- },
- "decimal.js": {
- "version": "10.3.1",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz",
- "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
- },
- "decode-uri-component": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
- "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
- },
- "dedent": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
- "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
- },
- "deep-diff": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-1.0.2.tgz",
- "integrity": "sha512-aWS3UIVH+NPGCD1kki+DCU9Dua032iSsO43LqQpcs4R3+dVv7tX0qBGjiVHJHjplsoUM2XRO/KB92glqc68awg=="
- },
- "deep-equal": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
- "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
- "requires": {
- "is-arguments": "^1.0.4",
- "is-date-object": "^1.0.1",
- "is-regex": "^1.0.4",
- "object-is": "^1.0.1",
- "object-keys": "^1.1.1",
- "regexp.prototype.flags": "^1.2.0"
- }
- },
- "deep-is": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
- "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
- },
- "deep-object-diff": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz",
- "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==",
- "dev": true
- },
- "deepmerge": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
- "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
- },
- "default-gateway": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
- "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
- "requires": {
- "execa": "^1.0.0",
- "ip-regex": "^2.1.0"
- }
- },
- "define-properties": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
- "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
- "requires": {
- "object-keys": "^1.0.12"
- }
- },
- "define-property": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
- "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
- "requires": {
- "is-descriptor": "^1.0.2",
- "isobject": "^3.0.1"
- },
- "dependencies": {
- "is-accessor-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
- "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-data-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
- "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-descriptor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
- "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
- "requires": {
- "is-accessor-descriptor": "^1.0.0",
- "is-data-descriptor": "^1.0.0",
- "kind-of": "^6.0.2"
- }
- }
- }
- },
- "del": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
- "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
- "requires": {
- "@types/glob": "^7.1.1",
- "globby": "^6.1.0",
- "is-path-cwd": "^2.0.0",
- "is-path-in-cwd": "^2.0.0",
- "p-map": "^2.0.0",
- "pify": "^4.0.1",
- "rimraf": "^2.6.3"
- },
- "dependencies": {
- "array-union": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
- "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
- "requires": {
- "array-uniq": "^1.0.1"
- }
- },
- "globby": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
- "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
- "requires": {
- "array-union": "^1.0.1",
- "glob": "^7.0.3",
- "object-assign": "^4.0.1",
- "pify": "^2.0.0",
- "pinkie-promise": "^2.0.0"
- },
- "dependencies": {
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
- }
- }
- },
- "p-map": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
- "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
- },
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
- },
- "delegates": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
- "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
- },
- "depd": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
- "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
- },
- "des.js": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
- "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
- "requires": {
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0"
- }
- },
- "destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
- },
- "detab": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/detab/-/detab-2.0.4.tgz",
- "integrity": "sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==",
- "dev": true,
- "requires": {
- "repeat-string": "^1.5.4"
- }
- },
- "detect-newline": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
- "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="
- },
- "detect-node": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
- "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="
- },
- "detect-port": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/detect-port/-/detect-port-1.3.0.tgz",
- "integrity": "sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==",
- "dev": true,
- "requires": {
- "address": "^1.0.1",
- "debug": "^2.6.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "dev": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
- "dev": true
- }
- }
- },
- "detect-port-alt": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz",
- "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==",
- "requires": {
- "address": "^1.0.1",
- "debug": "^2.6.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "diff-sequences": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz",
- "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q=="
- },
- "diffie-hellman": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
- "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
- "requires": {
- "bn.js": "^4.1.0",
- "miller-rabin": "^4.0.0",
- "randombytes": "^2.0.0"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "requires": {
- "path-type": "^4.0.0"
- },
- "dependencies": {
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
- }
- }
- },
- "dns-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
- "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
- },
- "dns-packet": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz",
- "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==",
- "requires": {
- "ip": "^1.1.0",
- "safe-buffer": "^5.0.1"
- }
- },
- "dns-txt": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
- "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
- "requires": {
- "buffer-indexof": "^1.0.0"
- }
- },
- "doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "dom-accessibility-api": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz",
- "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ=="
- },
- "dom-converter": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
- "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==",
- "requires": {
- "utila": "~0.4"
- }
- },
- "dom-helpers": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz",
- "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==",
- "requires": {
- "@babel/runtime": "^7.8.7",
- "csstype": "^3.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
- "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
- }
- }
- },
- "dom-serializer": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.2.0.tgz",
- "integrity": "sha512-n6kZFH/KlCrqs/1GHMOd5i2fd/beQHuehKdWvNNffbGHTr/almdhuVvTVFb3V7fglz+nC50fFusu3lY33h12pA==",
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "entities": "^2.0.0"
- },
- "dependencies": {
- "domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "requires": {
- "domelementtype": "^2.1.0"
- }
- }
- }
- },
- "dom-walk": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
- "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==",
- "dev": true
- },
- "domain-browser": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
- "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA=="
- },
- "domelementtype": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.1.0.tgz",
- "integrity": "sha512-LsTgx/L5VpD+Q8lmsXSHW2WpA+eBlZ9HPf3erD1IoPF00/3JKHZ3BknUVA2QGDNu69ZNmyFmCWBSO45XjYKC5w=="
- },
- "domexception": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
- "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
- "requires": {
- "webidl-conversions": "^5.0.0"
- },
- "dependencies": {
- "webidl-conversions": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
- "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
- }
- }
- },
- "domhandler": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz",
- "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==",
- "requires": {
- "domelementtype": "^2.0.1"
- }
- },
- "domutils": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.4.tgz",
- "integrity": "sha512-jBC0vOsECI4OMdD0GC9mGn7NXPLb+Qt6KW1YDQzeQYRUFKmNG8lh7mO5HiELfr+lLQE7loDVI4QcAxV80HS+RA==",
- "requires": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0"
- },
- "dependencies": {
- "domhandler": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.0.0.tgz",
- "integrity": "sha512-KPTbnGQ1JeEMQyO1iYXoagsI6so/C96HZiFyByU3T6iAzpXn8EGEvct6unm1ZGoed8ByO2oirxgwxBmqKF9haA==",
- "requires": {
- "domelementtype": "^2.1.0"
- }
- }
- }
- },
- "dot-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz",
- "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==",
- "requires": {
- "no-case": "^3.0.4",
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "dot-prop": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
- "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
- "requires": {
- "is-obj": "^2.0.0"
- }
- },
- "dotenv": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
- "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
- },
- "dotenv-expand": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
- "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
- },
- "downshift": {
- "version": "6.1.7",
- "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.7.tgz",
- "integrity": "sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.14.8",
- "compute-scroll-into-view": "^1.0.17",
- "prop-types": "^15.7.2",
- "react-is": "^17.0.2",
- "tslib": "^2.3.0"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
- "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- },
- "tslib": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
- "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
- "dev": true
- }
- }
- },
- "duplexer": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
- "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
- },
- "duplexify": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
- "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
- "requires": {
- "end-of-stream": "^1.0.0",
- "inherits": "^2.0.1",
- "readable-stream": "^2.0.0",
- "stream-shift": "^1.0.0"
- }
- },
- "ecc-jsbn": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
- "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
- "requires": {
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.1.0"
- }
- },
- "ecdsa-sig-formatter": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
- "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
- },
- "ejs": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
- "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "element-resize-detector": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/element-resize-detector/-/element-resize-detector-1.2.4.tgz",
- "integrity": "sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==",
- "dev": true,
- "requires": {
- "batch-processor": "1.0.0"
- }
- },
- "elliptic": {
- "version": "6.5.4",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
- "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
- "requires": {
- "bn.js": "^4.11.9",
- "brorand": "^1.1.0",
- "hash.js": "^1.0.0",
- "hmac-drbg": "^1.0.1",
- "inherits": "^2.0.4",
- "minimalistic-assert": "^1.0.1",
- "minimalistic-crypto-utils": "^1.0.1"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "emittery": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz",
- "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ=="
- },
- "emoji-regex": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
- "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
- },
- "emojis-list": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
- "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
- },
- "emotion-theming": {
- "version": "10.3.0",
- "resolved": "https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.3.0.tgz",
- "integrity": "sha512-mXiD2Oj7N9b6+h/dC6oLf9hwxbtKHQjoIqtodEyL8CpkN4F3V4IK/BT4D0C7zSs4BBFOu4UlPJbvvBLa88SGEA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.5",
- "@emotion/weak-memoize": "0.2.5",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "encodeurl": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
- "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
- },
- "end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "requires": {
- "once": "^1.4.0"
- }
- },
- "endent": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/endent/-/endent-2.1.0.tgz",
- "integrity": "sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==",
- "dev": true,
- "requires": {
- "dedent": "^0.7.0",
- "fast-json-parse": "^1.0.3",
- "objectorarray": "^1.0.5"
- }
- },
- "enhanced-resolve": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
- "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
- "requires": {
- "graceful-fs": "^4.1.2",
- "memory-fs": "^0.5.0",
- "tapable": "^1.0.0"
- },
- "dependencies": {
- "memory-fs": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
- "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
- "requires": {
- "errno": "^0.1.3",
- "readable-stream": "^2.0.1"
- }
- }
- }
- },
- "enquirer": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
- "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
- "requires": {
- "ansi-colors": "^4.1.1"
- }
- },
- "entities": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
- "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
- },
- "env-paths": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
- "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="
- },
- "eol": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/eol/-/eol-0.9.1.tgz",
- "integrity": "sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==",
- "dev": true
- },
- "errno": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
- "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
- "requires": {
- "prr": "~1.0.1"
- }
- },
- "error-ex": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
- "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
- "requires": {
- "is-arrayish": "^0.2.1"
- }
- },
- "error-stack-parser": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.0.6.tgz",
- "integrity": "sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==",
- "requires": {
- "stackframe": "^1.1.1"
- }
- },
- "es-abstract": {
- "version": "1.18.0-next.2",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.2.tgz",
- "integrity": "sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw==",
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.2",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.1",
- "object-inspect": "^1.9.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.3",
- "string.prototype.trimstart": "^1.0.3"
- }
- },
- "es-array-method-boxes-properly": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
- "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==",
- "dev": true
- },
- "es-get-iterator": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz",
- "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.0",
- "has-symbols": "^1.0.1",
- "is-arguments": "^1.1.0",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.5",
- "isarray": "^2.0.5"
- },
- "dependencies": {
- "isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
- "dev": true
- }
- }
- },
- "es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "requires": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- }
- },
- "es5-ext": {
- "version": "0.10.53",
- "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
- "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
- "requires": {
- "es6-iterator": "~2.0.3",
- "es6-symbol": "~3.1.3",
- "next-tick": "~1.0.0"
- }
- },
- "es5-shim": {
- "version": "4.6.4",
- "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.4.tgz",
- "integrity": "sha512-Z0f7OUYZ8JfqT12d3Tgh2ErxIH5Shaz97GE8qyDG9quxb2Hmh2vvFHlOFjx6lzyD0CRgvJfnNYcisjdbRp7MPw==",
- "dev": true
- },
- "es6-iterator": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
- "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
- "requires": {
- "d": "1",
- "es5-ext": "^0.10.35",
- "es6-symbol": "^3.1.1"
- }
- },
- "es6-shim": {
- "version": "0.35.6",
- "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.6.tgz",
- "integrity": "sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==",
- "dev": true
- },
- "es6-symbol": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
- "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
- "requires": {
- "d": "^1.0.1",
- "ext": "^1.1.2"
- }
- },
- "escalade": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
- "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
- },
- "escodegen": {
- "version": "1.14.3",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
- "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
- "dev": true,
- "requires": {
- "esprima": "^4.0.1",
- "estraverse": "^4.2.0",
- "esutils": "^2.0.2",
- "optionator": "^0.8.1",
- "source-map": "~0.6.1"
- },
- "dependencies": {
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
- }
- },
- "optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
- "dev": true,
- "requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
- }
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
- "dev": true
- },
- "type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "dev": true,
- "requires": {
- "prelude-ls": "~1.1.2"
- }
- }
- }
- },
- "eslint": {
- "version": "7.20.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
- "integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
- "requires": {
- "@babel/code-frame": "7.12.11",
- "@eslint/eslintrc": "^0.3.0",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.0.1",
- "doctrine": "^3.0.0",
- "enquirer": "^2.3.5",
- "eslint-scope": "^5.1.1",
- "eslint-utils": "^2.1.0",
- "eslint-visitor-keys": "^2.0.0",
- "espree": "^7.3.1",
- "esquery": "^1.4.0",
- "esutils": "^2.0.2",
- "file-entry-cache": "^6.0.0",
- "functional-red-black-tree": "^1.0.1",
- "glob-parent": "^5.0.0",
- "globals": "^12.1.0",
- "ignore": "^4.0.6",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "js-yaml": "^3.13.1",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash": "^4.17.20",
- "minimatch": "^3.0.4",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "progress": "^2.0.0",
- "regexpp": "^3.1.0",
- "semver": "^7.2.1",
- "strip-ansi": "^6.0.0",
- "strip-json-comments": "^3.1.0",
- "table": "^6.0.4",
- "text-table": "^0.2.0",
- "v8-compile-cache": "^2.0.3"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.12.11",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
- "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
- "requires": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "requires": {
- "is-glob": "^4.0.3"
- }
- },
- "globals": {
- "version": "12.4.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
- "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
- "requires": {
- "type-fest": "^0.8.1"
- }
- },
- "ignore": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
- "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
- },
- "semver": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
- "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "eslint-config-prettier": {
- "version": "6.15.0",
- "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz",
- "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==",
- "dev": true,
- "requires": {
- "get-stdin": "^6.0.0"
- },
- "dependencies": {
- "get-stdin": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
- "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
- "dev": true
- }
- }
- },
- "eslint-config-react-app": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
- "integrity": "sha512-bpoAAC+YRfzq0dsTk+6v9aHm/uqnDwayNAXleMypGl6CpxI9oXXscVHo4fk3eJPIn+rsbtNetB4r/ZIidFIE8A==",
- "requires": {
- "confusing-browser-globals": "^1.0.10"
- }
- },
- "eslint-import-resolver-node": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
- "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
- "requires": {
- "debug": "^3.2.7",
- "resolve": "^1.20.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "eslint-module-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz",
- "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==",
- "requires": {
- "debug": "^3.2.7",
- "find-up": "^2.1.0",
- "pkg-dir": "^2.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- },
- "find-up": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
- "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
- "requires": {
- "locate-path": "^2.0.0"
- }
- },
- "locate-path": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
- "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
- "requires": {
- "p-locate": "^2.0.0",
- "path-exists": "^3.0.0"
- }
- },
- "p-limit": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
- "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
- "requires": {
- "p-try": "^1.0.0"
- }
- },
- "p-locate": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
- "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
- "requires": {
- "p-limit": "^1.1.0"
- }
- },
- "p-try": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
- "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
- },
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
- },
- "pkg-dir": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
- "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
- "requires": {
- "find-up": "^2.1.0"
- }
- }
- }
- },
- "eslint-plugin-flowtype": {
- "version": "5.10.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz",
- "integrity": "sha512-vcz32f+7TP+kvTUyMXZmCnNujBQZDNmcqPImw8b9PZ+16w1Qdm6ryRuYZYVaG9xRqqmAPr2Cs9FAX5gN+x/bjw==",
- "requires": {
- "lodash": "^4.17.15",
- "string-natural-compare": "^3.0.1"
- }
- },
- "eslint-plugin-import": {
- "version": "2.25.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz",
- "integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==",
- "requires": {
- "array-includes": "^3.1.4",
- "array.prototype.flat": "^1.2.5",
- "debug": "^2.6.9",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-module-utils": "^2.7.0",
- "has": "^1.0.3",
- "is-core-module": "^2.7.0",
- "is-glob": "^4.0.3",
- "minimatch": "^3.0.4",
- "object.values": "^1.1.5",
- "resolve": "^1.20.0",
- "tsconfig-paths": "^3.11.0"
- },
- "dependencies": {
- "array-includes": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz",
- "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "is-string": "^1.0.7"
- }
- },
- "array.prototype.flat": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz",
- "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0"
- }
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "requires": {
- "esutils": "^2.0.2"
- }
- },
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
- },
- "is-core-module": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
- "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "object-inspect": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
- "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
- },
- "object.values": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
- "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- }
- }
- }
- },
- "eslint-plugin-jest": {
- "version": "24.7.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.7.0.tgz",
- "integrity": "sha512-wUxdF2bAZiYSKBclsUMrYHH6WxiBreNjyDxbRv345TIvPeoCEgPNEn3Sa+ZrSqsf1Dl9SqqSREXMHExlMMu1DA==",
- "requires": {
- "@typescript-eslint/experimental-utils": "^4.0.1"
- }
- },
- "eslint-plugin-jsx-a11y": {
- "version": "6.4.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
- "integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
- "requires": {
- "@babel/runtime": "^7.11.2",
- "aria-query": "^4.2.2",
- "array-includes": "^3.1.1",
- "ast-types-flow": "^0.0.7",
- "axe-core": "^4.0.2",
- "axobject-query": "^2.2.0",
- "damerau-levenshtein": "^1.0.6",
- "emoji-regex": "^9.0.0",
- "has": "^1.0.3",
- "jsx-ast-utils": "^3.1.0",
- "language-tags": "^1.0.5"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
- }
- }
- },
- "eslint-plugin-react": {
- "version": "7.22.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz",
- "integrity": "sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA==",
- "requires": {
- "array-includes": "^3.1.1",
- "array.prototype.flatmap": "^1.2.3",
- "doctrine": "^2.1.0",
- "has": "^1.0.3",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "object.entries": "^1.1.2",
- "object.fromentries": "^2.0.2",
- "object.values": "^1.1.1",
- "prop-types": "^15.7.2",
- "resolve": "^1.18.1",
- "string.prototype.matchall": "^4.0.2"
- },
- "dependencies": {
- "doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "requires": {
- "esutils": "^2.0.2"
- }
- }
- }
- },
- "eslint-plugin-react-hooks": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
- "integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ=="
- },
- "eslint-plugin-testing-library": {
- "version": "3.10.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-3.10.2.tgz",
- "integrity": "sha512-WAmOCt7EbF1XM8XfbCKAEzAPnShkNSwcIsAD2jHdsMUT9mZJPjLCG7pMzbcC8kK366NOuGip8HKLDC+Xk4yIdA==",
- "requires": {
- "@typescript-eslint/experimental-utils": "^3.10.1"
- },
- "dependencies": {
- "@typescript-eslint/experimental-utils": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz",
- "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==",
- "requires": {
- "@types/json-schema": "^7.0.3",
- "@typescript-eslint/types": "3.10.1",
- "@typescript-eslint/typescript-estree": "3.10.1",
- "eslint-scope": "^5.0.0",
- "eslint-utils": "^2.0.0"
- }
- },
- "@typescript-eslint/types": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz",
- "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ=="
- },
- "@typescript-eslint/typescript-estree": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz",
- "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==",
- "requires": {
- "@typescript-eslint/types": "3.10.1",
- "@typescript-eslint/visitor-keys": "3.10.1",
- "debug": "^4.1.1",
- "glob": "^7.1.6",
- "is-glob": "^4.0.1",
- "lodash": "^4.17.15",
- "semver": "^7.3.2",
- "tsutils": "^3.17.1"
- }
- },
- "@typescript-eslint/visitor-keys": {
- "version": "3.10.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz",
- "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==",
- "requires": {
- "eslint-visitor-keys": "^1.1.0"
- }
- },
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "eslint-scope": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
- "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
- "requires": {
- "esrecurse": "^4.3.0",
- "estraverse": "^4.1.1"
- }
- },
- "eslint-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
- "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
- "requires": {
- "eslint-visitor-keys": "^1.1.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "eslint-visitor-keys": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
- "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ=="
- },
- "eslint-webpack-plugin": {
- "version": "2.5.4",
- "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.5.4.tgz",
- "integrity": "sha512-7rYh0m76KyKSDE+B+2PUQrlNS4HJ51t3WKpkJg6vo2jFMbEPTG99cBV0Dm7LXSHucN4WGCG65wQcRiTFrj7iWw==",
- "requires": {
- "@types/eslint": "^7.2.6",
- "arrify": "^2.0.1",
- "jest-worker": "^26.6.2",
- "micromatch": "^4.0.2",
- "normalize-path": "^3.0.0",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "espree": {
- "version": "7.3.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
- "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
- "requires": {
- "acorn": "^7.4.0",
- "acorn-jsx": "^5.3.1",
- "eslint-visitor-keys": "^1.3.0"
- },
- "dependencies": {
- "eslint-visitor-keys": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
- "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
- }
- }
- },
- "esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
- },
- "esquery": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
- "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
- "requires": {
- "estraverse": "^5.1.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
- "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
- }
- }
- },
- "esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "requires": {
- "estraverse": "^5.2.0"
- },
- "dependencies": {
- "estraverse": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
- "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
- }
- }
- },
- "estraverse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
- "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
- },
- "estree-to-babel": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/estree-to-babel/-/estree-to-babel-3.2.1.tgz",
- "integrity": "sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==",
- "dev": true,
- "requires": {
- "@babel/traverse": "^7.1.6",
- "@babel/types": "^7.2.0",
- "c8": "^7.6.0"
- }
- },
- "estree-walker": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
- "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
- },
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
- },
- "etag": {
- "version": "1.8.1",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
- "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
- },
- "eventemitter2": {
- "version": "6.4.5",
- "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz",
- "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==",
- "dev": true
- },
- "eventemitter3": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
- "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
- },
- "events": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
- "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg=="
- },
- "eventsource": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
- "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
- "requires": {
- "original": "^1.0.0"
- }
- },
- "evp_bytestokey": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
- "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
- "requires": {
- "md5.js": "^1.3.4",
- "safe-buffer": "^5.1.1"
- }
- },
- "exec-sh": {
- "version": "0.3.4",
- "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
- "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A=="
- },
- "execa": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
- "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
- "requires": {
- "cross-spawn": "^6.0.0",
- "get-stream": "^4.0.0",
- "is-stream": "^1.1.0",
- "npm-run-path": "^2.0.0",
- "p-finally": "^1.0.0",
- "signal-exit": "^3.0.0",
- "strip-eof": "^1.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "6.0.5",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
- "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
- "requires": {
- "nice-try": "^1.0.4",
- "path-key": "^2.0.1",
- "semver": "^5.5.0",
- "shebang-command": "^1.2.0",
- "which": "^1.2.9"
- }
- },
- "path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
- },
- "shebang-command": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
- "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
- "requires": {
- "shebang-regex": "^1.0.0"
- }
- },
- "shebang-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
- "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
- },
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "requires": {
- "isexe": "^2.0.0"
- }
- }
- }
- },
- "executable": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz",
- "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==",
- "dev": true,
- "requires": {
- "pify": "^2.2.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",
- "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw="
- },
- "expand-brackets": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
- "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
- "requires": {
- "debug": "^2.3.3",
- "define-property": "^0.2.5",
- "extend-shallow": "^2.0.1",
- "posix-character-classes": "^0.1.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- },
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "expect": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz",
- "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==",
- "requires": {
- "@jest/types": "^26.6.2",
- "ansi-styles": "^4.0.0",
- "jest-get-type": "^26.3.0",
- "jest-matcher-utils": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-regex-util": "^26.0.0"
- }
- },
- "express": {
- "version": "4.17.1",
- "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
- "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
- "requires": {
- "accepts": "~1.3.7",
- "array-flatten": "1.1.1",
- "body-parser": "1.19.0",
- "content-disposition": "0.5.3",
- "content-type": "~1.0.4",
- "cookie": "0.4.0",
- "cookie-signature": "1.0.6",
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "finalhandler": "~1.1.2",
- "fresh": "0.5.2",
- "merge-descriptors": "1.0.1",
- "methods": "~1.1.2",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.3",
- "path-to-regexp": "0.1.7",
- "proxy-addr": "~2.0.5",
- "qs": "6.7.0",
- "range-parser": "~1.2.1",
- "safe-buffer": "5.1.2",
- "send": "0.17.1",
- "serve-static": "1.14.1",
- "setprototypeof": "1.1.1",
- "statuses": "~1.5.0",
- "type-is": "~1.6.18",
- "utils-merge": "1.0.1",
- "vary": "~1.1.2"
- },
- "dependencies": {
- "array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
- },
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "path-to-regexp": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
- "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
- },
- "qs": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
- "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
- },
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "ext": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
- "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
- "requires": {
- "type": "^2.0.0"
- },
- "dependencies": {
- "type": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/type/-/type-2.3.0.tgz",
- "integrity": "sha512-rgPIqOdfK/4J9FhiVrZ3cveAjRRo5rsQBAIhnylX874y1DX/kEKSVdLsnuHB6l1KTjHyU01VjiMBHgU2adejyg=="
- }
- }
- },
- "extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
- },
- "extend-shallow": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
- "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
- "requires": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- },
- "dependencies": {
- "is-extendable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
- "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "requires": {
- "is-plain-object": "^2.0.4"
- }
- }
- }
- },
- "extglob": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
- "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
- "requires": {
- "array-unique": "^0.3.2",
- "define-property": "^1.0.0",
- "expand-brackets": "^2.1.4",
- "extend-shallow": "^2.0.1",
- "fragment-cache": "^0.2.1",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "requires": {
- "is-descriptor": "^1.0.0"
- }
- },
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "is-accessor-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
- "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-data-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
- "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-descriptor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
- "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
- "requires": {
- "is-accessor-descriptor": "^1.0.0",
- "is-data-descriptor": "^1.0.0",
- "kind-of": "^6.0.2"
- }
- }
- }
- },
- "extract-zip": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
- "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
- "dev": true,
- "requires": {
- "@types/yauzl": "^2.9.1",
- "debug": "^4.1.1",
- "get-stream": "^5.1.0",
- "yauzl": "^2.10.0"
- },
- "dependencies": {
- "get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "dev": true,
- "requires": {
- "pump": "^3.0.0"
- }
- }
- }
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
- },
- "fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
- },
- "fast-glob": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz",
- "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==",
- "requires": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.0",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.2",
- "picomatch": "^2.2.1"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "requires": {
- "is-glob": "^4.0.3"
- }
- }
- }
- },
- "fast-json-parse": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz",
- "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==",
- "dev": true
- },
- "fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
- },
- "fastq": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz",
- "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==",
- "requires": {
- "reusify": "^1.0.4"
- }
- },
- "fault": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
- "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
- "dev": true,
- "requires": {
- "format": "^0.2.0"
- }
- },
- "faye-websocket": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
- "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
- "requires": {
- "websocket-driver": ">=0.5.1"
- }
- },
- "fb-watchman": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
- "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==",
- "requires": {
- "bser": "2.1.1"
- }
- },
- "fd-slicer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
- "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
- "dev": true,
- "requires": {
- "pend": "~1.2.0"
- }
- },
- "figgy-pudding": {
- "version": "3.5.2",
- "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
- "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw=="
- },
- "figures": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
- "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^1.0.5"
- }
- },
- "file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "requires": {
- "flat-cache": "^3.0.4"
- }
- },
- "file-loader": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.1.1.tgz",
- "integrity": "sha512-Klt8C4BjWSXYQAfhpYYkG4qHNTna4toMHEbWrI5IuVoxbU6uiDKeKAP99R8mmbJi3lvewn/jQBOgU4+NS3tDQw==",
- "requires": {
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "file-system-cache": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/file-system-cache/-/file-system-cache-1.0.5.tgz",
- "integrity": "sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08=",
- "dev": true,
- "requires": {
- "bluebird": "^3.3.5",
- "fs-extra": "^0.30.0",
- "ramda": "^0.21.0"
- },
- "dependencies": {
- "fs-extra": {
- "version": "0.30.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
- "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^2.1.0",
- "klaw": "^1.0.0",
- "path-is-absolute": "^1.0.0",
- "rimraf": "^2.2.8"
- }
- },
- "jsonfile": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
- "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "ramda": {
- "version": "0.21.0",
- "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz",
- "integrity": "sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=",
- "dev": true
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "filesize": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
- "integrity": "sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg=="
- },
- "fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "requires": {
- "to-regex-range": "^5.0.1"
- }
- },
- "finalhandler": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
- "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
- "requires": {
- "debug": "2.6.9",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "on-finished": "~2.3.0",
- "parseurl": "~1.3.3",
- "statuses": "~1.5.0",
- "unpipe": "~1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "find-cache-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
- "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^2.0.0",
- "pkg-dir": "^3.0.0"
- }
- },
- "find-root": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
- "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
- "dev": true
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "dependencies": {
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- }
- }
- },
- "flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "requires": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- }
- },
- "flatted": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz",
- "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA=="
- },
- "flatten": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.3.tgz",
- "integrity": "sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg=="
- },
- "flush-write-stream": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
- "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
- "requires": {
- "inherits": "^2.0.3",
- "readable-stream": "^2.3.6"
- }
- },
- "follow-redirects": {
- "version": "1.14.7",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
- "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
- },
- "for-in": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
- },
- "foreground-child": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz",
- "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.0",
- "signal-exit": "^3.0.2"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
- },
- "fork-ts-checker-webpack-plugin": {
- "version": "4.1.6",
- "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-4.1.6.tgz",
- "integrity": "sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==",
- "requires": {
- "@babel/code-frame": "^7.5.5",
- "chalk": "^2.4.1",
- "micromatch": "^3.1.10",
- "minimatch": "^3.0.4",
- "semver": "^5.6.0",
- "tapable": "^1.0.0",
- "worker-rpc": "^0.1.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "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"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
- "form-data": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
- "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.6",
- "mime-types": "^2.1.12"
- }
- },
- "format": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
- "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=",
- "dev": true
- },
- "forwarded": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
- "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
- },
- "fragment-cache": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
- "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
- "requires": {
- "map-cache": "^0.2.2"
- }
- },
- "framer-motion": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-3.10.0.tgz",
- "integrity": "sha512-i+Pp3bwMGHFZw3OnsMJGWeAxlAg6ye6Hbek3xRuoCmGjpOQrGKG7Ra249YFAk32wMSwmAbGUzxTE1fgP3ZOmnQ==",
- "requires": {
- "@emotion/is-prop-valid": "^0.8.2",
- "framesync": "5.2.0",
- "hey-listen": "^1.0.8",
- "popmotion": "9.3.1",
- "style-value-types": "4.1.1",
- "tslib": "^1.10.0"
- }
- },
- "framesync": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/framesync/-/framesync-5.2.0.tgz",
- "integrity": "sha512-dcl92w5SHc0o6pRK3//VBVNvu6WkYkiXmHG6ZIXrVzmgh0aDYMDAaoA3p3LH71JIdN5qmhDcfONFA4Lmq22tNA=="
- },
- "fresh": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
- "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
- },
- "from2": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
- "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
- "requires": {
- "inherits": "^2.0.1",
- "readable-stream": "^2.0.0"
- }
- },
- "fs-extra": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
- "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
- "requires": {
- "at-least-node": "^1.0.0",
- "graceful-fs": "^4.2.0",
- "jsonfile": "^6.0.1",
- "universalify": "^2.0.0"
- }
- },
- "fs-minipass": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
- "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "fs-mkdirp-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
- "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "through2": "^2.0.3"
- }
- },
- "fs-monkey": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
- "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
- "dev": true
- },
- "fs-write-stream-atomic": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
- "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
- "requires": {
- "graceful-fs": "^4.1.2",
- "iferr": "^0.1.5",
- "imurmurhash": "^0.1.4",
- "readable-stream": "1 || 2"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "fsevents": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
- "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "optional": true
- },
- "function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
- },
- "function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "functional-red-black-tree": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
- },
- "functions-have-names": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz",
- "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==",
- "dev": true
- },
- "fuse.js": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz",
- "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==",
- "dev": true
- },
- "gauge": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
- "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
- "requires": {
- "aproba": "^1.0.3",
- "console-control-strings": "^1.0.0",
- "has-unicode": "^2.0.0",
- "object-assign": "^4.1.0",
- "signal-exit": "^3.0.0",
- "string-width": "^1.0.1",
- "strip-ansi": "^3.0.1",
- "wide-align": "^1.1.0"
- }
- },
- "gaze": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
- "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
- "requires": {
- "globule": "^1.0.0"
- }
- },
- "gensync": {
- "version": "1.0.0-beta.2",
- "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
- "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
- },
- "get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
- },
- "get-intrinsic": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
- "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
- "requires": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1"
- }
- },
- "get-own-enumerable-property-symbols": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
- "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g=="
- },
- "get-package-type": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
- "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="
- },
- "get-stdin": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
- "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
- },
- "get-stream": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
- "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "requires": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- }
- },
- "get-value": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
- "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg="
- },
- "getos": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz",
- "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==",
- "dev": true,
- "requires": {
- "async": "^3.2.0"
- },
- "dependencies": {
- "async": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.1.tgz",
- "integrity": "sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==",
- "dev": true
- }
- }
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "requires": {
- "assert-plus": "^1.0.0"
- }
- },
- "github-slugger": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz",
- "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==",
- "dev": true
- },
- "glob": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
- "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
- "requires": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- }
- },
- "glob-promise": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/glob-promise/-/glob-promise-3.4.0.tgz",
- "integrity": "sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==",
- "dev": true,
- "requires": {
- "@types/glob": "*"
- }
- },
- "glob-stream": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
- "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
- "dev": true,
- "requires": {
- "extend": "^3.0.0",
- "glob": "^7.1.1",
- "glob-parent": "^3.1.0",
- "is-negated-glob": "^1.0.0",
- "ordered-read-streams": "^1.0.0",
- "pumpify": "^1.3.5",
- "readable-stream": "^2.1.5",
- "remove-trailing-separator": "^1.0.1",
- "to-absolute-glob": "^2.0.0",
- "unique-stream": "^2.0.2"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "requires": {
- "is-glob": "^4.0.3"
- }
- },
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "glob-to-regexp": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
- "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
- "dev": true
- },
- "global": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz",
- "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==",
- "dev": true,
- "requires": {
- "min-document": "^2.19.0",
- "process": "^0.11.10"
- }
- },
- "global-dirs": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz",
- "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==",
- "dev": true,
- "requires": {
- "ini": "2.0.0"
- },
- "dependencies": {
- "ini": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
- "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
- "dev": true
- }
- }
- },
- "global-modules": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
- "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==",
- "requires": {
- "global-prefix": "^3.0.0"
- }
- },
- "global-prefix": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz",
- "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==",
- "requires": {
- "ini": "^1.3.5",
- "kind-of": "^6.0.2",
- "which": "^1.3.1"
- },
- "dependencies": {
- "which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "requires": {
- "isexe": "^2.0.0"
- }
- }
- }
- },
- "globals": {
- "version": "11.12.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
- "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
- },
- "globalthis": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz",
- "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==",
- "dev": true,
- "requires": {
- "define-properties": "^1.1.3"
- }
- },
- "globby": {
- "version": "11.0.4",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz",
- "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==",
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.1.1",
- "ignore": "^5.1.4",
- "merge2": "^1.3.0",
- "slash": "^3.0.0"
- }
- },
- "globule": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz",
- "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==",
- "requires": {
- "glob": "~7.1.1",
- "lodash": "~4.17.10",
- "minimatch": "~3.0.2"
- }
- },
- "google-map-react": {
- "version": "2.1.9",
- "resolved": "https://registry.npmjs.org/google-map-react/-/google-map-react-2.1.9.tgz",
- "integrity": "sha512-//Pa0o6sdspU2H0ehVztSDQSnYYeV6TY4Z6ftty34yiCJYLliOzeq17dA9uFkyUFdL+XwbTU6e9mfs+bjBMIzw==",
- "requires": {
- "@googlemaps/js-api-loader": "^1.7.0",
- "@mapbox/point-geometry": "^0.1.0",
- "eventemitter3": "^4.0.4",
- "prop-types": "^15.7.2"
- }
- },
- "graceful-fs": {
- "version": "4.2.6",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz",
- "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ=="
- },
- "graceful-readlink": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
- "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
- "dev": true
- },
- "growly": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
- "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
- "optional": true
- },
- "gulp-sort": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/gulp-sort/-/gulp-sort-2.0.0.tgz",
- "integrity": "sha1-xnYqLx8N4KP8WVohWZ0/rI26Gso=",
- "dev": true,
- "requires": {
- "through2": "^2.0.1"
- }
- },
- "gzip-size": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
- "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==",
- "requires": {
- "duplexer": "^0.1.1",
- "pify": "^4.0.1"
- },
- "dependencies": {
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- }
- }
- },
- "handle-thing": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
- "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="
- },
- "handlebars": {
- "version": "4.7.7",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
- "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
- "dev": true,
- "requires": {
- "minimist": "^1.2.5",
- "neo-async": "^2.6.0",
- "source-map": "^0.6.1",
- "uglify-js": "^3.1.4",
- "wordwrap": "^1.0.0"
- }
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
- },
- "har-validator": {
- "version": "5.1.5",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
- "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
- "requires": {
- "ajv": "^6.12.3",
- "har-schema": "^2.0.0"
- }
- },
- "hard-rejection": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
- "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA=="
- },
- "harmony-reflect": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz",
- "integrity": "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g=="
- },
- "has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "requires": {
- "function-bind": "^1.1.1"
- }
- },
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "requires": {
- "ansi-regex": "^2.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "has-bigints": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz",
- "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA=="
- },
- "has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
- },
- "has-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz",
- "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=",
- "dev": true,
- "requires": {
- "is-glob": "^3.0.0"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "dev": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "has-symbols": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
- "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
- },
- "has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "requires": {
- "has-symbols": "^1.0.2"
- },
- "dependencies": {
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
- }
- }
- },
- "has-unicode": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
- "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
- },
- "has-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
- "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
- "requires": {
- "get-value": "^2.0.6",
- "has-values": "^1.0.0",
- "isobject": "^3.0.0"
- }
- },
- "has-values": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
- "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
- "requires": {
- "is-number": "^3.0.0",
- "kind-of": "^4.0.0"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "kind-of": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
- "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "hash-base": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
- "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
- "requires": {
- "inherits": "^2.0.4",
- "readable-stream": "^3.6.0",
- "safe-buffer": "^5.2.0"
- },
- "dependencies": {
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- }
- }
- },
- "hash.js": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
- "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
- "requires": {
- "inherits": "^2.0.3",
- "minimalistic-assert": "^1.0.1"
- }
- },
- "hast-to-hyperscript": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.1.tgz",
- "integrity": "sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==",
- "dev": true,
- "requires": {
- "@types/unist": "^2.0.3",
- "comma-separated-tokens": "^1.0.0",
- "property-information": "^5.3.0",
- "space-separated-tokens": "^1.0.0",
- "style-to-object": "^0.3.0",
- "unist-util-is": "^4.0.0",
- "web-namespaces": "^1.0.0"
- }
- },
- "hast-util-from-parse5": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz",
- "integrity": "sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==",
- "dev": true,
- "requires": {
- "@types/parse5": "^5.0.0",
- "hastscript": "^6.0.0",
- "property-information": "^5.0.0",
- "vfile": "^4.0.0",
- "vfile-location": "^3.2.0",
- "web-namespaces": "^1.0.0"
- }
- },
- "hast-util-parse-selector": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
- "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
- "dev": true
- },
- "hast-util-raw": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz",
- "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==",
- "dev": true,
- "requires": {
- "@types/hast": "^2.0.0",
- "hast-util-from-parse5": "^6.0.0",
- "hast-util-to-parse5": "^6.0.0",
- "html-void-elements": "^1.0.0",
- "parse5": "^6.0.0",
- "unist-util-position": "^3.0.0",
- "vfile": "^4.0.0",
- "web-namespaces": "^1.0.0",
- "xtend": "^4.0.0",
- "zwitch": "^1.0.0"
- }
- },
- "hast-util-to-parse5": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
- "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==",
- "dev": true,
- "requires": {
- "hast-to-hyperscript": "^9.0.0",
- "property-information": "^5.0.0",
- "web-namespaces": "^1.0.0",
- "xtend": "^4.0.0",
- "zwitch": "^1.0.0"
- }
- },
- "hastscript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
- "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
- "dev": true,
- "requires": {
- "@types/hast": "^2.0.0",
- "comma-separated-tokens": "^1.0.0",
- "hast-util-parse-selector": "^2.0.0",
- "property-information": "^5.0.0",
- "space-separated-tokens": "^1.0.0"
- }
- },
- "he": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
- "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
- },
- "hex-color-regex": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
- "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
- },
- "hey-listen": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
- "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
- },
- "highlight.js": {
- "version": "10.7.3",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
- "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
- "dev": true
- },
- "history": {
- "version": "4.10.1",
- "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
- "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
- "requires": {
- "@babel/runtime": "^7.1.2",
- "loose-envify": "^1.2.0",
- "resolve-pathname": "^3.0.0",
- "tiny-invariant": "^1.0.2",
- "tiny-warning": "^1.0.0",
- "value-equal": "^1.0.1"
- }
- },
- "hmac-drbg": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
- "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
- "requires": {
- "hash.js": "^1.0.3",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.1"
- }
- },
- "hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "requires": {
- "react-is": "^16.7.0"
- },
- "dependencies": {
- "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=="
- }
- }
- },
- "hoopy": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
- "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ=="
- },
- "hosted-git-info": {
- "version": "2.8.9",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
- "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
- },
- "hpack.js": {
- "version": "2.1.6",
- "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
- "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
- "requires": {
- "inherits": "^2.0.1",
- "obuf": "^1.0.0",
- "readable-stream": "^2.0.1",
- "wbuf": "^1.1.0"
- }
- },
- "hsl-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
- "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4="
- },
- "hsla-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
- "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg="
- },
- "html-encoding-sniffer": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
- "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
- "requires": {
- "whatwg-encoding": "^1.0.5"
- }
- },
- "html-entities": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz",
- "integrity": "sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA=="
- },
- "html-escaper": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
- "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
- },
- "html-minifier-terser": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
- "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==",
- "requires": {
- "camel-case": "^4.1.1",
- "clean-css": "^4.2.3",
- "commander": "^4.1.1",
- "he": "^1.2.0",
- "param-case": "^3.0.3",
- "relateurl": "^0.2.7",
- "terser": "^4.6.3"
- }
- },
- "html-parse-stringify2": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
- "integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
- "requires": {
- "void-elements": "^2.0.1"
- }
- },
- "html-tags": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
- "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
- "dev": true
- },
- "html-to-react": {
- "version": "1.4.5",
- "resolved": "https://registry.npmjs.org/html-to-react/-/html-to-react-1.4.5.tgz",
- "integrity": "sha512-KONZUDFPg5OodWaQu2ymfkDmU0JA7zB1iPfvyHehTmMUZnk0DS7/TyCMTzsLH6b4BvxX15g88qZCXFhJWktsmA==",
- "requires": {
- "domhandler": "^3.3.0",
- "htmlparser2": "^5.0",
- "lodash.camelcase": "^4.3.0",
- "ramda": "^0.27.1"
- }
- },
- "html-void-elements": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz",
- "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==",
- "dev": true
- },
- "html-webpack-plugin": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz",
- "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==",
- "requires": {
- "@types/html-minifier-terser": "^5.0.0",
- "@types/tapable": "^1.0.5",
- "@types/webpack": "^4.41.8",
- "html-minifier-terser": "^5.0.1",
- "loader-utils": "^1.2.3",
- "lodash": "^4.17.15",
- "pretty-error": "^2.1.1",
- "tapable": "^1.1.3",
- "util.promisify": "1.0.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- }
- },
- "util.promisify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
- "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==",
- "requires": {
- "define-properties": "^1.1.2",
- "object.getownpropertydescriptors": "^2.0.3"
- }
- }
- }
- },
- "html2canvas": {
- "version": "1.0.0-rc.7",
- "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-rc.7.tgz",
- "integrity": "sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA==",
- "requires": {
- "css-line-break": "1.1.1"
- }
- },
- "htmlparser2": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-5.0.1.tgz",
- "integrity": "sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==",
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^3.3.0",
- "domutils": "^2.4.2",
- "entities": "^2.0.0"
- }
- },
- "http-deceiver": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
- "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc="
- },
- "http-errors": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
- "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.1",
- "statuses": ">= 1.5.0 < 2",
- "toidentifier": "1.0.0"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
- }
- }
- },
- "http-parser-js": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz",
- "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg=="
- },
- "http-proxy": {
- "version": "1.18.1",
- "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
- "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
- "requires": {
- "eventemitter3": "^4.0.0",
- "follow-redirects": "^1.0.0",
- "requires-port": "^1.0.0"
- }
- },
- "http-proxy-agent": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
- "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
- "requires": {
- "@tootallnate/once": "1",
- "agent-base": "6",
- "debug": "4"
- }
- },
- "http-proxy-middleware": {
- "version": "0.19.1",
- "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
- "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
- "requires": {
- "http-proxy": "^1.17.0",
- "is-glob": "^4.0.0",
- "lodash": "^4.17.11",
- "micromatch": "^3.1.10"
- },
- "dependencies": {
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "requires": {
- "assert-plus": "^1.0.0",
- "jsprim": "^1.2.2",
- "sshpk": "^1.7.0"
- }
- },
- "https-browserify": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
- "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
- },
- "https-proxy-agent": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
- "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
- "requires": {
- "agent-base": "6",
- "debug": "4"
- }
- },
- "human-signals": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
- "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
- },
- "hyphenate-style-name": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz",
- "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ=="
- },
- "i18next": {
- "version": "19.9.0",
- "resolved": "https://registry.npmjs.org/i18next/-/i18next-19.9.0.tgz",
- "integrity": "sha512-5zRG3aFl+e+LsdpVUp0dKkVhYH2iCv+gxyzXP1q2oJUc3BV26fqX87cBE3AHkMOir1X0liOaSoxS/Kg95iEcEQ==",
- "requires": {
- "@babel/runtime": "^7.12.0"
- }
- },
- "i18next-browser-languagedetector": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.0.1.tgz",
- "integrity": "sha512-3H+OsNQn3FciomUU0d4zPFHsvJv4X66lBelXk9hnIDYDsveIgT7dWZ3/VvcSlpKk9lvCK770blRZ/CwHMXZqWw==",
- "requires": {
- "@babel/runtime": "^7.5.5"
- }
- },
- "i18next-parser": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/i18next-parser/-/i18next-parser-3.6.0.tgz",
- "integrity": "sha512-XMXvMp+qSs7NOwDoEUipkT/PHesGyvw0tjIBR1w1+ROYYxCMqn8zd/UAtBHq3wKLjqWLtL+/JCS5aO+NxKsqjw==",
- "dev": true,
- "requires": {
- "broccoli-plugin": "^1.3.0",
- "cheerio": "^1.0.0-rc.2",
- "colors": "~1.2.0-rc0",
- "commander": "~2.9.0",
- "concat-stream": "~1.6.0",
- "eol": "^0.9.1",
- "fs-extra": "^6.0.1",
- "gulp-sort": "^2.0.0",
- "i18next": "^19.0.1",
- "js-yaml": "^3.14.0",
- "rsvp": "^4.8.2",
- "through2": "~2.0.3",
- "typescript": "^3.6.4",
- "vinyl": "~2.0.1",
- "vinyl-fs": "^3.0.2",
- "vue-template-compiler": "^2.6.11"
- },
- "dependencies": {
- "colors": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz",
- "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==",
- "dev": true
- },
- "commander": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
- "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
- "dev": true,
- "requires": {
- "graceful-readlink": ">= 1.0.0"
- }
- },
- "fs-extra": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
- "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
- "dev": true
- }
- }
- },
- "i18next-xhr-backend": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/i18next-xhr-backend/-/i18next-xhr-backend-3.2.2.tgz",
- "integrity": "sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==",
- "requires": {
- "@babel/runtime": "^7.5.5"
- }
- },
- "icepick": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/icepick/-/icepick-1.3.0.tgz",
- "integrity": "sha1-5JQoQu2Pnud419149+NmJ/Sf2u8="
- },
- "iconv-lite": {
- "version": "0.4.24",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
- "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3"
- }
- },
- "icss-utils": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
- "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==",
- "requires": {
- "postcss": "^7.0.14"
- }
- },
- "identity-obj-proxy": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz",
- "integrity": "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ=",
- "requires": {
- "harmony-reflect": "^1.4.6"
- }
- },
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
- },
- "iferr": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
- "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE="
- },
- "ignore": {
- "version": "5.1.8",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
- "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
- },
- "immer": {
- "version": "9.0.12",
- "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
- "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
- },
- "import-cwd": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
- "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
- "requires": {
- "import-from": "^2.1.0"
- }
- },
- "import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "requires": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- }
- },
- "import-from": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
- "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
- "requires": {
- "resolve-from": "^3.0.0"
- },
- "dependencies": {
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
- }
- }
- },
- "import-local": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz",
- "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==",
- "requires": {
- "pkg-dir": "^4.2.0",
- "resolve-cwd": "^3.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "requires": {
- "find-up": "^4.0.0"
- }
- }
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
- },
- "indefinite-observable": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz",
- "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==",
- "requires": {
- "symbol-observable": "1.2.0"
- }
- },
- "indent-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
- "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
- },
- "indexes-of": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
- "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc="
- },
- "infer-owner": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
- "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A=="
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "requires": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "ini": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
- "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
- },
- "inline-style-parser": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
- "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==",
- "dev": true
- },
- "internal-ip": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
- "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
- "requires": {
- "default-gateway": "^4.2.0",
- "ipaddr.js": "^1.9.0"
- }
- },
- "internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "requires": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- }
- },
- "interpret": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
- "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
- "dev": true
- },
- "invariant": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
- "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
- "requires": {
- "loose-envify": "^1.0.0"
- }
- },
- "ip": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
- "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
- },
- "ip-regex": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
- "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
- },
- "ipaddr.js": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
- "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
- },
- "is-absolute": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
- "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
- "dev": true,
- "requires": {
- "is-relative": "^1.0.0",
- "is-windows": "^1.0.1"
- }
- },
- "is-absolute-url": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
- "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY="
- },
- "is-accessor-descriptor": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
- "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-alphabetical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
- "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg=="
- },
- "is-alphanumerical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
- "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
- "requires": {
- "is-alphabetical": "^1.0.0",
- "is-decimal": "^1.0.0"
- }
- },
- "is-arguments": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz",
- "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==",
- "requires": {
- "call-bind": "^1.0.0"
- }
- },
- "is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
- },
- "is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "requires": {
- "has-bigints": "^1.0.1"
- }
- },
- "is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "requires": {
- "binary-extensions": "^2.0.0"
- }
- },
- "is-blob": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz",
- "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw=="
- },
- "is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-buffer": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
- "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
- },
- "is-callable": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz",
- "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ=="
- },
- "is-ci": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
- "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
- "requires": {
- "ci-info": "^2.0.0"
- }
- },
- "is-color-stop": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
- "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
- "requires": {
- "css-color-names": "^0.0.4",
- "hex-color-regex": "^1.1.0",
- "hsl-regex": "^1.0.0",
- "hsla-regex": "^1.0.0",
- "rgb-regex": "^1.0.1",
- "rgba-regex": "^1.0.0"
- }
- },
- "is-core-module": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz",
- "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "is-data-descriptor": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
- "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-date-object": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
- "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
- },
- "is-decimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
- "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw=="
- },
- "is-descriptor": {
- "version": "0.1.6",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
- "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
- "requires": {
- "is-accessor-descriptor": "^0.1.6",
- "is-data-descriptor": "^0.1.4",
- "kind-of": "^5.0.0"
- },
- "dependencies": {
- "kind-of": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
- "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
- }
- }
- },
- "is-directory": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
- "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
- },
- "is-docker": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
- "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw=="
- },
- "is-dom": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-dom/-/is-dom-1.1.0.tgz",
- "integrity": "sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==",
- "dev": true,
- "requires": {
- "is-object": "^1.0.1",
- "is-window": "^1.0.2"
- }
- },
- "is-extendable": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
- },
- "is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "requires": {
- "number-is-nan": "^1.0.0"
- }
- },
- "is-function": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz",
- "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==",
- "dev": true
- },
- "is-generator-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
- "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="
- },
- "is-glob": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
- "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
- "requires": {
- "is-extglob": "^2.1.1"
- }
- },
- "is-hexadecimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
- "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw=="
- },
- "is-in-browser": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
- "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
- },
- "is-installed-globally": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz",
- "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==",
- "dev": true,
- "requires": {
- "global-dirs": "^3.0.0",
- "is-path-inside": "^3.0.2"
- },
- "dependencies": {
- "is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true
- }
- }
- },
- "is-lite": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.6.0.tgz",
- "integrity": "sha512-kJ16DuwOhtZg7RimZOf+zK86XOlPeNGGy20MhAfjN/zozuetECxOEtUDUAtzC5n21Yd2lVx6LqZvO1Zvd5DYhw=="
- },
- "is-map": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz",
- "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==",
- "dev": true
- },
- "is-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
- "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE="
- },
- "is-negated-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
- "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
- "dev": true
- },
- "is-negative-zero": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz",
- "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w=="
- },
- "is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
- },
- "is-number-object": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz",
- "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==",
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-obj": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
- "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
- },
- "is-object": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz",
- "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==",
- "dev": true
- },
- "is-path-cwd": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
- "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ=="
- },
- "is-path-in-cwd": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
- "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
- "requires": {
- "is-path-inside": "^2.1.0"
- }
- },
- "is-path-inside": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
- "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
- "requires": {
- "path-is-inside": "^1.0.2"
- }
- },
- "is-plain-obj": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
- "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
- },
- "is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "requires": {
- "isobject": "^3.0.1"
- }
- },
- "is-potential-custom-element-name": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
- "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
- },
- "is-primitive": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-3.0.1.tgz",
- "integrity": "sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w=="
- },
- "is-regex": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz",
- "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==",
- "requires": {
- "call-bind": "^1.0.2",
- "has-symbols": "^1.0.1"
- }
- },
- "is-regexp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
- "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk="
- },
- "is-relative": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
- "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
- "dev": true,
- "requires": {
- "is-unc-path": "^1.0.0"
- }
- },
- "is-resolvable": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
- "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg=="
- },
- "is-root": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz",
- "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg=="
- },
- "is-set": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz",
- "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==",
- "dev": true
- },
- "is-shared-array-buffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz",
- "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA=="
- },
- "is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
- },
- "is-string": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz",
- "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ=="
- },
- "is-symbol": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
- "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
- "requires": {
- "has-symbols": "^1.0.1"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
- },
- "is-unc-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
- "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
- "dev": true,
- "requires": {
- "unc-path-regex": "^0.1.2"
- }
- },
- "is-unicode-supported": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
- "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
- "dev": true
- },
- "is-utf8": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
- "dev": true
- },
- "is-valid-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
- "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
- "dev": true
- },
- "is-weakref": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz",
- "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==",
- "requires": {
- "call-bind": "^1.0.0"
- }
- },
- "is-whitespace-character": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
- "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
- "dev": true
- },
- "is-window": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz",
- "integrity": "sha1-LIlspT25feRdPDMTOmXYyfVjSA0=",
- "dev": true
- },
- "is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
- },
- "is-word-character": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
- "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
- "dev": true
- },
- "is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "requires": {
- "is-docker": "^2.0.0"
- }
- },
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
- },
- "isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
- },
- "istanbul-lib-coverage": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
- "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg=="
- },
- "istanbul-lib-instrument": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
- "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
- "requires": {
- "@babel/core": "^7.7.5",
- "@istanbuljs/schema": "^0.1.2",
- "istanbul-lib-coverage": "^3.0.0",
- "semver": "^6.3.0"
- },
- "dependencies": {
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "istanbul-lib-report": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
- "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==",
- "requires": {
- "istanbul-lib-coverage": "^3.0.0",
- "make-dir": "^3.0.0",
- "supports-color": "^7.1.0"
- },
- "dependencies": {
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- }
- }
- },
- "istanbul-lib-source-maps": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
- "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
- "requires": {
- "debug": "^4.1.1",
- "istanbul-lib-coverage": "^3.0.0",
- "source-map": "^0.6.1"
- }
- },
- "istanbul-reports": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
- "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
- "requires": {
- "html-escaper": "^2.0.0",
- "istanbul-lib-report": "^3.0.0"
- }
- },
- "iterate-iterator": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/iterate-iterator/-/iterate-iterator-1.0.2.tgz",
- "integrity": "sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==",
- "dev": true
- },
- "iterate-value": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/iterate-value/-/iterate-value-1.0.2.tgz",
- "integrity": "sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==",
- "dev": true,
- "requires": {
- "es-get-iterator": "^1.0.2",
- "iterate-iterator": "^1.0.1"
- }
- },
- "jest": {
- "version": "26.6.0",
- "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.0.tgz",
- "integrity": "sha512-jxTmrvuecVISvKFFhOkjsWRZV7sFqdSUAd1ajOKY+/QE/aLBVstsJ/dX8GczLzwiT6ZEwwmZqtCUHLHHQVzcfA==",
- "requires": {
- "@jest/core": "^26.6.0",
- "import-local": "^3.0.2",
- "jest-cli": "^26.6.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- },
- "jest-cli": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz",
- "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==",
- "requires": {
- "@jest/core": "^26.6.3",
- "@jest/test-result": "^26.6.2",
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.4",
- "import-local": "^3.0.2",
- "is-ci": "^2.0.0",
- "jest-config": "^26.6.3",
- "jest-util": "^26.6.2",
- "jest-validate": "^26.6.2",
- "prompts": "^2.0.1",
- "yargs": "^15.4.1"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "requires": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- }
- }
- },
- "jest-changed-files": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz",
- "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "execa": "^4.0.0",
- "throat": "^5.0.0"
- },
- "dependencies": {
- "execa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
- "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
- "requires": {
- "cross-spawn": "^7.0.0",
- "get-stream": "^5.0.0",
- "human-signals": "^1.1.1",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.0",
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2",
- "strip-final-newline": "^2.0.0"
- }
- },
- "get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "requires": {
- "path-key": "^3.0.0"
- }
- }
- }
- },
- "jest-circus": {
- "version": "26.6.0",
- "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-26.6.0.tgz",
- "integrity": "sha512-L2/Y9szN6FJPWFK8kzWXwfp+FOR7xq0cUL4lIsdbIdwz3Vh6P1nrpcqOleSzr28zOtSHQNV9Z7Tl+KkuK7t5Ng==",
- "requires": {
- "@babel/traverse": "^7.1.0",
- "@jest/environment": "^26.6.0",
- "@jest/test-result": "^26.6.0",
- "@jest/types": "^26.6.0",
- "@types/babel__traverse": "^7.0.4",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "co": "^4.6.0",
- "dedent": "^0.7.0",
- "expect": "^26.6.0",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^26.6.0",
- "jest-matcher-utils": "^26.6.0",
- "jest-message-util": "^26.6.0",
- "jest-runner": "^26.6.0",
- "jest-runtime": "^26.6.0",
- "jest-snapshot": "^26.6.0",
- "jest-util": "^26.6.0",
- "pretty-format": "^26.6.0",
- "stack-utils": "^2.0.2",
- "throat": "^5.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-config": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz",
- "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==",
- "requires": {
- "@babel/core": "^7.1.0",
- "@jest/test-sequencer": "^26.6.3",
- "@jest/types": "^26.6.2",
- "babel-jest": "^26.6.3",
- "chalk": "^4.0.0",
- "deepmerge": "^4.2.2",
- "glob": "^7.1.1",
- "graceful-fs": "^4.2.4",
- "jest-environment-jsdom": "^26.6.2",
- "jest-environment-node": "^26.6.2",
- "jest-get-type": "^26.3.0",
- "jest-jasmine2": "^26.6.3",
- "jest-regex-util": "^26.0.0",
- "jest-resolve": "^26.6.2",
- "jest-util": "^26.6.2",
- "jest-validate": "^26.6.2",
- "micromatch": "^4.0.2",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- }
- }
- },
- "jest-diff": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz",
- "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==",
- "requires": {
- "chalk": "^4.0.0",
- "diff-sequences": "^26.6.2",
- "jest-get-type": "^26.3.0",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-docblock": {
- "version": "26.0.0",
- "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz",
- "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==",
- "requires": {
- "detect-newline": "^3.0.0"
- }
- },
- "jest-each": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz",
- "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "jest-get-type": "^26.3.0",
- "jest-util": "^26.6.2",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-environment-jsdom": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz",
- "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==",
- "requires": {
- "@jest/environment": "^26.6.2",
- "@jest/fake-timers": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "jest-mock": "^26.6.2",
- "jest-util": "^26.6.2",
- "jsdom": "^16.4.0"
- }
- },
- "jest-environment-jsdom-fourteen": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/jest-environment-jsdom-fourteen/-/jest-environment-jsdom-fourteen-1.0.1.tgz",
- "integrity": "sha512-DojMX1sY+at5Ep+O9yME34CdidZnO3/zfPh8UW+918C5fIZET5vCjfkegixmsi7AtdYfkr4bPlIzmWnlvQkP7Q==",
- "dev": true,
- "requires": {
- "@jest/environment": "^24.3.0",
- "@jest/fake-timers": "^24.3.0",
- "@jest/types": "^24.3.0",
- "jest-mock": "^24.0.0",
- "jest-util": "^24.0.0",
- "jsdom": "^14.1.0"
- },
- "dependencies": {
- "@jest/console": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz",
- "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==",
- "dev": true,
- "requires": {
- "@jest/source-map": "^24.9.0",
- "chalk": "^2.0.1",
- "slash": "^2.0.0"
- }
- },
- "@jest/environment": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz",
- "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==",
- "dev": true,
- "requires": {
- "@jest/fake-timers": "^24.9.0",
- "@jest/transform": "^24.9.0",
- "@jest/types": "^24.9.0",
- "jest-mock": "^24.9.0"
- }
- },
- "@jest/fake-timers": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz",
- "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==",
- "dev": true,
- "requires": {
- "@jest/types": "^24.9.0",
- "jest-message-util": "^24.9.0",
- "jest-mock": "^24.9.0"
- }
- },
- "@jest/source-map": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz",
- "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==",
- "dev": true,
- "requires": {
- "callsites": "^3.0.0",
- "graceful-fs": "^4.1.15",
- "source-map": "^0.6.0"
- }
- },
- "@jest/test-result": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz",
- "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==",
- "dev": true,
- "requires": {
- "@jest/console": "^24.9.0",
- "@jest/types": "^24.9.0",
- "@types/istanbul-lib-coverage": "^2.0.0"
- }
- },
- "@jest/transform": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz",
- "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.1.0",
- "@jest/types": "^24.9.0",
- "babel-plugin-istanbul": "^5.1.0",
- "chalk": "^2.0.1",
- "convert-source-map": "^1.4.0",
- "fast-json-stable-stringify": "^2.0.0",
- "graceful-fs": "^4.1.15",
- "jest-haste-map": "^24.9.0",
- "jest-regex-util": "^24.9.0",
- "jest-util": "^24.9.0",
- "micromatch": "^3.1.10",
- "pirates": "^4.0.1",
- "realpath-native": "^1.1.0",
- "slash": "^2.0.0",
- "source-map": "^0.6.1",
- "write-file-atomic": "2.4.1"
- }
- },
- "@jest/types": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz",
- "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^1.1.1",
- "@types/yargs": "^13.0.0"
- }
- },
- "@types/istanbul-reports": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz",
- "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "*",
- "@types/istanbul-lib-report": "*"
- }
- },
- "@types/stack-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
- "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
- "dev": true
- },
- "@types/yargs": {
- "version": "13.0.11",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.11.tgz",
- "integrity": "sha512-NRqD6T4gktUrDi1o1wLH3EKC1o2caCr7/wR87ODcbVITQF106OM3sFN92ysZ++wqelOd1CTzatnOBRDYYG6wGQ==",
- "dev": true,
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "acorn": {
- "version": "6.4.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
- "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
- "dev": true
- },
- "acorn-globals": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
- "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
- "dev": true,
- "requires": {
- "acorn": "^6.0.1",
- "acorn-walk": "^6.0.1"
- }
- },
- "acorn-walk": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
- "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
- "dev": true
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "dev": true,
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- }
- },
- "babel-plugin-istanbul": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz",
- "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.0.0",
- "find-up": "^3.0.0",
- "istanbul-lib-instrument": "^3.3.0",
- "test-exclude": "^5.2.3"
- }
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "dev": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "cssom": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
- "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
- "dev": true
- },
- "cssstyle": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz",
- "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==",
- "dev": true,
- "requires": {
- "cssom": "0.3.x"
- }
- },
- "data-urls": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
- "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
- "dev": true,
- "requires": {
- "abab": "^2.0.0",
- "whatwg-mimetype": "^2.2.0",
- "whatwg-url": "^7.0.0"
- }
- },
- "domexception": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
- "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
- "dev": true,
- "requires": {
- "webidl-conversions": "^4.0.2"
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "dev": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "dev": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "dev": true,
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "fsevents": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
- "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
- "dev": true,
- "optional": true,
- "requires": {
- "nan": "^2.12.1"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "html-encoding-sniffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
- "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
- "dev": true,
- "requires": {
- "whatwg-encoding": "^1.0.1"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "dev": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "istanbul-lib-coverage": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz",
- "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==",
- "dev": true
- },
- "istanbul-lib-instrument": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz",
- "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==",
- "dev": true,
- "requires": {
- "@babel/generator": "^7.4.0",
- "@babel/parser": "^7.4.3",
- "@babel/template": "^7.4.0",
- "@babel/traverse": "^7.4.3",
- "@babel/types": "^7.4.0",
- "istanbul-lib-coverage": "^2.0.5",
- "semver": "^6.0.0"
- }
- },
- "jest-haste-map": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz",
- "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==",
- "dev": true,
- "requires": {
- "@jest/types": "^24.9.0",
- "anymatch": "^2.0.0",
- "fb-watchman": "^2.0.0",
- "fsevents": "^1.2.7",
- "graceful-fs": "^4.1.15",
- "invariant": "^2.2.4",
- "jest-serializer": "^24.9.0",
- "jest-util": "^24.9.0",
- "jest-worker": "^24.9.0",
- "micromatch": "^3.1.10",
- "sane": "^4.0.3",
- "walker": "^1.0.7"
- }
- },
- "jest-message-util": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz",
- "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@jest/test-result": "^24.9.0",
- "@jest/types": "^24.9.0",
- "@types/stack-utils": "^1.0.1",
- "chalk": "^2.0.1",
- "micromatch": "^3.1.10",
- "slash": "^2.0.0",
- "stack-utils": "^1.0.1"
- }
- },
- "jest-mock": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz",
- "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==",
- "dev": true,
- "requires": {
- "@jest/types": "^24.9.0"
- }
- },
- "jest-regex-util": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz",
- "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==",
- "dev": true
- },
- "jest-serializer": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz",
- "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==",
- "dev": true
- },
- "jest-util": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz",
- "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==",
- "dev": true,
- "requires": {
- "@jest/console": "^24.9.0",
- "@jest/fake-timers": "^24.9.0",
- "@jest/source-map": "^24.9.0",
- "@jest/test-result": "^24.9.0",
- "@jest/types": "^24.9.0",
- "callsites": "^3.0.0",
- "chalk": "^2.0.1",
- "graceful-fs": "^4.1.15",
- "is-ci": "^2.0.0",
- "mkdirp": "^0.5.1",
- "slash": "^2.0.0",
- "source-map": "^0.6.0"
- }
- },
- "jest-worker": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
- "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
- "dev": true,
- "requires": {
- "merge-stream": "^2.0.0",
- "supports-color": "^6.1.0"
- },
- "dependencies": {
- "supports-color": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
- "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "jsdom": {
- "version": "14.1.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-14.1.0.tgz",
- "integrity": "sha512-O901mfJSuTdwU2w3Sn+74T+RnDVP+FuV5fH8tcPWyqrseRAb0s5xOtPgCFiPOtLcyK7CLIJwPyD83ZqQWvA5ng==",
- "dev": true,
- "requires": {
- "abab": "^2.0.0",
- "acorn": "^6.0.4",
- "acorn-globals": "^4.3.0",
- "array-equal": "^1.0.0",
- "cssom": "^0.3.4",
- "cssstyle": "^1.1.1",
- "data-urls": "^1.1.0",
- "domexception": "^1.0.1",
- "escodegen": "^1.11.0",
- "html-encoding-sniffer": "^1.0.2",
- "nwsapi": "^2.1.3",
- "parse5": "5.1.0",
- "pn": "^1.1.0",
- "request": "^2.88.0",
- "request-promise-native": "^1.0.5",
- "saxes": "^3.1.9",
- "symbol-tree": "^3.2.2",
- "tough-cookie": "^2.5.0",
- "w3c-hr-time": "^1.0.1",
- "w3c-xmlserializer": "^1.1.2",
- "webidl-conversions": "^4.0.2",
- "whatwg-encoding": "^1.0.5",
- "whatwg-mimetype": "^2.3.0",
- "whatwg-url": "^7.0.0",
- "ws": "^6.1.2",
- "xml-name-validator": "^3.0.0"
- }
- },
- "load-json-file": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
- "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.2",
- "parse-json": "^4.0.0",
- "pify": "^3.0.0",
- "strip-bom": "^3.0.0"
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "dev": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- },
- "parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
- "dev": true,
- "requires": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- }
- },
- "parse5": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
- "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
- "dev": true
- },
- "path-type": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
- "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
- "dev": true,
- "requires": {
- "pify": "^3.0.0"
- }
- },
- "pify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
- "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
- "dev": true
- },
- "read-pkg": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
- "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
- "dev": true,
- "requires": {
- "load-json-file": "^4.0.0",
- "normalize-package-data": "^2.3.2",
- "path-type": "^3.0.0"
- }
- },
- "read-pkg-up": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz",
- "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==",
- "dev": true,
- "requires": {
- "find-up": "^3.0.0",
- "read-pkg": "^3.0.0"
- }
- },
- "saxes": {
- "version": "3.1.11",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
- "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
- "dev": true,
- "requires": {
- "xmlchars": "^2.1.1"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "slash": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
- "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
- "dev": true
- },
- "stack-utils": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.4.tgz",
- "integrity": "sha512-IPDJfugEGbfizBwBZRZ3xpccMdRyP5lqsBWXGQWimVjua/ccLCeMOAVjlc1R7LxFjo5sEDhyNIXd8mo/AiDS9w==",
- "dev": true,
- "requires": {
- "escape-string-regexp": "^2.0.0"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true
- }
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "test-exclude": {
- "version": "5.2.3",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz",
- "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3",
- "minimatch": "^3.0.4",
- "read-pkg-up": "^4.0.0",
- "require-main-filename": "^2.0.0"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "dev": true,
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- },
- "tr46": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
- "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
- "dev": true,
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "w3c-xmlserializer": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
- "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
- "dev": true,
- "requires": {
- "domexception": "^1.0.1",
- "webidl-conversions": "^4.0.2",
- "xml-name-validator": "^3.0.0"
- }
- },
- "webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true
- },
- "whatwg-url": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
- "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
- "dev": true,
- "requires": {
- "lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
- }
- },
- "write-file-atomic": {
- "version": "2.4.1",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz",
- "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "imurmurhash": "^0.1.4",
- "signal-exit": "^3.0.2"
- }
- },
- "ws": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
- "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
- "dev": true,
- "requires": {
- "async-limiter": "~1.0.0"
- }
- }
- }
- },
- "jest-environment-node": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz",
- "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==",
- "requires": {
- "@jest/environment": "^26.6.2",
- "@jest/fake-timers": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "jest-mock": "^26.6.2",
- "jest-util": "^26.6.2"
- }
- },
- "jest-get-type": {
- "version": "26.3.0",
- "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
- "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig=="
- },
- "jest-haste-map": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz",
- "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==",
- "requires": {
- "@jest/types": "^26.6.2",
- "@types/graceful-fs": "^4.1.2",
- "@types/node": "*",
- "anymatch": "^3.0.3",
- "fb-watchman": "^2.0.0",
- "fsevents": "^2.1.2",
- "graceful-fs": "^4.2.4",
- "jest-regex-util": "^26.0.0",
- "jest-serializer": "^26.6.2",
- "jest-util": "^26.6.2",
- "jest-worker": "^26.6.2",
- "micromatch": "^4.0.2",
- "sane": "^4.0.3",
- "walker": "^1.0.7"
- }
- },
- "jest-jasmine2": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz",
- "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==",
- "requires": {
- "@babel/traverse": "^7.1.0",
- "@jest/environment": "^26.6.2",
- "@jest/source-map": "^26.6.2",
- "@jest/test-result": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "co": "^4.6.0",
- "expect": "^26.6.2",
- "is-generator-fn": "^2.0.0",
- "jest-each": "^26.6.2",
- "jest-matcher-utils": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-runtime": "^26.6.3",
- "jest-snapshot": "^26.6.2",
- "jest-util": "^26.6.2",
- "pretty-format": "^26.6.2",
- "throat": "^5.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-leak-detector": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz",
- "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==",
- "requires": {
- "jest-get-type": "^26.3.0",
- "pretty-format": "^26.6.2"
- }
- },
- "jest-matcher-utils": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz",
- "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==",
- "requires": {
- "chalk": "^4.0.0",
- "jest-diff": "^26.6.2",
- "jest-get-type": "^26.3.0",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-message-util": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz",
- "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "@jest/types": "^26.6.2",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "micromatch": "^4.0.2",
- "pretty-format": "^26.6.2",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-mock": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz",
- "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==",
- "requires": {
- "@jest/types": "^26.6.2",
- "@types/node": "*"
- }
- },
- "jest-pnp-resolver": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
- "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w=="
- },
- "jest-regex-util": {
- "version": "26.0.0",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz",
- "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A=="
- },
- "jest-resolve": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz",
- "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==",
- "dev": true,
- "requires": {
- "@jest/types": "^24.9.0",
- "browser-resolve": "^1.11.3",
- "chalk": "^2.0.1",
- "jest-pnp-resolver": "^1.2.1",
- "realpath-native": "^1.1.0"
- },
- "dependencies": {
- "@jest/types": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz",
- "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^1.1.1",
- "@types/yargs": "^13.0.0"
- }
- },
- "@types/istanbul-reports": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz",
- "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "*",
- "@types/istanbul-lib-report": "*"
- }
- },
- "@types/yargs": {
- "version": "13.0.12",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.12.tgz",
- "integrity": "sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ==",
- "dev": true,
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "jest-resolve-dependencies": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz",
- "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==",
- "requires": {
- "@jest/types": "^26.6.2",
- "jest-regex-util": "^26.0.0",
- "jest-snapshot": "^26.6.2"
- }
- },
- "jest-runner": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz",
- "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==",
- "requires": {
- "@jest/console": "^26.6.2",
- "@jest/environment": "^26.6.2",
- "@jest/test-result": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "emittery": "^0.7.1",
- "exit": "^0.1.2",
- "graceful-fs": "^4.2.4",
- "jest-config": "^26.6.3",
- "jest-docblock": "^26.0.0",
- "jest-haste-map": "^26.6.2",
- "jest-leak-detector": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-resolve": "^26.6.2",
- "jest-runtime": "^26.6.3",
- "jest-util": "^26.6.2",
- "jest-worker": "^26.6.2",
- "source-map-support": "^0.5.6",
- "throat": "^5.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- }
- }
- },
- "jest-runtime": {
- "version": "26.6.3",
- "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz",
- "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==",
- "requires": {
- "@jest/console": "^26.6.2",
- "@jest/environment": "^26.6.2",
- "@jest/fake-timers": "^26.6.2",
- "@jest/globals": "^26.6.2",
- "@jest/source-map": "^26.6.2",
- "@jest/test-result": "^26.6.2",
- "@jest/transform": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/yargs": "^15.0.0",
- "chalk": "^4.0.0",
- "cjs-module-lexer": "^0.6.0",
- "collect-v8-coverage": "^1.0.0",
- "exit": "^0.1.2",
- "glob": "^7.1.3",
- "graceful-fs": "^4.2.4",
- "jest-config": "^26.6.3",
- "jest-haste-map": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-mock": "^26.6.2",
- "jest-regex-util": "^26.0.0",
- "jest-resolve": "^26.6.2",
- "jest-snapshot": "^26.6.2",
- "jest-util": "^26.6.2",
- "jest-validate": "^26.6.2",
- "slash": "^3.0.0",
- "strip-bom": "^4.0.0",
- "yargs": "^15.4.1"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "requires": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "requires": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- }
- },
- "yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- }
- }
- }
- },
- "jest-serializer": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz",
- "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==",
- "requires": {
- "@types/node": "*",
- "graceful-fs": "^4.2.4"
- }
- },
- "jest-snapshot": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz",
- "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==",
- "requires": {
- "@babel/types": "^7.0.0",
- "@jest/types": "^26.6.2",
- "@types/babel__traverse": "^7.0.4",
- "@types/prettier": "^2.0.0",
- "chalk": "^4.0.0",
- "expect": "^26.6.2",
- "graceful-fs": "^4.2.4",
- "jest-diff": "^26.6.2",
- "jest-get-type": "^26.3.0",
- "jest-haste-map": "^26.6.2",
- "jest-matcher-utils": "^26.6.2",
- "jest-message-util": "^26.6.2",
- "jest-resolve": "^26.6.2",
- "natural-compare": "^1.4.0",
- "pretty-format": "^26.6.2",
- "semver": "^7.3.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz",
- "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.2",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.18.1",
- "slash": "^3.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "semver": {
- "version": "7.3.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
- "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "jest-specific-snapshot": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jest-specific-snapshot/-/jest-specific-snapshot-4.0.0.tgz",
- "integrity": "sha512-YdW5P/MVwOizWR0MJwURxdrjdXvdG2MMpXKVGr7dZ2YrBmE6E6Ab74UL3DOYmGmzaCnNAW1CL02pY5MTHE3ulQ==",
- "dev": true,
- "requires": {
- "jest-snapshot": "^26.3.0"
- }
- },
- "jest-util": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz",
- "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==",
- "requires": {
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "is-ci": "^2.0.0",
- "micromatch": "^4.0.2"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-validate": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz",
- "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==",
- "requires": {
- "@jest/types": "^26.6.2",
- "camelcase": "^6.0.0",
- "chalk": "^4.0.0",
- "jest-get-type": "^26.3.0",
- "leven": "^3.1.0",
- "pretty-format": "^26.6.2"
- },
- "dependencies": {
- "camelcase": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
- "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg=="
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-watch-typeahead": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.6.5.tgz",
- "integrity": "sha512-GIbV6h37/isatMDtqZlA8Q5vC6T3w+5qdvtF+3LIkPc58zEWzbKmTHvlUIp3wvBm400RzrQWcVPcsAJqKWu7XQ==",
- "dev": true,
- "requires": {
- "ansi-escapes": "^4.3.1",
- "chalk": "^4.0.0",
- "jest-regex-util": "^27.0.0",
- "jest-watcher": "^27.0.0",
- "slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "@jest/console": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz",
- "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==",
- "dev": true,
- "requires": {
- "@jest/types": "^27.4.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "jest-message-util": "^27.4.2",
- "jest-util": "^27.4.2",
- "slash": "^3.0.0"
- }
- },
- "@jest/test-result": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz",
- "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==",
- "dev": true,
- "requires": {
- "@jest/console": "^27.4.2",
- "@jest/types": "^27.4.2",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "collect-v8-coverage": "^1.0.0"
- }
- },
- "@jest/types": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz",
- "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==",
- "dev": true,
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^16.0.0",
- "chalk": "^4.0.0"
- }
- },
- "@types/yargs": {
- "version": "16.0.4",
- "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz",
- "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==",
- "dev": true,
- "requires": {
- "@types/yargs-parser": "*"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "ci-info": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz",
- "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==",
- "dev": true
- },
- "jest-message-util": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz",
- "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.12.13",
- "@jest/types": "^27.4.2",
- "@types/stack-utils": "^2.0.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "micromatch": "^4.0.4",
- "pretty-format": "^27.4.2",
- "slash": "^3.0.0",
- "stack-utils": "^2.0.3"
- }
- },
- "jest-regex-util": {
- "version": "27.4.0",
- "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz",
- "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==",
- "dev": true
- },
- "jest-util": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz",
- "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==",
- "dev": true,
- "requires": {
- "@jest/types": "^27.4.2",
- "@types/node": "*",
- "chalk": "^4.0.0",
- "ci-info": "^3.2.0",
- "graceful-fs": "^4.2.4",
- "picomatch": "^2.2.3"
- }
- },
- "jest-watcher": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz",
- "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==",
- "dev": true,
- "requires": {
- "@jest/test-result": "^27.4.2",
- "@jest/types": "^27.4.2",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "jest-util": "^27.4.2",
- "string-length": "^4.0.1"
- }
- },
- "micromatch": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
- "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
- "dev": true,
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.2.3"
- }
- },
- "picomatch": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
- "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
- "dev": true
- },
- "pretty-format": {
- "version": "27.4.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz",
- "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==",
- "dev": true,
- "requires": {
- "@jest/types": "^27.4.2",
- "ansi-regex": "^5.0.1",
- "ansi-styles": "^5.0.0",
- "react-is": "^17.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- },
- "ansi-styles": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
- "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
- "dev": true
- }
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "jest-watcher": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz",
- "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==",
- "requires": {
- "@jest/test-result": "^26.6.2",
- "@jest/types": "^26.6.2",
- "@types/node": "*",
- "ansi-escapes": "^4.2.1",
- "chalk": "^4.0.0",
- "jest-util": "^26.6.2",
- "string-length": "^4.0.1"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "jest-worker": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
- "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
- "requires": {
- "@types/node": "*",
- "merge-stream": "^2.0.0",
- "supports-color": "^7.0.0"
- }
- },
- "js-base64": {
- "version": "2.6.4",
- "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
- "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ=="
- },
- "js-string-escape": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz",
- "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=",
- "dev": true
- },
- "js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
- "requires": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- }
- },
- "js-year-calendar": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/js-year-calendar/-/js-year-calendar-1.0.2.tgz",
- "integrity": "sha512-ayHH/vE7xuXgGCprhQ23REbp3Rb2fy1rXO8jA26Wmuw4vYJ/TTIgFxFuNAlNPL8WR4tNXfnG41nlH3p+hjFesg=="
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
- },
- "jsdom": {
- "version": "16.7.0",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz",
- "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==",
- "requires": {
- "abab": "^2.0.5",
- "acorn": "^8.2.4",
- "acorn-globals": "^6.0.0",
- "cssom": "^0.4.4",
- "cssstyle": "^2.3.0",
- "data-urls": "^2.0.0",
- "decimal.js": "^10.2.1",
- "domexception": "^2.0.1",
- "escodegen": "^2.0.0",
- "form-data": "^3.0.0",
- "html-encoding-sniffer": "^2.0.1",
- "http-proxy-agent": "^4.0.1",
- "https-proxy-agent": "^5.0.0",
- "is-potential-custom-element-name": "^1.0.1",
- "nwsapi": "^2.2.0",
- "parse5": "6.0.1",
- "saxes": "^5.0.1",
- "symbol-tree": "^3.2.4",
- "tough-cookie": "^4.0.0",
- "w3c-hr-time": "^1.0.2",
- "w3c-xmlserializer": "^2.0.0",
- "webidl-conversions": "^6.1.0",
- "whatwg-encoding": "^1.0.5",
- "whatwg-mimetype": "^2.3.0",
- "whatwg-url": "^8.5.0",
- "ws": "^7.4.6",
- "xml-name-validator": "^3.0.0"
- },
- "dependencies": {
- "acorn": {
- "version": "8.5.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz",
- "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q=="
- },
- "escodegen": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz",
- "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==",
- "requires": {
- "esprima": "^4.0.1",
- "estraverse": "^5.2.0",
- "esutils": "^2.0.2",
- "optionator": "^0.8.1",
- "source-map": "~0.6.1"
- }
- },
- "estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
- },
- "form-data": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz",
- "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==",
- "requires": {
- "asynckit": "^0.4.0",
- "combined-stream": "^1.0.8",
- "mime-types": "^2.1.12"
- }
- },
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "requires": {
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2"
- }
- },
- "optionator": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
- "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
- "requires": {
- "deep-is": "~0.1.3",
- "fast-levenshtein": "~2.0.6",
- "levn": "~0.3.0",
- "prelude-ls": "~1.1.2",
- "type-check": "~0.3.2",
- "word-wrap": "~1.2.3"
- }
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
- },
- "tough-cookie": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz",
- "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==",
- "requires": {
- "psl": "^1.1.33",
- "punycode": "^2.1.1",
- "universalify": "^0.1.2"
- }
- },
- "type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "requires": {
- "prelude-ls": "~1.1.2"
- }
- },
- "universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
- }
- }
- },
- "jsesc": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
- "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
- },
- "json-parse-better-errors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
- "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
- },
- "json-parse-even-better-errors": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
- "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
- },
- "json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
- },
- "json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
- },
- "json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
- },
- "json3": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
- "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA=="
- },
- "json5": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
- "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "jsonfile": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
- "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
- "requires": {
- "graceful-fs": "^4.1.6",
- "universalify": "^2.0.0"
- }
- },
- "jsonwebtoken": {
- "version": "8.5.1",
- "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
- "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
- "requires": {
- "jws": "^3.2.2",
- "lodash.includes": "^4.3.0",
- "lodash.isboolean": "^3.0.3",
- "lodash.isinteger": "^4.0.4",
- "lodash.isnumber": "^3.0.3",
- "lodash.isplainobject": "^4.0.6",
- "lodash.isstring": "^4.0.1",
- "lodash.once": "^4.0.0",
- "ms": "^2.1.1",
- "semver": "^5.6.0"
- }
- },
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "jss": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss/-/jss-10.5.1.tgz",
- "integrity": "sha512-hbbO3+FOTqVdd7ZUoTiwpHzKXIo5vGpMNbuXH1a0wubRSWLWSBvwvaq4CiHH/U42CmjOnp6lVNNs/l+Z7ZdDmg==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "csstype": "^3.0.2",
- "indefinite-observable": "^2.0.1",
- "is-in-browser": "^1.1.3",
- "tiny-warning": "^1.0.2"
- },
- "dependencies": {
- "csstype": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz",
- "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g=="
- }
- }
- },
- "jss-plugin-camel-case": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.1.tgz",
- "integrity": "sha512-9+oymA7wPtswm+zxVti1qiowC5q7bRdCJNORtns2JUj/QHp2QPXYwSNRD8+D2Cy3/CEMtdJzlNnt5aXmpS6NAg==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "hyphenate-style-name": "^1.0.3",
- "jss": "10.5.1"
- }
- },
- "jss-plugin-default-unit": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.1.tgz",
- "integrity": "sha512-D48hJBc9Tj3PusvlillHW8Fz0y/QqA7MNmTYDQaSB/7mTrCZjt7AVRROExoOHEtd2qIYKOYJW3Jc2agnvsXRlQ==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.5.1"
- }
- },
- "jss-plugin-global": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.1.tgz",
- "integrity": "sha512-jX4XpNgoaB8yPWw/gA1aPXJEoX0LNpvsROPvxlnYe+SE0JOhuvF7mA6dCkgpXBxfTWKJsno7cDSCgzHTocRjCQ==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.5.1"
- }
- },
- "jss-plugin-nested": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.1.tgz",
- "integrity": "sha512-xXkWKOCljuwHNjSYcXrCxBnjd8eJp90KVFW1rlhvKKRXnEKVD6vdKXYezk2a89uKAHckSvBvBoDGsfZrldWqqQ==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.5.1",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-props-sort": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.1.tgz",
- "integrity": "sha512-t+2vcevNmMg4U/jAuxlfjKt46D/jHzCPEjsjLRj/J56CvP7Iy03scsUP58Iw8mVnaV36xAUZH2CmAmAdo8994g==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.5.1"
- }
- },
- "jss-plugin-rule-value-function": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.1.tgz",
- "integrity": "sha512-3gjrSxsy4ka/lGQsTDY8oYYtkt2esBvQiceGBB4PykXxHoGRz14tbCK31Zc6DHEnIeqsjMUGbq+wEly5UViStQ==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "jss": "10.5.1",
- "tiny-warning": "^1.0.2"
- }
- },
- "jss-plugin-vendor-prefixer": {
- "version": "10.5.1",
- "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.1.tgz",
- "integrity": "sha512-cLkH6RaPZWHa1TqSfd2vszNNgxT1W0omlSjAd6hCFHp3KIocSrW21gaHjlMU26JpTHwkc+tJTCQOmE/O1A4FKQ==",
- "requires": {
- "@babel/runtime": "^7.3.1",
- "css-vendor": "^2.0.8",
- "jss": "10.5.1"
- }
- },
- "jsx-ast-utils": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz",
- "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==",
- "requires": {
- "array-includes": "^3.1.2",
- "object.assign": "^4.1.2"
- }
- },
- "junk": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
- "integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
- "dev": true
- },
- "jwa": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
- "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
- "requires": {
- "buffer-equal-constant-time": "1.0.1",
- "ecdsa-sig-formatter": "1.0.11",
- "safe-buffer": "^5.0.1"
- }
- },
- "jws": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
- "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
- "requires": {
- "jwa": "^1.4.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "kapellmeister": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/kapellmeister/-/kapellmeister-3.0.1.tgz",
- "integrity": "sha512-S7+gYcziMREv8RxG46138mb1O4Xf9II/bCxEJPYkhlZ7PgGWTlicgsyNad/DGc5oEAlWGLXE5ExLbTDVvJmgDA==",
- "requires": {
- "d3-timer": "^1.0.9"
- }
- },
- "killable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
- "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg=="
- },
- "kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
- },
- "klaw": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
- "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=",
- "dev": true,
- "requires": {
- "graceful-fs": "^4.1.9"
- }
- },
- "kleur": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
- "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
- },
- "klona": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
- "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA=="
- },
- "language-subtag-registry": {
- "version": "0.3.21",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
- "integrity": "sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg=="
- },
- "language-tags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
- "integrity": "sha1-0yHbxNowuovzAk4ED6XBRmH5GTo=",
- "requires": {
- "language-subtag-registry": "~0.3.2"
- }
- },
- "last-call-webpack-plugin": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz",
- "integrity": "sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w==",
- "requires": {
- "lodash": "^4.17.5",
- "webpack-sources": "^1.1.0"
- }
- },
- "lazy-ass": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz",
- "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=",
- "dev": true
- },
- "lazy-universal-dotenv": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lazy-universal-dotenv/-/lazy-universal-dotenv-3.0.1.tgz",
- "integrity": "sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.5.0",
- "app-root-dir": "^1.0.2",
- "core-js": "^3.0.4",
- "dotenv": "^8.0.0",
- "dotenv-expand": "^5.1.0"
- }
- },
- "lazystream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
- "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.5"
- }
- },
- "lead": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
- "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
- "dev": true,
- "requires": {
- "flush-write-stream": "^1.0.2"
- }
- },
- "leven": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
- "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="
- },
- "levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "requires": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- }
- },
- "lines-and-columns": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
- "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA="
- },
- "lint-staged": {
- "version": "10.5.4",
- "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.4.tgz",
- "integrity": "sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "cli-truncate": "^2.1.0",
- "commander": "^6.2.0",
- "cosmiconfig": "^7.0.0",
- "debug": "^4.2.0",
- "dedent": "^0.7.0",
- "enquirer": "^2.3.6",
- "execa": "^4.1.0",
- "listr2": "^3.2.2",
- "log-symbols": "^4.0.0",
- "micromatch": "^4.0.2",
- "normalize-path": "^3.0.0",
- "please-upgrade-node": "^3.2.0",
- "string-argv": "0.3.1",
- "stringify-object": "^3.3.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "dev": true,
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- }
- },
- "commander": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
- "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
- "dev": true
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "execa": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
- "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.0",
- "get-stream": "^5.0.0",
- "human-signals": "^1.1.1",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.0",
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2",
- "strip-final-newline": "^2.0.0"
- }
- },
- "get-stream": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
- "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
- "dev": true,
- "requires": {
- "pump": "^3.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "is-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
- "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
- "dev": true
- },
- "log-symbols": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
- "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
- "dev": true,
- "requires": {
- "chalk": "^4.0.0"
- }
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "requires": {
- "path-key": "^3.0.0"
- }
- },
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "listr2": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.3.3.tgz",
- "integrity": "sha512-CeQrTeot/OQTrd2loXEBMfwlOjlPeHu/9alA8UyEoiEyncpj/mv2zRLgx32JzO62wbJIBSKgGM2L23XeOwrRlg==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "cli-truncate": "^2.1.0",
- "figures": "^3.2.0",
- "indent-string": "^4.0.0",
- "log-update": "^4.0.0",
- "p-map": "^4.0.0",
- "rxjs": "^6.6.3",
- "through": "^2.3.8",
- "wrap-ansi": "^7.0.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
- "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "dev": true,
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
- "dev": true,
- "requires": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
- },
- "dependencies": {
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "load-script": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/load-script/-/load-script-1.0.0.tgz",
- "integrity": "sha1-BJGTngvuVkPuSUp+PaPSuscMbKQ="
- },
- "loader-runner": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
- "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw=="
- },
- "loader-utils": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
- "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^2.1.2"
- }
- },
- "locate-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
- "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
- "requires": {
- "p-locate": "^3.0.0",
- "path-exists": "^3.0.0"
- },
- "dependencies": {
- "path-exists": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
- "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
- }
- }
- },
- "lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
- },
- "lodash._basebind": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._basebind/-/lodash._basebind-2.3.0.tgz",
- "integrity": "sha1-K1vEUqDhBhQ7IYafIzvbWHQX0kg=",
- "requires": {
- "lodash._basecreate": "~2.3.0",
- "lodash._setbinddata": "~2.3.0",
- "lodash.isobject": "~2.3.0"
- }
- },
- "lodash._basecreate": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-2.3.0.tgz",
- "integrity": "sha1-m4ioak3P97fzxh2Dovz8BnHsneA=",
- "requires": {
- "lodash._renative": "~2.3.0",
- "lodash.isobject": "~2.3.0",
- "lodash.noop": "~2.3.0"
- }
- },
- "lodash._basecreatecallback": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._basecreatecallback/-/lodash._basecreatecallback-2.3.0.tgz",
- "integrity": "sha1-N7KrF1kaM56YjbMln81GAZ16w2I=",
- "requires": {
- "lodash._setbinddata": "~2.3.0",
- "lodash.bind": "~2.3.0",
- "lodash.identity": "~2.3.0",
- "lodash.support": "~2.3.0"
- }
- },
- "lodash._basecreatewrapper": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._basecreatewrapper/-/lodash._basecreatewrapper-2.3.0.tgz",
- "integrity": "sha1-qgxhrZYETDkzN2ExSDqXWcNlEkc=",
- "requires": {
- "lodash._basecreate": "~2.3.0",
- "lodash._setbinddata": "~2.3.0",
- "lodash._slice": "~2.3.0",
- "lodash.isobject": "~2.3.0"
- }
- },
- "lodash._createwrapper": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._createwrapper/-/lodash._createwrapper-2.3.0.tgz",
- "integrity": "sha1-0arhEC2t9EDo4G/BM6bt1/4UYHU=",
- "requires": {
- "lodash._basebind": "~2.3.0",
- "lodash._basecreatewrapper": "~2.3.0",
- "lodash.isfunction": "~2.3.0"
- }
- },
- "lodash._objecttypes": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.3.0.tgz",
- "integrity": "sha1-aj6jmH3W7rgCGy1cnDA1Scwrrh4="
- },
- "lodash._reinterpolate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
- "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
- },
- "lodash._renative": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._renative/-/lodash._renative-2.3.0.tgz",
- "integrity": "sha1-d9jt1M7SbdWXH54Vpfdy5OMX+9M="
- },
- "lodash._setbinddata": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._setbinddata/-/lodash._setbinddata-2.3.0.tgz",
- "integrity": "sha1-5WEEkKzRMnfVmFjZW18nJ/FQjwQ=",
- "requires": {
- "lodash._renative": "~2.3.0",
- "lodash.noop": "~2.3.0"
- }
- },
- "lodash._shimkeys": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.3.0.tgz",
- "integrity": "sha1-YR+TFJ4+bHIQlrSHae8pU3rai6k=",
- "requires": {
- "lodash._objecttypes": "~2.3.0"
- }
- },
- "lodash._slice": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash._slice/-/lodash._slice-2.3.0.tgz",
- "integrity": "sha1-FHGYEyhZly5GgMoppZkshVZpqlw="
- },
- "lodash.bind": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-2.3.0.tgz",
- "integrity": "sha1-wqjhi2jl7MFS4rFoJmEW/qWwFsw=",
- "requires": {
- "lodash._createwrapper": "~2.3.0",
- "lodash._renative": "~2.3.0",
- "lodash._slice": "~2.3.0"
- }
- },
- "lodash.camelcase": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
- "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
- },
- "lodash.debounce": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
- },
- "lodash.foreach": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-2.3.0.tgz",
- "integrity": "sha1-CDQEyR6EbudyRf3512UZxosq8Wg=",
- "requires": {
- "lodash._basecreatecallback": "~2.3.0",
- "lodash.forown": "~2.3.0"
- }
- },
- "lodash.forown": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.forown/-/lodash.forown-2.3.0.tgz",
- "integrity": "sha1-JPtKr4ANRfwtxgv+w84EyDajrX8=",
- "requires": {
- "lodash._basecreatecallback": "~2.3.0",
- "lodash._objecttypes": "~2.3.0",
- "lodash.keys": "~2.3.0"
- }
- },
- "lodash.get": {
- "version": "4.4.2",
- "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
- "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
- },
- "lodash.identity": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.identity/-/lodash.identity-2.3.0.tgz",
- "integrity": "sha1-awGiEMlIU1XCqRO0i2cRIZoXPe0="
- },
- "lodash.includes": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
- "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
- },
- "lodash.isboolean": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
- "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
- },
- "lodash.isfunction": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-2.3.0.tgz",
- "integrity": "sha1-aylz5HpkfPEucNZ2rqE2Q3BuUmc="
- },
- "lodash.isinteger": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
- "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
- },
- "lodash.isnumber": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
- "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
- },
- "lodash.isobject": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.3.0.tgz",
- "integrity": "sha1-LhbT/Fg9qYMZaJU/LY5tc0NPZ5k=",
- "requires": {
- "lodash._objecttypes": "~2.3.0"
- }
- },
- "lodash.isplainobject": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
- "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
- },
- "lodash.isstring": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
- "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
- },
- "lodash.keys": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.3.0.tgz",
- "integrity": "sha1-s1D0+Syqn0WkouzwGEVM8vKK4lM=",
- "requires": {
- "lodash._renative": "~2.3.0",
- "lodash._shimkeys": "~2.3.0",
- "lodash.isobject": "~2.3.0"
- }
- },
- "lodash.memoize": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
- "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
- },
- "lodash.noop": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-2.3.0.tgz",
- "integrity": "sha1-MFnWKNUbv5N80qC2/Dp/ISpmnCw="
- },
- "lodash.once": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
- "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
- },
- "lodash.sortby": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
- "dev": true
- },
- "lodash.support": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/lodash.support/-/lodash.support-2.3.0.tgz",
- "integrity": "sha1-fq8DivTw1qq3drRKptz8gDNMm/0=",
- "requires": {
- "lodash._renative": "~2.3.0"
- }
- },
- "lodash.template": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
- "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
- "requires": {
- "lodash._reinterpolate": "^3.0.0",
- "lodash.templatesettings": "^4.0.0"
- }
- },
- "lodash.templatesettings": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
- "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
- "requires": {
- "lodash._reinterpolate": "^3.0.0"
- }
- },
- "lodash.topath": {
- "version": "4.5.2",
- "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
- "integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak="
- },
- "lodash.uniq": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
- "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
- },
- "log-symbols": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
- "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
- "dev": true,
- "requires": {
- "chalk": "^4.1.0",
- "is-unicode-supported": "^0.1.0"
- },
- "dependencies": {
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- }
- }
- },
- "log-update": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
- "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
- "dev": true,
- "requires": {
- "ansi-escapes": "^4.3.0",
- "cli-cursor": "^3.1.0",
- "slice-ansi": "^4.0.0",
- "wrap-ansi": "^6.2.0"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- },
- "wrap-ansi": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
- "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- }
- }
- }
- },
- "loglevel": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz",
- "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw=="
- },
- "loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "requires": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- }
- },
- "lower-case": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
- "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
- "requires": {
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "lowlight": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz",
- "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==",
- "dev": true,
- "requires": {
- "fault": "^1.0.0",
- "highlight.js": "~10.7.0"
- }
- },
- "lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "lz-string": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
- "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY="
- },
- "magic-string": {
- "version": "0.25.7",
- "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
- "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
- "requires": {
- "sourcemap-codec": "^1.4.4"
- }
- },
- "make-dir": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
- "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
- "requires": {
- "pify": "^4.0.1",
- "semver": "^5.6.0"
- },
- "dependencies": {
- "pify": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
- "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="
- }
- }
- },
- "makeerror": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
- "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=",
- "requires": {
- "tmpl": "1.0.x"
- }
- },
- "map-cache": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
- "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8="
- },
- "map-obj": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
- "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ=="
- },
- "map-or-similar": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz",
- "integrity": "sha1-beJlMXSt+12e3DPGnT6Sobdvrwg=",
- "dev": true
- },
- "map-visit": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
- "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
- "requires": {
- "object-visit": "^1.0.0"
- }
- },
- "markdown-escapes": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
- "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
- "dev": true
- },
- "markdown-to-jsx": {
- "version": "7.1.6",
- "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.6.tgz",
- "integrity": "sha512-1wrIGZYwIG2gR3yfRmbr4FlQmhaAKoKTpRo4wur4fp9p0njU1Hi7vR8fj0AUKKIcPduiJmPprzmCB5B/GvlC7g==",
- "dev": true
- },
- "matchmediaquery": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz",
- "integrity": "sha512-Hlk20WQHRIm9EE9luN1kjRjYXAQToHOIAHPJn9buxBwuhfTHoKUcX+lXBbxc85DVQfXYbEQ4HcwQdd128E3qHQ==",
- "requires": {
- "css-mediaquery": "^0.1.2"
- }
- },
- "md5.js": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
- "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
- "requires": {
- "hash-base": "^3.0.0",
- "inherits": "^2.0.1",
- "safe-buffer": "^5.1.2"
- }
- },
- "mdast-add-list-metadata": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz",
- "integrity": "sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==",
- "requires": {
- "unist-util-visit-parents": "1.1.2"
- }
- },
- "mdast-squeeze-paragraphs": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mdast-squeeze-paragraphs/-/mdast-squeeze-paragraphs-4.0.0.tgz",
- "integrity": "sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==",
- "dev": true,
- "requires": {
- "unist-util-remove": "^2.0.0"
- }
- },
- "mdast-util-definitions": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz",
- "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==",
- "dev": true,
- "requires": {
- "unist-util-visit": "^2.0.0"
- }
- },
- "mdast-util-from-markdown": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz",
- "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==",
- "requires": {
- "@types/mdast": "^3.0.0",
- "mdast-util-to-string": "^2.0.0",
- "micromark": "~2.11.0",
- "parse-entities": "^2.0.0",
- "unist-util-stringify-position": "^2.0.0"
- }
- },
- "mdast-util-to-hast": {
- "version": "10.0.1",
- "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.1.tgz",
- "integrity": "sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==",
- "dev": true,
- "requires": {
- "@types/mdast": "^3.0.0",
- "@types/unist": "^2.0.0",
- "mdast-util-definitions": "^4.0.0",
- "mdurl": "^1.0.0",
- "unist-builder": "^2.0.0",
- "unist-util-generated": "^1.0.0",
- "unist-util-position": "^3.0.0",
- "unist-util-visit": "^2.0.0"
- }
- },
- "mdast-util-to-string": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz",
- "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w=="
- },
- "mdn-data": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
- "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA=="
- },
- "mdurl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
- "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
- "dev": true
- },
- "media-typer": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
- "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
- },
- "memfs": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz",
- "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==",
- "dev": true,
- "requires": {
- "fs-monkey": "1.0.3"
- }
- },
- "memoize-one": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz",
- "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA=="
- },
- "memoizerific": {
- "version": "1.11.3",
- "resolved": "https://registry.npmjs.org/memoizerific/-/memoizerific-1.11.3.tgz",
- "integrity": "sha1-fIekZGREwy11Q4VwkF8tvRsagFo=",
- "dev": true,
- "requires": {
- "map-or-similar": "^1.5.0"
- }
- },
- "memory-fs": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
- "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
- "requires": {
- "errno": "^0.1.3",
- "readable-stream": "^2.0.1"
- }
- },
- "meow": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
- "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
- "requires": {
- "@types/minimist": "^1.2.0",
- "camelcase-keys": "^6.2.2",
- "decamelize": "^1.2.0",
- "decamelize-keys": "^1.1.0",
- "hard-rejection": "^2.1.0",
- "minimist-options": "4.1.0",
- "normalize-package-data": "^3.0.0",
- "read-pkg-up": "^7.0.1",
- "redent": "^3.0.0",
- "trim-newlines": "^3.0.0",
- "type-fest": "^0.18.0",
- "yargs-parser": "^20.2.3"
- },
- "dependencies": {
- "hosted-git-info": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz",
- "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "is-core-module": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
- "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==",
- "requires": {
- "has": "^1.0.3"
- }
- },
- "normalize-package-data": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
- "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
- "requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- },
- "type-fest": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
- "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw=="
- },
- "yargs-parser": {
- "version": "20.2.9",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
- "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
- }
- }
- },
- "merge-descriptors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
- "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
- },
- "merge-stream": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
- "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
- },
- "merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
- },
- "methods": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
- "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
- },
- "microevent.ts": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/microevent.ts/-/microevent.ts-0.1.1.tgz",
- "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g=="
- },
- "micromark": {
- "version": "2.11.4",
- "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz",
- "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==",
- "requires": {
- "debug": "^4.0.0",
- "parse-entities": "^2.0.0"
- }
- },
- "micromatch": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
- "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
- "requires": {
- "braces": "^3.0.1",
- "picomatch": "^2.0.5"
- }
- },
- "miller-rabin": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
- "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
- "requires": {
- "bn.js": "^4.0.0",
- "brorand": "^1.0.1"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "mime": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
- "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
- },
- "mime-db": {
- "version": "1.46.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
- "integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ=="
- },
- "mime-types": {
- "version": "2.1.29",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
- "integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
- "requires": {
- "mime-db": "1.46.0"
- }
- },
- "mimic-fn": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
- "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
- },
- "min-document": {
- "version": "2.19.0",
- "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
- "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
- "dev": true,
- "requires": {
- "dom-walk": "^0.1.0"
- }
- },
- "min-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
- "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg=="
- },
- "mini-css-extract-plugin": {
- "version": "0.11.3",
- "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.3.tgz",
- "integrity": "sha512-n9BA8LonkOkW1/zn+IbLPQmovsL0wMb9yx75fMJQZf2X1Zoec9yTZtyMePcyu19wPkmFbzZZA6fLTotpFhQsOA==",
- "requires": {
- "loader-utils": "^1.1.0",
- "normalize-url": "1.9.1",
- "schema-utils": "^1.0.0",
- "webpack-sources": "^1.1.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- }
- },
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
- "requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
- }
- }
- }
- },
- "minimalistic-assert": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
- "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
- },
- "minimalistic-crypto-utils": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
- "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "requires": {
- "brace-expansion": "^1.1.7"
- }
- },
- "minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
- },
- "minimist-options": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
- "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
- "requires": {
- "arrify": "^1.0.1",
- "is-plain-obj": "^1.1.0",
- "kind-of": "^6.0.3"
- },
- "dependencies": {
- "arrify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
- "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
- },
- "is-plain-obj": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
- }
- }
- },
- "minipass": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
- "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
- "requires": {
- "yallist": "^4.0.0"
- }
- },
- "minipass-collect": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
- "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-flush": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
- "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minipass-pipeline": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
- "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
- "requires": {
- "minipass": "^3.0.0"
- }
- },
- "minizlib": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
- "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
- "requires": {
- "minipass": "^3.0.0",
- "yallist": "^4.0.0"
- }
- },
- "mississippi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
- "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
- "requires": {
- "concat-stream": "^1.5.0",
- "duplexify": "^3.4.2",
- "end-of-stream": "^1.1.0",
- "flush-write-stream": "^1.0.0",
- "from2": "^2.1.0",
- "parallel-transform": "^1.1.0",
- "pump": "^3.0.0",
- "pumpify": "^1.3.3",
- "stream-each": "^1.1.0",
- "through2": "^2.0.0"
- }
- },
- "mixin-deep": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
- "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
- "requires": {
- "for-in": "^1.0.2",
- "is-extendable": "^1.0.1"
- },
- "dependencies": {
- "is-extendable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
- "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "requires": {
- "is-plain-object": "^2.0.4"
- }
- }
- }
- },
- "mkdirp": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
- "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
- "requires": {
- "minimist": "^1.2.5"
- }
- },
- "mktemp": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/mktemp/-/mktemp-0.4.0.tgz",
- "integrity": "sha1-bQUVYRyKjITkhKogABKbmOmB/ws=",
- "dev": true
- },
- "moment": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
- "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
- },
- "moment-range": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz",
- "integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==",
- "requires": {
- "es6-symbol": "^3.1.0"
- }
- },
- "move-concurrently": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
- "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
- "requires": {
- "aproba": "^1.1.1",
- "copy-concurrently": "^1.0.0",
- "fs-write-stream-atomic": "^1.0.8",
- "mkdirp": "^0.5.1",
- "rimraf": "^2.5.4",
- "run-queue": "^1.0.3"
- },
- "dependencies": {
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
- },
- "multicast-dns": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
- "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
- "requires": {
- "dns-packet": "^1.3.1",
- "thunky": "^1.0.2"
- }
- },
- "multicast-dns-service-types": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
- "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
- },
- "nan": {
- "version": "2.14.2",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz",
- "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ=="
- },
- "nanoid": {
- "version": "3.1.30",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz",
- "integrity": "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
- },
- "nanomatch": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
- "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "fragment-cache": "^0.2.1",
- "is-windows": "^1.0.2",
- "kind-of": "^6.0.2",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.1"
- }
- },
- "native-url": {
- "version": "0.2.6",
- "resolved": "https://registry.npmjs.org/native-url/-/native-url-0.2.6.tgz",
- "integrity": "sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA==",
- "requires": {
- "querystring": "^0.2.0"
- }
- },
- "natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
- },
- "negotiator": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
- "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
- },
- "neo-async": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
- "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
- },
- "nested-error-stacks": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
- "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==",
- "dev": true
- },
- "nested-property": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-1.0.1.tgz",
- "integrity": "sha512-BnBBoo/8bBNRdAnJc7+m79oWk7dXwW1+vCesaEQhfDGVwXGLMvmI4NwYgLTW94R/x+R2s/yr2g/hB/4w/YSAvA=="
- },
- "next-tick": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
- "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
- },
- "nice-try": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
- "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
- },
- "no-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
- "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
- "requires": {
- "lower-case": "^2.0.2",
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "node-dir": {
- "version": "0.1.17",
- "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz",
- "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=",
- "dev": true,
- "requires": {
- "minimatch": "^3.0.2"
- }
- },
- "node-fetch": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
- "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
- "dev": true,
- "requires": {
- "whatwg-url": "^5.0.0"
- },
- "dependencies": {
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "dev": true
- },
- "webidl-conversions": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
- "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
- "dev": true
- },
- "whatwg-url": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
- "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
- "dev": true,
- "requires": {
- "tr46": "~0.0.3",
- "webidl-conversions": "^3.0.0"
- }
- }
- }
- },
- "node-forge": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
- "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
- },
- "node-gyp": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
- "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==",
- "requires": {
- "env-paths": "^2.2.0",
- "glob": "^7.1.4",
- "graceful-fs": "^4.2.3",
- "nopt": "^5.0.0",
- "npmlog": "^4.1.2",
- "request": "^2.88.2",
- "rimraf": "^3.0.2",
- "semver": "^7.3.2",
- "tar": "^6.0.2",
- "which": "^2.0.2"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "node-int64": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
- "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
- },
- "node-libs-browser": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
- "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
- "requires": {
- "assert": "^1.1.1",
- "browserify-zlib": "^0.2.0",
- "buffer": "^4.3.0",
- "console-browserify": "^1.1.0",
- "constants-browserify": "^1.0.0",
- "crypto-browserify": "^3.11.0",
- "domain-browser": "^1.1.1",
- "events": "^3.0.0",
- "https-browserify": "^1.0.0",
- "os-browserify": "^0.3.0",
- "path-browserify": "0.0.1",
- "process": "^0.11.10",
- "punycode": "^1.2.4",
- "querystring-es3": "^0.2.0",
- "readable-stream": "^2.3.3",
- "stream-browserify": "^2.0.1",
- "stream-http": "^2.7.2",
- "string_decoder": "^1.0.0",
- "timers-browserify": "^2.0.4",
- "tty-browserify": "0.0.0",
- "url": "^0.11.0",
- "util": "^0.11.0",
- "vm-browserify": "^1.0.1"
- },
- "dependencies": {
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
- }
- }
- },
- "node-modules-regexp": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
- "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA="
- },
- "node-notifier": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz",
- "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==",
- "optional": true,
- "requires": {
- "growly": "^1.3.0",
- "is-wsl": "^2.2.0",
- "semver": "^7.3.2",
- "shellwords": "^0.1.1",
- "uuid": "^8.3.0",
- "which": "^2.0.2"
- },
- "dependencies": {
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "optional": true,
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "node-releases": {
- "version": "1.1.77",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz",
- "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ=="
- },
- "node-sass": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz",
- "integrity": "sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==",
- "requires": {
- "async-foreach": "^0.1.3",
- "chalk": "^1.1.1",
- "cross-spawn": "^7.0.3",
- "gaze": "^1.0.0",
- "get-stdin": "^4.0.1",
- "glob": "^7.0.3",
- "lodash": "^4.17.15",
- "meow": "^9.0.0",
- "nan": "^2.13.2",
- "node-gyp": "^7.1.0",
- "npmlog": "^4.0.0",
- "request": "^2.88.0",
- "sass-graph": "2.2.5",
- "stdout-stream": "^1.4.0",
- "true-case-path": "^1.0.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "requires": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- }
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
- }
- }
- },
- "nopt": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
- "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
- "requires": {
- "abbrev": "1"
- }
- },
- "normalize-package-data": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
- "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
- "requires": {
- "hosted-git-info": "^2.1.4",
- "resolve": "^1.10.0",
- "semver": "2 || 3 || 4 || 5",
- "validate-npm-package-license": "^3.0.1"
- }
- },
- "normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
- },
- "normalize-range": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
- "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
- },
- "normalize-url": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
- "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
- "requires": {
- "object-assign": "^4.0.1",
- "prepend-http": "^1.0.0",
- "query-string": "^4.1.0",
- "sort-keys": "^1.0.0"
- }
- },
- "notistack": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/notistack/-/notistack-1.0.9.tgz",
- "integrity": "sha512-Dal2HtTpWrdYCZ3t0HhJt47NJZwVSPee36WzORRbqUkFR0k9pxFszxBuPSWshBLwF6Av8s86XPP+ED5zRz0CGw==",
- "requires": {
- "clsx": "^1.1.0",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "now-and-later": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz",
- "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==",
- "dev": true,
- "requires": {
- "once": "^1.3.2"
- }
- },
- "npm-run-path": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
- "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
- "requires": {
- "path-key": "^2.0.0"
- },
- "dependencies": {
- "path-key": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
- "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
- }
- }
- },
- "npmlog": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
- "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
- "requires": {
- "are-we-there-yet": "~1.1.2",
- "console-control-strings": "~1.1.0",
- "gauge": "~2.7.3",
- "set-blocking": "~2.0.0"
- }
- },
- "nuka-carousel": {
- "version": "4.7.5",
- "resolved": "https://registry.npmjs.org/nuka-carousel/-/nuka-carousel-4.7.5.tgz",
- "integrity": "sha512-E5zsWgRZQxNz6lJaaioz+/3aTJr5pAAkZpxTIW+lK+9OpGz813rGEGEroO9FzHhnMGhV7KcuUnQ8bJgdoUq+1w==",
- "requires": {
- "csstype": "^2.6.6",
- "d3-ease": "^1.0.3",
- "exenv": "^1.2.0",
- "prop-types": "^15.6.0",
- "react-move": "^6.1.0",
- "wicg-inert": "^3.1.0"
- }
- },
- "num2fraction": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
- "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4="
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
- },
- "nwsapi": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
- "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
- },
- "oauth-sign": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
- "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
- },
- "object-copy": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
- "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
- "requires": {
- "copy-descriptor": "^0.1.0",
- "define-property": "^0.2.5",
- "kind-of": "^3.0.3"
- },
- "dependencies": {
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "object-inspect": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz",
- "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw=="
- },
- "object-is": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz",
- "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
- },
- "object-visit": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
- "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
- "requires": {
- "isobject": "^3.0.0"
- }
- },
- "object.assign": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
- "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3",
- "has-symbols": "^1.0.1",
- "object-keys": "^1.1.1"
- }
- },
- "object.entries": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz",
- "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==",
- "requires": {
- "call-bind": "^1.0.0",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.1",
- "has": "^1.0.3"
- }
- },
- "object.fromentries": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz",
- "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.2",
- "has": "^1.0.3"
- }
- },
- "object.getownpropertydescriptors": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz",
- "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.2"
- }
- },
- "object.pick": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
- "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
- "requires": {
- "isobject": "^3.0.1"
- }
- },
- "object.values": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz",
- "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.2",
- "has": "^1.0.3"
- }
- },
- "objectorarray": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz",
- "integrity": "sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==",
- "dev": true
- },
- "obuf": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
- "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
- },
- "on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "on-headers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
- "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1"
- }
- },
- "onetime": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
- "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
- "requires": {
- "mimic-fn": "^2.1.0"
- }
- },
- "open": {
- "version": "7.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
- "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
- "requires": {
- "is-docker": "^2.0.0",
- "is-wsl": "^2.1.1"
- }
- },
- "opn": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
- "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
- "requires": {
- "is-wsl": "^1.1.0"
- },
- "dependencies": {
- "is-wsl": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
- "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
- }
- }
- },
- "optimize-css-assets-webpack-plugin": {
- "version": "5.0.4",
- "resolved": "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz",
- "integrity": "sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A==",
- "requires": {
- "cssnano": "^4.1.10",
- "last-call-webpack-plugin": "^3.0.0"
- }
- },
- "optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "requires": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- }
- },
- "ordered-read-streams": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
- "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
- "dev": true,
- "requires": {
- "readable-stream": "^2.0.1"
- }
- },
- "original": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
- "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
- "requires": {
- "url-parse": "^1.4.3"
- }
- },
- "os-browserify": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
- "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
- },
- "ospath": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz",
- "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=",
- "dev": true
- },
- "overlayscrollbars": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz",
- "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==",
- "dev": true
- },
- "p-all": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz",
- "integrity": "sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==",
- "dev": true,
- "requires": {
- "p-map": "^2.0.0"
- },
- "dependencies": {
- "p-map": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
- "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
- "dev": true
- }
- }
- },
- "p-each-series": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz",
- "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA=="
- },
- "p-event": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
- "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==",
- "dev": true,
- "requires": {
- "p-timeout": "^3.1.0"
- }
- },
- "p-filter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-2.1.0.tgz",
- "integrity": "sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==",
- "dev": true,
- "requires": {
- "p-map": "^2.0.0"
- },
- "dependencies": {
- "p-map": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
- "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
- "dev": true
- }
- }
- },
- "p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
- },
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- },
- "p-locate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
- "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
- "requires": {
- "p-limit": "^2.0.0"
- }
- },
- "p-map": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
- "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
- "requires": {
- "aggregate-error": "^3.0.0"
- }
- },
- "p-retry": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
- "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==",
- "requires": {
- "retry": "^0.12.0"
- }
- },
- "p-timeout": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
- "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
- "dev": true,
- "requires": {
- "p-finally": "^1.0.0"
- }
- },
- "p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
- },
- "pako": {
- "version": "1.0.11",
- "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
- "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
- },
- "parallel-transform": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
- "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
- "requires": {
- "cyclist": "^1.0.1",
- "inherits": "^2.0.3",
- "readable-stream": "^2.1.5"
- }
- },
- "param-case": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz",
- "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==",
- "requires": {
- "dot-case": "^3.0.4",
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "requires": {
- "callsites": "^3.0.0"
- }
- },
- "parse-asn1": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
- "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
- "requires": {
- "asn1.js": "^5.2.0",
- "browserify-aes": "^1.0.0",
- "evp_bytestokey": "^1.0.0",
- "pbkdf2": "^3.0.3",
- "safe-buffer": "^5.1.1"
- }
- },
- "parse-entities": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
- "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
- "requires": {
- "character-entities": "^1.0.0",
- "character-entities-legacy": "^1.0.0",
- "character-reference-invalid": "^1.0.0",
- "is-alphanumerical": "^1.0.0",
- "is-decimal": "^1.0.0",
- "is-hexadecimal": "^1.0.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "parse5": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
- "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
- },
- "parse5-htmlparser2-tree-adapter": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
- "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
- "dev": true,
- "requires": {
- "parse5": "^6.0.1"
- },
- "dependencies": {
- "parse5": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
- "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
- "dev": true
- }
- }
- },
- "parseurl": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
- "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
- },
- "pascal-case": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
- "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
- "requires": {
- "no-case": "^3.0.4",
- "tslib": "^2.0.3"
- },
- "dependencies": {
- "tslib": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
- "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A=="
- }
- }
- },
- "pascalcase": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
- "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ="
- },
- "path-browserify": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
- "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ=="
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
- },
- "path-is-inside": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
- "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
- },
- "path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
- },
- "path-to-regexp": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
- "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
- "requires": {
- "isarray": "0.0.1"
- },
- "dependencies": {
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
- }
- }
- },
- "path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true
- },
- "pbkdf2": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
- "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
- "requires": {
- "create-hash": "^1.1.2",
- "create-hmac": "^1.1.4",
- "ripemd160": "^2.0.1",
- "safe-buffer": "^5.0.1",
- "sha.js": "^2.4.8"
- }
- },
- "pend": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
- "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
- "dev": true
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
- },
- "picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "picomatch": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
- "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
- },
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
- "dev": true
- },
- "pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
- },
- "pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "requires": {
- "pinkie": "^2.0.0"
- }
- },
- "pirates": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
- "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==",
- "requires": {
- "node-modules-regexp": "^1.0.0"
- }
- },
- "pkg-dir": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
- "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
- "requires": {
- "find-up": "^3.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "requires": {
- "locate-path": "^3.0.0"
- }
- }
- }
- },
- "pkg-up": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
- "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
- "requires": {
- "find-up": "^3.0.0"
- },
- "dependencies": {
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "requires": {
- "locate-path": "^3.0.0"
- }
- }
- }
- },
- "please-upgrade-node": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
- "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
- "dev": true,
- "requires": {
- "semver-compare": "^1.0.0"
- }
- },
- "pn": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
- "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
- "dev": true
- },
- "pnp-webpack-plugin": {
- "version": "1.6.4",
- "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz",
- "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==",
- "requires": {
- "ts-pnp": "^1.1.6"
- }
- },
- "polished": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz",
- "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.14.0"
- },
- "dependencies": {
- "@babel/runtime": {
- "version": "7.16.7",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz",
- "integrity": "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==",
- "dev": true,
- "requires": {
- "regenerator-runtime": "^0.13.4"
- }
- }
- }
- },
- "popmotion": {
- "version": "9.3.1",
- "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-9.3.1.tgz",
- "integrity": "sha512-Qozvg8rz2OGeZwWuIjqlSXqqgWto/+QL24ll8sAAc0n71KY/wvN1W4sAASxTuHv8YWdDnk9u9IdadyPo2DGvDA==",
- "requires": {
- "framesync": "5.2.0",
- "hey-listen": "^1.0.8",
- "style-value-types": "4.1.1",
- "tslib": "^1.10.0"
- }
- },
- "popper.js": {
- "version": "1.16.1-lts",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz",
- "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA=="
- },
- "portfinder": {
- "version": "1.0.28",
- "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
- "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
- "requires": {
- "async": "^2.6.2",
- "debug": "^3.1.1",
- "mkdirp": "^0.5.5"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "posix-character-classes": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
- "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
- },
- "postcss": {
- "version": "7.0.39",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
- "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
- "requires": {
- "picocolors": "^0.2.1",
- "source-map": "^0.6.1"
- },
- "dependencies": {
- "picocolors": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
- "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
- }
- }
- },
- "postcss-attribute-case-insensitive": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz",
- "integrity": "sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-selector-parser": "^6.0.2"
- }
- },
- "postcss-browser-comments": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-browser-comments/-/postcss-browser-comments-3.0.0.tgz",
- "integrity": "sha512-qfVjLfq7HFd2e0HW4s1dvU8X080OZdG46fFbIBFjW7US7YPDcWfRvdElvwMJr2LI6hMmD+7LnH2HcmXTs+uOig==",
- "requires": {
- "postcss": "^7"
- }
- },
- "postcss-calc": {
- "version": "7.0.5",
- "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
- "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
- "requires": {
- "postcss": "^7.0.27",
- "postcss-selector-parser": "^6.0.2",
- "postcss-value-parser": "^4.0.2"
- }
- },
- "postcss-color-functional-notation": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz",
- "integrity": "sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-color-gray": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz",
- "integrity": "sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw==",
- "requires": {
- "@csstools/convert-colors": "^1.4.0",
- "postcss": "^7.0.5",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-color-hex-alpha": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz",
- "integrity": "sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw==",
- "requires": {
- "postcss": "^7.0.14",
- "postcss-values-parser": "^2.0.1"
- }
- },
- "postcss-color-mod-function": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz",
- "integrity": "sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ==",
- "requires": {
- "@csstools/convert-colors": "^1.4.0",
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-color-rebeccapurple": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz",
- "integrity": "sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-colormin": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz",
- "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==",
- "requires": {
- "browserslist": "^4.0.0",
- "color": "^3.0.0",
- "has": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "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=="
- }
- }
- },
- "postcss-convert-values": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz",
- "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==",
- "requires": {
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-custom-media": {
- "version": "7.0.8",
- "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz",
- "integrity": "sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg==",
- "requires": {
- "postcss": "^7.0.14"
- }
- },
- "postcss-custom-properties": {
- "version": "8.0.11",
- "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz",
- "integrity": "sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA==",
- "requires": {
- "postcss": "^7.0.17",
- "postcss-values-parser": "^2.0.1"
- }
- },
- "postcss-custom-selectors": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz",
- "integrity": "sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-selector-parser": "^5.0.0-rc.3"
- },
- "dependencies": {
- "cssesc": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
- "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg=="
- },
- "postcss-selector-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
- "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
- "requires": {
- "cssesc": "^2.0.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "postcss-dir-pseudo-class": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz",
- "integrity": "sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-selector-parser": "^5.0.0-rc.3"
- },
- "dependencies": {
- "cssesc": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
- "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg=="
- },
- "postcss-selector-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
- "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
- "requires": {
- "cssesc": "^2.0.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "postcss-discard-comments": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
- "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "postcss-discard-duplicates": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz",
- "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "postcss-discard-empty": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz",
- "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "postcss-discard-overridden": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz",
- "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "postcss-double-position-gradients": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz",
- "integrity": "sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA==",
- "requires": {
- "postcss": "^7.0.5",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-env-function": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-2.0.2.tgz",
- "integrity": "sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-flexbugs-fixes": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz",
- "integrity": "sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==",
- "requires": {
- "postcss": "^7.0.26"
- }
- },
- "postcss-focus-visible": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz",
- "integrity": "sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-focus-within": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz",
- "integrity": "sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-font-variant": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz",
- "integrity": "sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-gap-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz",
- "integrity": "sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-image-set-function": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz",
- "integrity": "sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-initial": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-3.0.4.tgz",
- "integrity": "sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-lab-function": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz",
- "integrity": "sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg==",
- "requires": {
- "@csstools/convert-colors": "^1.4.0",
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-load-config": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
- "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==",
- "requires": {
- "cosmiconfig": "^5.0.0",
- "import-cwd": "^2.0.0"
- },
- "dependencies": {
- "cosmiconfig": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
- "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
- "requires": {
- "import-fresh": "^2.0.0",
- "is-directory": "^0.3.1",
- "js-yaml": "^3.13.1",
- "parse-json": "^4.0.0"
- }
- },
- "import-fresh": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
- "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
- "requires": {
- "caller-path": "^2.0.0",
- "resolve-from": "^3.0.0"
- }
- },
- "parse-json": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
- "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
- "requires": {
- "error-ex": "^1.3.1",
- "json-parse-better-errors": "^1.0.1"
- }
- },
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
- }
- }
- },
- "postcss-loader": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
- "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
- "requires": {
- "loader-utils": "^1.1.0",
- "postcss": "^7.0.0",
- "postcss-load-config": "^2.0.0",
- "schema-utils": "^1.0.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- }
- },
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
- "requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
- }
- }
- }
- },
- "postcss-logical": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-3.0.0.tgz",
- "integrity": "sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-media-minmax": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz",
- "integrity": "sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-merge-longhand": {
- "version": "4.0.11",
- "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
- "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==",
- "requires": {
- "css-color-names": "0.0.4",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0",
- "stylehacks": "^4.0.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=="
- }
- }
- },
- "postcss-merge-rules": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz",
- "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==",
- "requires": {
- "browserslist": "^4.0.0",
- "caniuse-api": "^3.0.0",
- "cssnano-util-same-parent": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-selector-parser": "^3.0.0",
- "vendors": "^1.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "postcss-selector-parser": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
- "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
- "requires": {
- "dot-prop": "^5.2.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "postcss-minify-font-values": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz",
- "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==",
- "requires": {
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-minify-gradients": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz",
- "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==",
- "requires": {
- "cssnano-util-get-arguments": "^4.0.0",
- "is-color-stop": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-minify-params": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz",
- "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==",
- "requires": {
- "alphanum-sort": "^1.0.0",
- "browserslist": "^4.0.0",
- "cssnano-util-get-arguments": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0",
- "uniqs": "^2.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "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=="
- }
- }
- },
- "postcss-minify-selectors": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz",
- "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==",
- "requires": {
- "alphanum-sort": "^1.0.0",
- "has": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-selector-parser": "^3.0.0"
- },
- "dependencies": {
- "postcss-selector-parser": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
- "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
- "requires": {
- "dot-prop": "^5.2.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "postcss-modules-extract-imports": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
- "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
- "requires": {
- "postcss": "^7.0.5"
- }
- },
- "postcss-modules-local-by-default": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz",
- "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==",
- "requires": {
- "icss-utils": "^4.1.1",
- "postcss": "^7.0.32",
- "postcss-selector-parser": "^6.0.2",
- "postcss-value-parser": "^4.1.0"
- }
- },
- "postcss-modules-scope": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz",
- "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==",
- "requires": {
- "postcss": "^7.0.6",
- "postcss-selector-parser": "^6.0.0"
- }
- },
- "postcss-modules-values": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz",
- "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==",
- "requires": {
- "icss-utils": "^4.0.0",
- "postcss": "^7.0.6"
- }
- },
- "postcss-nesting": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-7.0.1.tgz",
- "integrity": "sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-normalize": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize/-/postcss-normalize-8.0.1.tgz",
- "integrity": "sha512-rt9JMS/m9FHIRroDDBGSMsyW1c0fkvOJPy62ggxSHUldJO7B195TqFMqIf+lY5ezpDcYOV4j86aUp3/XbxzCCQ==",
- "requires": {
- "@csstools/normalize.css": "^10.1.0",
- "browserslist": "^4.6.2",
- "postcss": "^7.0.17",
- "postcss-browser-comments": "^3.0.0",
- "sanitize.css": "^10.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- }
- }
- },
- "postcss-normalize-charset": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz",
- "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==",
- "requires": {
- "postcss": "^7.0.0"
- }
- },
- "postcss-normalize-display-values": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz",
- "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==",
- "requires": {
- "cssnano-util-get-match": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-normalize-positions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz",
- "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==",
- "requires": {
- "cssnano-util-get-arguments": "^4.0.0",
- "has": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-normalize-repeat-style": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz",
- "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==",
- "requires": {
- "cssnano-util-get-arguments": "^4.0.0",
- "cssnano-util-get-match": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-normalize-string": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz",
- "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==",
- "requires": {
- "has": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-normalize-timing-functions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz",
- "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==",
- "requires": {
- "cssnano-util-get-match": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-normalize-unicode": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz",
- "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==",
- "requires": {
- "browserslist": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "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=="
- }
- }
- },
- "postcss-normalize-url": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz",
- "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==",
- "requires": {
- "is-absolute-url": "^2.0.0",
- "normalize-url": "^3.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0"
- },
- "dependencies": {
- "normalize-url": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
- "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg=="
- },
- "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=="
- }
- }
- },
- "postcss-normalize-whitespace": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz",
- "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==",
- "requires": {
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-ordered-values": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz",
- "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==",
- "requires": {
- "cssnano-util-get-arguments": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-overflow-shorthand": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz",
- "integrity": "sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-page-break": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-2.0.0.tgz",
- "integrity": "sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-place": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-4.0.1.tgz",
- "integrity": "sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-values-parser": "^2.0.0"
- }
- },
- "postcss-preset-env": {
- "version": "6.7.0",
- "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz",
- "integrity": "sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg==",
- "requires": {
- "autoprefixer": "^9.6.1",
- "browserslist": "^4.6.4",
- "caniuse-lite": "^1.0.30000981",
- "css-blank-pseudo": "^0.1.4",
- "css-has-pseudo": "^0.10.0",
- "css-prefers-color-scheme": "^3.1.1",
- "cssdb": "^4.4.0",
- "postcss": "^7.0.17",
- "postcss-attribute-case-insensitive": "^4.0.1",
- "postcss-color-functional-notation": "^2.0.1",
- "postcss-color-gray": "^5.0.0",
- "postcss-color-hex-alpha": "^5.0.3",
- "postcss-color-mod-function": "^3.0.3",
- "postcss-color-rebeccapurple": "^4.0.1",
- "postcss-custom-media": "^7.0.8",
- "postcss-custom-properties": "^8.0.11",
- "postcss-custom-selectors": "^5.1.2",
- "postcss-dir-pseudo-class": "^5.0.0",
- "postcss-double-position-gradients": "^1.0.0",
- "postcss-env-function": "^2.0.2",
- "postcss-focus-visible": "^4.0.0",
- "postcss-focus-within": "^3.0.0",
- "postcss-font-variant": "^4.0.0",
- "postcss-gap-properties": "^2.0.0",
- "postcss-image-set-function": "^3.0.1",
- "postcss-initial": "^3.0.0",
- "postcss-lab-function": "^2.0.1",
- "postcss-logical": "^3.0.0",
- "postcss-media-minmax": "^4.0.0",
- "postcss-nesting": "^7.0.0",
- "postcss-overflow-shorthand": "^2.0.0",
- "postcss-page-break": "^2.0.0",
- "postcss-place": "^4.0.1",
- "postcss-pseudo-class-any-link": "^6.0.0",
- "postcss-replace-overflow-wrap": "^3.0.0",
- "postcss-selector-matches": "^4.0.0",
- "postcss-selector-not": "^4.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- },
- "dependencies": {
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- }
- }
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- }
- }
- },
- "postcss-pseudo-class-any-link": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz",
- "integrity": "sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew==",
- "requires": {
- "postcss": "^7.0.2",
- "postcss-selector-parser": "^5.0.0-rc.3"
- },
- "dependencies": {
- "cssesc": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
- "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg=="
- },
- "postcss-selector-parser": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
- "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
- "requires": {
- "cssesc": "^2.0.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "postcss-reduce-initial": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz",
- "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==",
- "requires": {
- "browserslist": "^4.0.0",
- "caniuse-api": "^3.0.0",
- "has": "^1.0.0",
- "postcss": "^7.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- }
- }
- },
- "postcss-reduce-transforms": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz",
- "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==",
- "requires": {
- "cssnano-util-get-match": "^4.0.0",
- "has": "^1.0.0",
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.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=="
- }
- }
- },
- "postcss-replace-overflow-wrap": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz",
- "integrity": "sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw==",
- "requires": {
- "postcss": "^7.0.2"
- }
- },
- "postcss-safe-parser": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-5.0.2.tgz",
- "integrity": "sha512-jDUfCPJbKOABhwpUKcqCVbbXiloe/QXMcbJ6Iipf3sDIihEzTqRCeMBfRaOHxhBuTYqtASrI1KJWxzztZU4qUQ==",
- "requires": {
- "postcss": "^8.1.0"
- },
- "dependencies": {
- "postcss": {
- "version": "8.3.11",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.11.tgz",
- "integrity": "sha512-hCmlUAIlUiav8Xdqw3Io4LcpA1DOt7h3LSTAC4G6JGHFFaWzI6qvFt9oilvl8BmkbBRX1IhM90ZAmpk68zccQA==",
- "requires": {
- "nanoid": "^3.1.30",
- "picocolors": "^1.0.0",
- "source-map-js": "^0.6.2"
- }
- }
- }
- },
- "postcss-selector-matches": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz",
- "integrity": "sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww==",
- "requires": {
- "balanced-match": "^1.0.0",
- "postcss": "^7.0.2"
- }
- },
- "postcss-selector-not": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz",
- "integrity": "sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ==",
- "requires": {
- "balanced-match": "^1.0.0",
- "postcss": "^7.0.2"
- }
- },
- "postcss-selector-parser": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
- "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
- "requires": {
- "cssesc": "^3.0.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1",
- "util-deprecate": "^1.0.2"
- }
- },
- "postcss-svgo": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.3.tgz",
- "integrity": "sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw==",
- "requires": {
- "postcss": "^7.0.0",
- "postcss-value-parser": "^3.0.0",
- "svgo": "^1.0.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=="
- }
- }
- },
- "postcss-unique-selectors": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
- "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==",
- "requires": {
- "alphanum-sort": "^1.0.0",
- "postcss": "^7.0.0",
- "uniqs": "^2.0.0"
- }
- },
- "postcss-value-parser": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
- "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ=="
- },
- "postcss-values-parser": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz",
- "integrity": "sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg==",
- "requires": {
- "flatten": "^1.0.2",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- },
- "preact-render-to-string": {
- "version": "5.1.19",
- "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.1.19.tgz",
- "integrity": "sha512-bj8sn/oytIKO6RtOGSS/1+5CrQyRSC99eLUnEVbqUa6MzJX5dYh7wu9bmT0d6lm/Vea21k9KhCQwvr2sYN3rrQ==",
- "dev": true,
- "requires": {
- "pretty-format": "^3.8.0"
- },
- "dependencies": {
- "pretty-format": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz",
- "integrity": "sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U=",
- "dev": true
- }
- }
- },
- "prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
- },
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
- },
- "prettier": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.0.tgz",
- "integrity": "sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==",
- "dev": true
- },
- "pretty-bytes": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
- "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="
- },
- "pretty-error": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz",
- "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==",
- "requires": {
- "lodash": "^4.17.20",
- "renderkid": "^2.0.4"
- }
- },
- "pretty-format": {
- "version": "26.6.2",
- "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz",
- "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==",
- "requires": {
- "@jest/types": "^26.6.2",
- "ansi-regex": "^5.0.0",
- "ansi-styles": "^4.0.0",
- "react-is": "^17.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "pretty-hrtime": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
- "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
- "dev": true
- },
- "prismjs": {
- "version": "1.26.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.26.0.tgz",
- "integrity": "sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ==",
- "dev": true
- },
- "process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
- },
- "process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
- },
- "progress": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
- "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
- },
- "promise": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz",
- "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==",
- "requires": {
- "asap": "~2.0.6"
- }
- },
- "promise-inflight": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
- "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM="
- },
- "promise-map-series": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/promise-map-series/-/promise-map-series-0.2.3.tgz",
- "integrity": "sha1-wtN3r8kyU/a9A9u3d1XriKsgqEc=",
- "dev": true,
- "requires": {
- "rsvp": "^3.0.14"
- },
- "dependencies": {
- "rsvp": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz",
- "integrity": "sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw==",
- "dev": true
- }
- }
- },
- "promise.allsettled": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/promise.allsettled/-/promise.allsettled-1.0.5.tgz",
- "integrity": "sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==",
- "dev": true,
- "requires": {
- "array.prototype.map": "^1.0.4",
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "iterate-value": "^1.0.2"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "promise.prototype.finally": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz",
- "integrity": "sha512-EXRF3fC9/0gz4qkt/f5EP5iW4kj9oFpBICNpCNOb/52+8nlHIX07FPLbi/q4qYBQ1xZqivMzTpNQSnArVASolQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "prompts": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz",
- "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==",
- "requires": {
- "kleur": "^3.0.3",
- "sisteransi": "^1.0.5"
- }
- },
- "prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "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=="
- }
- }
- },
- "prop-types-extra": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
- "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
- "requires": {
- "react-is": "^16.3.2",
- "warning": "^4.0.0"
- },
- "dependencies": {
- "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=="
- }
- }
- },
- "property-information": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
- "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
- "dev": true,
- "requires": {
- "xtend": "^4.0.0"
- }
- },
- "proxy-addr": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
- "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
- "requires": {
- "forwarded": "~0.1.2",
- "ipaddr.js": "1.9.1"
- }
- },
- "proxy-from-env": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
- "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=",
- "dev": true
- },
- "prr": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
- "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
- },
- "psl": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
- "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
- },
- "public-encrypt": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
- "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
- "requires": {
- "bn.js": "^4.1.0",
- "browserify-rsa": "^4.0.0",
- "create-hash": "^1.1.0",
- "parse-asn1": "^5.0.0",
- "randombytes": "^2.0.1",
- "safe-buffer": "^5.1.2"
- },
- "dependencies": {
- "bn.js": {
- "version": "4.12.0",
- "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
- "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
- }
- }
- },
- "pump": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
- "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- },
- "pumpify": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
- "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
- "requires": {
- "duplexify": "^3.6.0",
- "inherits": "^2.0.3",
- "pump": "^2.0.0"
- },
- "dependencies": {
- "pump": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
- "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
- "requires": {
- "end-of-stream": "^1.1.0",
- "once": "^1.3.1"
- }
- }
- }
- },
- "punycode": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
- "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
- },
- "q": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
- },
- "qs": {
- "version": "6.5.2",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
- "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
- },
- "query-string": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
- "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
- "requires": {
- "object-assign": "^4.1.0",
- "strict-uri-encode": "^1.0.0"
- }
- },
- "querystring": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.1.tgz",
- "integrity": "sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg=="
- },
- "querystring-es3": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
- "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
- },
- "querystringify": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
- "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
- },
- "queue-microtask": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.2.tgz",
- "integrity": "sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg=="
- },
- "quick-lru": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
- "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g=="
- },
- "quick-temp": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/quick-temp/-/quick-temp-0.1.8.tgz",
- "integrity": "sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg=",
- "dev": true,
- "requires": {
- "mktemp": "~0.4.0",
- "rimraf": "^2.5.4",
- "underscore.string": "~3.3.4"
- },
- "dependencies": {
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "requires": {
- "glob": "^7.1.3"
- }
- }
- }
- },
- "raf": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
- "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
- "requires": {
- "performance-now": "^2.1.0"
- }
- },
- "ramda": {
- "version": "0.27.1",
- "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz",
- "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw=="
- },
- "randombytes": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
- "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
- "requires": {
- "safe-buffer": "^5.1.0"
- }
- },
- "randomfill": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
- "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
- "requires": {
- "randombytes": "^2.0.5",
- "safe-buffer": "^5.1.0"
- }
- },
- "range-parser": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
- "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
- },
- "raw-body": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
- "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
- "requires": {
- "bytes": "3.1.0",
- "http-errors": "1.7.2",
- "iconv-lite": "0.4.24",
- "unpipe": "1.0.0"
- },
- "dependencies": {
- "bytes": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
- "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
- }
- }
- },
- "raw-loader": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz",
- "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==",
- "dev": true,
- "requires": {
- "loader-utils": "^2.0.0",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==",
- "dev": true
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "dev": true,
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "rc-year-calendar": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/rc-year-calendar/-/rc-year-calendar-1.0.2.tgz",
- "integrity": "sha512-TdEHZ4hs3WEuEAAmX/HEWlK7EZwhACkpuJKdkxL360igekuQDguyXTC9RuDFdk6lv4CAT7L4d4D6PTP7zUMBlQ==",
- "requires": {
- "js-year-calendar": "^1.0.2"
- }
- },
- "react": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
- "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
- "react-app-polyfill": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz",
- "integrity": "sha512-0sF4ny9v/B7s6aoehwze9vJNWcmCemAUYBVasscVr92+UYiEqDXOxfKjXN685mDaMRNF3WdhHQs76oTODMocFA==",
- "requires": {
- "core-js": "^3.6.5",
- "object-assign": "^4.1.1",
- "promise": "^8.1.0",
- "raf": "^3.4.1",
- "regenerator-runtime": "^0.13.7",
- "whatwg-fetch": "^3.4.1"
- }
- },
- "react-bootstrap": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.5.0.tgz",
- "integrity": "sha512-t1o4kP3coj2HIaBepJxGAc7HZ1fWGria/s0Yr9JUmNkCilyrnXtK209qn28vuZ4muhnA0uR0GMMXAMrLsLyiIw==",
- "requires": {
- "@babel/runtime": "^7.4.2",
- "@restart/context": "^2.1.4",
- "@restart/hooks": "^0.3.21",
- "@types/classnames": "^2.2.10",
- "@types/invariant": "^2.2.33",
- "@types/prop-types": "^15.7.3",
- "@types/react": ">=16.9.35",
- "@types/react-transition-group": "^4.4.0",
- "@types/warning": "^3.0.0",
- "classnames": "^2.2.6",
- "dom-helpers": "^5.1.2",
- "invariant": "^2.2.4",
- "prop-types": "^15.7.2",
- "prop-types-extra": "^1.1.0",
- "react-overlays": "^4.1.1",
- "react-transition-group": "^4.4.1",
- "uncontrollable": "^7.0.0",
- "warning": "^4.0.3"
- }
- },
- "react-chartkick": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/react-chartkick/-/react-chartkick-0.3.3.tgz",
- "integrity": "sha512-O9+FMEKguHTlZiJQ3kXCN4Kqzx2f4qvv70F9L0SSdzgwS0mmSKiRO32yJ6sFnv4AeceTSsCHhFb3ZR3hRFtiGQ==",
- "requires": {
- "chartkick": "^3.1.3"
- }
- },
- "react-colorful": {
- "version": "5.5.1",
- "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.5.1.tgz",
- "integrity": "sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg==",
- "dev": true
- },
- "react-dev-utils": {
- "version": "11.0.4",
- "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
- "integrity": "sha512-dx0LvIGHcOPtKbeiSUM4jqpBl3TcY7CDjZdfOIcKeznE7BWr9dg0iPG90G5yfVQ+p/rGNMXdbfStvzQZEVEi4A==",
- "requires": {
- "@babel/code-frame": "7.10.4",
- "address": "1.1.2",
- "browserslist": "4.14.2",
- "chalk": "2.4.2",
- "cross-spawn": "7.0.3",
- "detect-port-alt": "1.1.6",
- "escape-string-regexp": "2.0.0",
- "filesize": "6.1.0",
- "find-up": "4.1.0",
- "fork-ts-checker-webpack-plugin": "4.1.6",
- "global-modules": "2.0.0",
- "globby": "11.0.1",
- "gzip-size": "5.1.1",
- "immer": "8.0.1",
- "is-root": "2.1.0",
- "loader-utils": "2.0.0",
- "open": "^7.0.2",
- "pkg-up": "3.1.0",
- "prompts": "2.4.0",
- "react-error-overlay": "^6.0.9",
- "recursive-readdir": "2.2.2",
- "shell-quote": "1.7.2",
- "strip-ansi": "6.0.0",
- "text-table": "0.2.0"
- },
- "dependencies": {
- "@babel/code-frame": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
- "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
- "requires": {
- "@babel/highlight": "^7.10.4"
- }
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
- }
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "globby": {
- "version": "11.0.1",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
- "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
- "requires": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.1.1",
- "ignore": "^5.1.4",
- "merge2": "^1.3.0",
- "slash": "^3.0.0"
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "immer": {
- "version": "9.0.12",
- "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.12.tgz",
- "integrity": "sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA=="
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "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"
- }
- }
- }
- },
- "react-docgen": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/react-docgen/-/react-docgen-5.4.0.tgz",
- "integrity": "sha512-JBjVQ9cahmNlfjMGxWUxJg919xBBKAoy3hgDgKERbR+BcF4ANpDuzWAScC7j27hZfd8sJNmMPOLWo9+vB/XJEQ==",
- "dev": true,
- "requires": {
- "@babel/core": "^7.7.5",
- "@babel/generator": "^7.12.11",
- "@babel/runtime": "^7.7.6",
- "ast-types": "^0.14.2",
- "commander": "^2.19.0",
- "doctrine": "^3.0.0",
- "estree-to-babel": "^3.1.0",
- "neo-async": "^2.6.1",
- "node-dir": "^0.1.10",
- "strip-indent": "^3.0.0"
- },
- "dependencies": {
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
- "dev": true
- }
- }
- },
- "react-docgen-typescript": {
- "version": "1.22.0",
- "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-1.22.0.tgz",
- "integrity": "sha512-MPLbF8vzRwAG3GcjdL+OHQlhgtWsLTXs+7uJiHfEeT3Ur7IsZaNYqRTLQ9sj2nB6M6jylcPCeCmH7qbszJmecg==",
- "dev": true
- },
- "react-docgen-typescript-plugin": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/react-docgen-typescript-plugin/-/react-docgen-typescript-plugin-1.0.0.tgz",
- "integrity": "sha512-Akc7EtryOA4d2yOX27B5ii+hyf/k15ymb01uB+VnRgtTAdfeDCmNPvyLbRJ6pRNYOuFlEBe1YfCH73bTPtpYVQ==",
- "dev": true,
- "requires": {
- "debug": "^4.1.1",
- "endent": "^2.0.1",
- "find-cache-dir": "^3.3.1",
- "flat-cache": "^3.0.4",
- "micromatch": "^4.0.2",
- "react-docgen-typescript": "^1.22.0",
- "tslib": "^2.0.0",
- "webpack-sources": "^2.2.0"
- },
- "dependencies": {
- "find-cache-dir": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
- "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
- "dev": true,
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "dev": true,
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "dev": true,
- "requires": {
- "find-up": "^4.0.0"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true
- },
- "tslib": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
- "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==",
- "dev": true
- },
- "webpack-sources": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.1.tgz",
- "integrity": "sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==",
- "dev": true,
- "requires": {
- "source-list-map": "^2.0.1",
- "source-map": "^0.6.1"
- }
- }
- }
- },
- "react-dom": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
- "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "scheduler": "^0.20.2"
- }
- },
- "react-draggable": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.4.tgz",
- "integrity": "sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==",
- "dev": true,
- "requires": {
- "clsx": "^1.1.1",
- "prop-types": "^15.6.0"
- }
- },
- "react-element-to-jsx-string": {
- "version": "14.3.4",
- "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-14.3.4.tgz",
- "integrity": "sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==",
- "dev": true,
- "requires": {
- "@base2/pretty-print-object": "1.0.1",
- "is-plain-object": "5.0.0",
- "react-is": "17.0.2"
- },
- "dependencies": {
- "is-plain-object": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
- "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
- "dev": true
- },
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- }
- }
- },
- "react-error-overlay": {
- "version": "6.0.9",
- "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.9.tgz",
- "integrity": "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew=="
- },
- "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==",
- "dev": true
- },
- "react-floater": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.2.tgz",
- "integrity": "sha512-YKixUNXdySMqo4gh6ZGVLI/h7cI59MFQKOG38jAdBJl7XVC///w+sa7dmz+o2xWe4oUSey3z2vmg+AtX7A7Kug==",
- "requires": {
- "deepmerge": "^4.2.2",
- "exenv": "^1.2.2",
- "is-lite": "^0.6.0",
- "popper.js": "^1.16.0",
- "react-proptype-conditional-require": "^1.0.4",
- "tree-changes": "^0.5.1"
- },
- "dependencies": {
- "popper.js": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
- "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ=="
- }
- }
- },
- "react-google-login": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/react-google-login/-/react-google-login-5.2.2.tgz",
- "integrity": "sha512-JUngfvaSMcOuV0lFff7+SzJ2qviuNMQdqlsDJkUM145xkGPVIfqWXq9Ui+2Dr6jdJWH5KYdynz9+4CzKjI5u6g==",
- "requires": {
- "@types/react": "*",
- "prop-types": "^15.6.0"
- }
- },
- "react-helmet-async": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.2.2.tgz",
- "integrity": "sha512-XgSQezeCbLfCxdZhDA3T/g27XZKnOYyOkruopTLSJj8RvFZwdXnM4djnfYaiBSDzOidDgTo1jcEozoRu/+P9UQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.12.5",
- "invariant": "^2.2.4",
- "prop-types": "^15.7.2",
- "react-fast-compare": "^3.2.0",
- "shallowequal": "^1.1.0"
- }
- },
- "react-hook-form": {
- "version": "7.13.0-next.0",
- "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.13.0-next.0.tgz",
- "integrity": "sha512-Fg6SolE4zWJrVmTUuCMTusX9eHJmRiNMtlCAXAOVNr97HMupCJjXUULpfWhBi+mupiIsGo3WayR7wfveZNIuBg=="
- },
- "react-i18next": {
- "version": "11.8.8",
- "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.8.8.tgz",
- "integrity": "sha512-Z8Daifh+FRpcQsCp48mWQViYSlojv0WiL2bf6e9DOzpfVMDaTT6qsYRbHCjLEeDeEioxoaWHMiWu2JPTW3Ni4w==",
- "requires": {
- "@babel/runtime": "^7.13.6",
- "html-parse-stringify2": "^2.0.1"
- }
- },
- "react-icons": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.2.0.tgz",
- "integrity": "sha512-rmzEDFt+AVXRzD7zDE21gcxyBizD/3NqjbX6cmViAgdqfJ2UiLer8927/QhhrXQV7dEj/1EGuOTPp7JnLYVJKQ=="
- },
- "react-input-autosize": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz",
- "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==",
- "requires": {
- "prop-types": "^15.5.8"
- }
- },
- "react-inspector": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz",
- "integrity": "sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.0.0",
- "is-dom": "^1.0.0",
- "prop-types": "^15.0.0"
- }
- },
- "react-is": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz",
- "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA=="
- },
- "react-joyride": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/react-joyride/-/react-joyride-2.3.0.tgz",
- "integrity": "sha512-aY7+dgmBKbgGoMjN828qXnMAqeA6QvwvSWxj/fyvxIIIx0iu3wNVT/A5NZ0wHxiVDav+Df9YZuL412Q6C0l7gw==",
- "requires": {
- "deep-diff": "^1.0.2",
- "deepmerge": "^4.2.2",
- "exenv": "^1.2.2",
- "is-lite": "^0.8.0",
- "nested-property": "^4.0.0",
- "react-floater": "^0.7.2",
- "react-is": "^16.13.1",
- "scroll": "^3.0.1",
- "scrollparent": "^2.0.1",
- "tree-changes": "^0.6.1"
- },
- "dependencies": {
- "is-lite": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/is-lite/-/is-lite-0.8.0.tgz",
- "integrity": "sha512-w/+euF/pELyAgLA6Pai8Vp3l2EMJygQx1wGkKf/Gu7/qTWxZvYFKrdVF4qbi9YdVmISzB/jE4Q7yO9alrHQa8A=="
- },
- "nested-property": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/nested-property/-/nested-property-4.0.0.tgz",
- "integrity": "sha512-yFehXNWRs4cM0+dz7QxCd06hTbWbSkV0ISsqBfkntU6TOY4Qm3Q88fRRLOddkGh2Qq6dZvnKVAahfhjcUvLnyA=="
- },
- "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=="
- },
- "tree-changes": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.6.1.tgz",
- "integrity": "sha512-J+eb7K2hHq8BexW71U5jPHr8RGtd7270plLBjz2a5ubsMpEhInH14k2kafHoCL+bncYS3ixGidToVwpzwC8kug==",
- "requires": {
- "fast-deep-equal": "^3.1.3",
- "is-lite": "^0.8.0",
- "react": "^16.8.0 || ^17.0.0"
- }
- }
- }
- },
- "react-lifecycles-compat": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
- "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
- },
- "react-load-script": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/react-load-script/-/react-load-script-0.0.6.tgz",
- "integrity": "sha512-aRGxDGP9VoLxcsaYvKWIW+LRrMOzz2eEcubTS4NvQPPugjk2VvMhow0wWTkSl7RxookomD1MwcP4l5UStg5ShQ=="
- },
- "react-markdown": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-5.0.3.tgz",
- "integrity": "sha512-jDWOc1AvWn0WahpjW6NK64mtx6cwjM4iSsLHJPNBqoAgGOVoIdJMqaKX4++plhOtdd4JksdqzlDibgPx6B/M2w==",
- "requires": {
- "@types/mdast": "^3.0.3",
- "@types/unist": "^2.0.3",
- "html-to-react": "^1.3.4",
- "mdast-add-list-metadata": "1.0.1",
- "prop-types": "^15.7.2",
- "react-is": "^16.8.6",
- "remark-parse": "^9.0.0",
- "unified": "^9.0.0",
- "unist-util-visit": "^2.0.0",
- "xtend": "^4.0.1"
- },
- "dependencies": {
- "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-move": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/react-move/-/react-move-6.4.0.tgz",
- "integrity": "sha512-TNyDQESDZ0xsejnxFTQ9CKarJQN6NbgpImrvIEzOVe7+jt8y7uTjJwWxqFTfmvwskIs+RmUbCWdN7PAbGyhrdA==",
- "requires": {
- "@babel/runtime": "^7.10.3",
- "kapellmeister": "^3.0.1",
- "prop-types": "^15.7.2"
- }
- },
- "react-native-segmented-control-tab": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/react-native-segmented-control-tab/-/react-native-segmented-control-tab-3.4.1.tgz",
- "integrity": "sha512-BNPdlE9Unr0Xabewn8W+FhBMLjssXy9Ey7S7AY0hXlrKrEKFdC9z0yT+eEWd5dLam4T6T4IuGL8b7ZF4uGyWNw=="
- },
- "react-overlays": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-4.1.1.tgz",
- "integrity": "sha512-WtJifh081e6M24KnvTQoNjQEpz7HoLxqt8TwZM7LOYIkYJ8i/Ly1Xi7RVte87ZVnmqQ4PFaFiNHZhSINPSpdBQ==",
- "requires": {
- "@babel/runtime": "^7.12.1",
- "@popperjs/core": "^2.5.3",
- "@restart/hooks": "^0.3.25",
- "@types/warning": "^3.0.0",
- "dom-helpers": "^5.2.0",
- "prop-types": "^15.7.2",
- "uncontrollable": "^7.0.0",
- "warning": "^4.0.3"
- }
- },
- "react-player": {
- "version": "1.15.3",
- "resolved": "https://registry.npmjs.org/react-player/-/react-player-1.15.3.tgz",
- "integrity": "sha512-8fc0R1AipFIy7l4lKgnIg+gMU2IY32ZMxxBlINjXAq/YnN3HUP3hOaE+aQ0lQv+a1/MMZgbekWD86ZGDO7kB8g==",
- "requires": {
- "deepmerge": "^4.0.0",
- "load-script": "^1.0.0",
- "prop-types": "^15.7.2"
- }
- },
- "react-popper": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz",
- "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==",
- "dev": true,
- "requires": {
- "react-fast-compare": "^3.0.1",
- "warning": "^4.0.2"
- }
- },
- "react-popper-tooltip": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz",
- "integrity": "sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.12.5",
- "@popperjs/core": "^2.5.4",
- "react-popper": "^2.2.4"
- }
- },
- "react-proptype-conditional-require": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz",
- "integrity": "sha1-acLVdB5t9eCPIw82u8KUTuEiJVU="
- },
- "react-redux": {
- "version": "7.2.4",
- "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz",
- "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==",
- "requires": {
- "@babel/runtime": "^7.12.1",
- "@types/react-redux": "^7.1.16",
- "hoist-non-react-statics": "^3.3.2",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.7.2",
- "react-is": "^16.13.1"
- },
- "dependencies": {
- "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-redux-form": {
- "version": "1.16.14",
- "resolved": "https://registry.npmjs.org/react-redux-form/-/react-redux-form-1.16.14.tgz",
- "integrity": "sha512-exd8FoWwJRQynjnYqCLmcbwcqgRPyU+qiKmTA7/T8qlNgyqgmbAgkYNe9NG9FYb5oLgHAtx5vDhVEpje888lIA==",
- "requires": {
- "icepick": "^1.1.0",
- "invariant": "~2.2.1",
- "lodash.get": "~4.4.2",
- "lodash.topath": "~4.5.2",
- "prop-types": "^15.5.6",
- "react-native-segmented-control-tab": "^3.2.1",
- "shallow-compare": "^1.2.1"
- }
- },
- "react-refresh": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
- "integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
- },
- "react-responsive": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.2.0.tgz",
- "integrity": "sha512-iagCqVrw4QSjhxKp3I/YK6+ODkWY6G+YPElvdYKiUUbywwh9Ds0M7r26Fj2/7dWFFbOpcGnJE6uE7aMck8j5Qg==",
- "requires": {
- "hyphenate-style-name": "^1.0.0",
- "matchmediaquery": "^0.3.0",
- "prop-types": "^15.6.1",
- "shallow-equal": "^1.1.0"
- }
- },
- "react-router": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
- "integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
- "requires": {
- "history": "^4.7.2",
- "hoist-non-react-statics": "^2.5.0",
- "invariant": "^2.2.4",
- "loose-envify": "^1.3.1",
- "path-to-regexp": "^1.7.0",
- "prop-types": "^15.6.1",
- "warning": "^4.0.1"
- },
- "dependencies": {
- "hoist-non-react-statics": {
- "version": "2.5.5",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
- "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
- }
- }
- },
- "react-router-dom": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
- "integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==",
- "requires": {
- "history": "^4.7.2",
- "invariant": "^2.2.4",
- "loose-envify": "^1.3.1",
- "prop-types": "^15.6.1",
- "react-router": "^4.3.1",
- "warning": "^4.0.1"
- }
- },
- "react-scripts": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-4.0.3.tgz",
- "integrity": "sha512-S5eO4vjUzUisvkIPB7jVsKtuH2HhWcASREYWHAQ1FP5HyCv3xgn+wpILAEWkmy+A+tTNbSZClhxjT3qz6g4L1A==",
- "requires": {
- "@babel/core": "7.12.3",
- "@pmmmwh/react-refresh-webpack-plugin": "0.4.3",
- "@svgr/webpack": "5.5.0",
- "@typescript-eslint/eslint-plugin": "^4.5.0",
- "@typescript-eslint/parser": "^4.5.0",
- "babel-eslint": "^10.1.0",
- "babel-jest": "^26.6.0",
- "babel-loader": "8.1.0",
- "babel-plugin-named-asset-import": "^0.3.7",
- "babel-preset-react-app": "^10.0.0",
- "bfj": "^7.0.2",
- "camelcase": "^6.1.0",
- "case-sensitive-paths-webpack-plugin": "2.3.0",
- "css-loader": "4.3.0",
- "dotenv": "8.2.0",
- "dotenv-expand": "5.1.0",
- "eslint": "^7.11.0",
- "eslint-config-react-app": "^6.0.0",
- "eslint-plugin-flowtype": "^5.2.0",
- "eslint-plugin-import": "^2.22.1",
- "eslint-plugin-jest": "^24.1.0",
- "eslint-plugin-jsx-a11y": "^6.3.1",
- "eslint-plugin-react": "^7.21.5",
- "eslint-plugin-react-hooks": "^4.2.0",
- "eslint-plugin-testing-library": "^3.9.2",
- "eslint-webpack-plugin": "^2.5.2",
- "file-loader": "6.1.1",
- "fs-extra": "^9.0.1",
- "fsevents": "^2.1.3",
- "html-webpack-plugin": "4.5.0",
- "identity-obj-proxy": "3.0.0",
- "jest": "26.6.0",
- "jest-circus": "26.6.0",
- "jest-resolve": "26.6.0",
- "jest-watch-typeahead": "0.6.1",
- "mini-css-extract-plugin": "0.11.3",
- "optimize-css-assets-webpack-plugin": "5.0.4",
- "pnp-webpack-plugin": "1.6.4",
- "postcss-flexbugs-fixes": "4.2.1",
- "postcss-loader": "3.0.0",
- "postcss-normalize": "8.0.1",
- "postcss-preset-env": "6.7.0",
- "postcss-safe-parser": "5.0.2",
- "prompts": "2.4.0",
- "react-app-polyfill": "^2.0.0",
- "react-dev-utils": "^11.0.3",
- "react-refresh": "^0.8.3",
- "resolve": "1.18.1",
- "resolve-url-loader": "^3.1.2",
- "sass-loader": "^10.0.5",
- "semver": "7.3.2",
- "style-loader": "1.3.0",
- "terser-webpack-plugin": "4.2.3",
- "ts-pnp": "1.2.0",
- "url-loader": "4.1.1",
- "webpack": "4.44.2",
- "webpack-dev-server": "3.11.1",
- "webpack-manifest-plugin": "2.2.0",
- "workbox-webpack-plugin": "5.1.4"
- },
- "dependencies": {
- "camelcase": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
- "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg=="
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "jest-resolve": {
- "version": "26.6.0",
- "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.0.tgz",
- "integrity": "sha512-tRAz2bwraHufNp+CCmAD8ciyCpXCs1NQxB5EJAmtCFy6BN81loFEGWKzYu26Y62lAJJe4X4jg36Kf+NsQyiStQ==",
- "requires": {
- "@jest/types": "^26.6.0",
- "chalk": "^4.0.0",
- "graceful-fs": "^4.2.4",
- "jest-pnp-resolver": "^1.2.2",
- "jest-util": "^26.6.0",
- "read-pkg-up": "^7.0.1",
- "resolve": "^1.17.0",
- "slash": "^3.0.0"
- }
- },
- "jest-watch-typeahead": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/jest-watch-typeahead/-/jest-watch-typeahead-0.6.1.tgz",
- "integrity": "sha512-ITVnHhj3Jd/QkqQcTqZfRgjfyRhDFM/auzgVo2RKvSwi18YMvh0WvXDJFoFED6c7jd/5jxtu4kSOb9PTu2cPVg==",
- "requires": {
- "ansi-escapes": "^4.3.1",
- "chalk": "^4.0.0",
- "jest-regex-util": "^26.0.0",
- "jest-watcher": "^26.3.0",
- "slash": "^3.0.0",
- "string-length": "^4.0.1",
- "strip-ansi": "^6.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- }
- },
- "parse-json": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
- "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
- "requires": {
- "@babel/code-frame": "^7.0.0",
- "error-ex": "^1.3.1",
- "json-parse-even-better-errors": "^2.3.0",
- "lines-and-columns": "^1.1.6"
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "resolve": {
- "version": "1.18.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
- "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==",
- "requires": {
- "is-core-module": "^2.0.0",
- "path-parse": "^1.0.6"
- }
- },
- "semver": {
- "version": "7.3.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
- "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ=="
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "react-select": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/react-select/-/react-select-4.2.1.tgz",
- "integrity": "sha512-JwwZjsR10AD5RXmx4iEkN0Ndim/uSaQ8j8cxMwOg8SJFeyXwu/m+sdSQ0ds0AWFm7hhXG9kusC3CQ/s4UNcOIg==",
- "requires": {
- "@babel/runtime": "^7.12.0",
- "@emotion/cache": "^11.0.0",
- "@emotion/react": "^11.1.1",
- "memoize-one": "^5.0.0",
- "prop-types": "^15.6.0",
- "react-input-autosize": "^3.0.0",
- "react-transition-group": "^4.3.0"
- },
- "dependencies": {
- "@emotion/cache": {
- "version": "11.1.3",
- "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.1.3.tgz",
- "integrity": "sha512-n4OWinUPJVaP6fXxWZD9OUeQ0lY7DvtmtSuqtRWT0Ofo/sBLCVSgb4/Oa0Q5eFxcwablRKjUXqXtNZVyEwCAuA==",
- "requires": {
- "@emotion/memoize": "^0.7.4",
- "@emotion/sheet": "^1.0.0",
- "@emotion/utils": "^1.0.0",
- "@emotion/weak-memoize": "^0.2.5",
- "stylis": "^4.0.3"
- }
- },
- "@emotion/sheet": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.1.tgz",
- "integrity": "sha512-GbIvVMe4U+Zc+929N1V7nW6YYJtidj31lidSmdYcWozwoBIObXBnaJkKNDjZrLm9Nc0BR+ZyHNaRZxqNZbof5g=="
- },
- "@emotion/utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
- "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
- }
- }
- },
- "react-shallow-renderer": {
- "version": "16.14.1",
- "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
- "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==",
- "dev": true,
- "requires": {
- "object-assign": "^4.1.1",
- "react-is": "^16.12.0 || ^17.0.0"
- }
- },
- "react-sizeme": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/react-sizeme/-/react-sizeme-3.0.2.tgz",
- "integrity": "sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==",
- "dev": true,
- "requires": {
- "element-resize-detector": "^1.2.2",
- "invariant": "^2.2.4",
- "shallowequal": "^1.1.0",
- "throttle-debounce": "^3.0.1"
- }
- },
- "react-syntax-highlighter": {
- "version": "13.5.3",
- "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz",
- "integrity": "sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.3.1",
- "highlight.js": "^10.1.1",
- "lowlight": "^1.14.0",
- "prismjs": "^1.21.0",
- "refractor": "^3.1.0"
- }
- },
- "react-table": {
- "version": "6.11.5",
- "resolved": "https://registry.npmjs.org/react-table/-/react-table-6.11.5.tgz",
- "integrity": "sha512-LM+AS9v//7Y7lAlgTWW/cW6Sn5VOb3EsSkKQfQTzOW8FngB1FUskLLNEVkAYsTX9LjOWR3QlGjykJqCE6eXT/g==",
- "requires": {
- "@types/react-table": "^6.8.5",
- "classnames": "^2.2.5",
- "react-is": "^16.8.1"
- },
- "dependencies": {
- "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-tabs-redux": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/react-tabs-redux/-/react-tabs-redux-4.0.0.tgz",
- "integrity": "sha512-yk5afCpUlmWqXA/fhSi02YaCSlpFH5v6QlUiiVRx+V1OTyLDaZFDnARCflUoGkwIq00o7ryVWUXNkQ3UwAcebA==",
- "requires": {
- "classnames": "^2.2.6",
- "prop-types": "^15.6.2"
- }
- },
- "react-test-renderer": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
- "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==",
- "dev": true,
- "requires": {
- "object-assign": "^4.1.1",
- "react-is": "^17.0.2",
- "react-shallow-renderer": "^16.13.1",
- "scheduler": "^0.20.2"
- },
- "dependencies": {
- "react-is": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
- "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
- "dev": true
- }
- }
- },
- "react-textarea-autosize": {
- "version": "8.3.3",
- "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz",
- "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.10.2",
- "use-composed-ref": "^1.0.0",
- "use-latest": "^1.0.0"
- }
- },
- "react-transition-group": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
- "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
- "requires": {
- "@babel/runtime": "^7.5.5",
- "dom-helpers": "^5.0.1",
- "loose-envify": "^1.4.0",
- "prop-types": "^15.6.2"
- }
- },
- "read-pkg": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
- "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
- "requires": {
- "@types/normalize-package-data": "^2.4.0",
- "normalize-package-data": "^2.5.0",
- "parse-json": "^5.0.0",
- "type-fest": "^0.6.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
- "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg=="
- }
- }
- },
- "read-pkg-up": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
- "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
- "requires": {
- "find-up": "^4.1.0",
- "read-pkg": "^5.2.0",
- "type-fest": "^0.8.1"
- }
- },
- "readable-stream": {
- "version": "2.3.7",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
- "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
- "requires": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "readdirp": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
- "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
- "requires": {
- "picomatch": "^2.2.1"
- }
- },
- "realpath-native": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz",
- "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==",
- "dev": true,
- "requires": {
- "util.promisify": "^1.0.0"
- }
- },
- "recursive-readdir": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
- "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==",
- "requires": {
- "minimatch": "3.0.4"
- }
- },
- "redent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
- "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
- "requires": {
- "indent-string": "^4.0.0",
- "strip-indent": "^3.0.0"
- }
- },
- "redux": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz",
- "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==",
- "requires": {
- "@babel/runtime": "^7.9.2"
- }
- },
- "redux-persist": {
- "version": "5.10.0",
- "resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-5.10.0.tgz",
- "integrity": "sha512-sSJAzNq7zka3qVHKce1hbvqf0Vf5DuTVm7dr4GtsqQVOexnrvbV47RWFiPxQ8fscnyiuWyD2O92DOxPl0tGCRg=="
- },
- "redux-saga": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
- "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
- "requires": {
- "@redux-saga/core": "^1.1.3"
- }
- },
- "redux-thunk": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
- "integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
- },
- "refractor": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.5.0.tgz",
- "integrity": "sha512-QwPJd3ferTZ4cSPPjdP5bsYHMytwWYnAN5EEnLtGvkqp/FCCnGsBgxrm9EuIDnjUC3Uc/kETtvVi7fSIVC74Dg==",
- "dev": true,
- "requires": {
- "hastscript": "^6.0.0",
- "parse-entities": "^2.0.0",
- "prismjs": "~1.25.0"
- },
- "dependencies": {
- "prismjs": {
- "version": "1.25.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz",
- "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==",
- "dev": true
- }
- }
- },
- "regenerate": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
- "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="
- },
- "regenerate-unicode-properties": {
- "version": "8.2.0",
- "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
- "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
- "requires": {
- "regenerate": "^1.4.0"
- }
- },
- "regenerator-runtime": {
- "version": "0.13.7",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
- "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
- },
- "regenerator-transform": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz",
- "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==",
- "requires": {
- "@babel/runtime": "^7.8.4"
- }
- },
- "regex-not": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
- "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
- "requires": {
- "extend-shallow": "^3.0.2",
- "safe-regex": "^1.1.0"
- }
- },
- "regex-parser": {
- "version": "2.2.11",
- "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
- "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q=="
- },
- "regexp.prototype.flags": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz",
- "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "regexpp": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
- "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q=="
- },
- "regexpu-core": {
- "version": "4.7.1",
- "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz",
- "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==",
- "requires": {
- "regenerate": "^1.4.0",
- "regenerate-unicode-properties": "^8.2.0",
- "regjsgen": "^0.5.1",
- "regjsparser": "^0.6.4",
- "unicode-match-property-ecmascript": "^1.0.4",
- "unicode-match-property-value-ecmascript": "^1.2.0"
- }
- },
- "regjsgen": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
- "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A=="
- },
- "regjsparser": {
- "version": "0.6.7",
- "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.7.tgz",
- "integrity": "sha512-ib77G0uxsA2ovgiYbCVGx4Pv3PSttAx2vIwidqQzbL2U5S4Q+j00HdSAneSBuyVcMvEnTXMjiGgB+DlXozVhpQ==",
- "requires": {
- "jsesc": "~0.5.0"
- },
- "dependencies": {
- "jsesc": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
- "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
- }
- }
- },
- "relateurl": {
- "version": "0.2.7",
- "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
- "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
- },
- "remark-external-links": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-8.0.0.tgz",
- "integrity": "sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==",
- "dev": true,
- "requires": {
- "extend": "^3.0.0",
- "is-absolute-url": "^3.0.0",
- "mdast-util-definitions": "^4.0.0",
- "space-separated-tokens": "^1.0.0",
- "unist-util-visit": "^2.0.0"
- },
- "dependencies": {
- "is-absolute-url": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
- "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==",
- "dev": true
- }
- }
- },
- "remark-footnotes": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/remark-footnotes/-/remark-footnotes-2.0.0.tgz",
- "integrity": "sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==",
- "dev": true
- },
- "remark-mdx": {
- "version": "1.6.22",
- "resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-1.6.22.tgz",
- "integrity": "sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==",
- "dev": true,
- "requires": {
- "@babel/core": "7.12.9",
- "@babel/helper-plugin-utils": "7.10.4",
- "@babel/plugin-proposal-object-rest-spread": "7.12.1",
- "@babel/plugin-syntax-jsx": "7.12.1",
- "@mdx-js/util": "1.6.22",
- "is-alphabetical": "1.0.4",
- "remark-parse": "8.0.3",
- "unified": "9.2.0"
- },
- "dependencies": {
- "@babel/core": {
- "version": "7.12.9",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
- "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
- "dev": true,
- "requires": {
- "@babel/code-frame": "^7.10.4",
- "@babel/generator": "^7.12.5",
- "@babel/helper-module-transforms": "^7.12.1",
- "@babel/helpers": "^7.12.5",
- "@babel/parser": "^7.12.7",
- "@babel/template": "^7.12.7",
- "@babel/traverse": "^7.12.9",
- "@babel/types": "^7.12.7",
- "convert-source-map": "^1.7.0",
- "debug": "^4.1.0",
- "gensync": "^1.0.0-beta.1",
- "json5": "^2.1.2",
- "lodash": "^4.17.19",
- "resolve": "^1.3.2",
- "semver": "^5.4.1",
- "source-map": "^0.5.0"
- }
- },
- "@babel/helper-plugin-utils": {
- "version": "7.10.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
- "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
- "dev": true
- },
- "@babel/plugin-proposal-object-rest-spread": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
- "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4",
- "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
- "@babel/plugin-transform-parameters": "^7.12.1"
- }
- },
- "@babel/plugin-syntax-jsx": {
- "version": "7.12.1",
- "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.12.1.tgz",
- "integrity": "sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==",
- "dev": true,
- "requires": {
- "@babel/helper-plugin-utils": "^7.10.4"
- }
- },
- "remark-parse": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
- "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
- "dev": true,
- "requires": {
- "ccount": "^1.0.0",
- "collapse-white-space": "^1.0.2",
- "is-alphabetical": "^1.0.0",
- "is-decimal": "^1.0.0",
- "is-whitespace-character": "^1.0.0",
- "is-word-character": "^1.0.0",
- "markdown-escapes": "^1.0.0",
- "parse-entities": "^2.0.0",
- "repeat-string": "^1.5.4",
- "state-toggle": "^1.0.0",
- "trim": "0.0.1",
- "trim-trailing-lines": "^1.0.0",
- "unherit": "^1.0.4",
- "unist-util-remove-position": "^2.0.0",
- "vfile-location": "^3.0.0",
- "xtend": "^4.0.1"
- },
- "dependencies": {
- "trim": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/trim/-/trim-1.0.1.tgz",
- "integrity": "sha512-3JVP2YVqITUisXblCDq/Bi4P9457G/sdEamInkyvCsjbTcXLXIiG7XCb4kGMFWh6JGXesS3TKxOPtrncN/xe8w==",
- "dev": true
- }
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "dev": true
- }
- }
- },
- "remark-parse": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz",
- "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==",
- "requires": {
- "mdast-util-from-markdown": "^0.8.0"
- }
- },
- "remark-slug": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/remark-slug/-/remark-slug-6.1.0.tgz",
- "integrity": "sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==",
- "dev": true,
- "requires": {
- "github-slugger": "^1.0.0",
- "mdast-util-to-string": "^1.0.0",
- "unist-util-visit": "^2.0.0"
- },
- "dependencies": {
- "mdast-util-to-string": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
- "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
- "dev": true
- }
- }
- },
- "remark-squeeze-paragraphs": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/remark-squeeze-paragraphs/-/remark-squeeze-paragraphs-4.0.0.tgz",
- "integrity": "sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==",
- "dev": true,
- "requires": {
- "mdast-squeeze-paragraphs": "^4.0.0"
- }
- },
- "remove-bom-buffer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
- "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
- "dev": true,
- "requires": {
- "is-buffer": "^1.1.5",
- "is-utf8": "^0.2.1"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- }
- }
- },
- "remove-bom-stream": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
- "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
- "dev": true,
- "requires": {
- "remove-bom-buffer": "^3.0.0",
- "safe-buffer": "^5.1.0",
- "through2": "^2.0.3"
- }
- },
- "remove-trailing-separator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
- },
- "renderkid": {
- "version": "2.0.7",
- "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz",
- "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==",
- "requires": {
- "css-select": "^4.1.3",
- "dom-converter": "^0.2.0",
- "htmlparser2": "^6.1.0",
- "lodash": "^4.17.21",
- "strip-ansi": "^3.0.1"
- },
- "dependencies": {
- "css-select": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz",
- "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==",
- "requires": {
- "boolbase": "^1.0.0",
- "css-what": "^5.0.0",
- "domhandler": "^4.2.0",
- "domutils": "^2.6.0",
- "nth-check": "^2.0.0"
- },
- "dependencies": {
- "nth-check": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
- "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
- "requires": {
- "boolbase": "^1.0.0"
- }
- }
- }
- },
- "css-what": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz",
- "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw=="
- },
- "domelementtype": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz",
- "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
- },
- "domhandler": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz",
- "integrity": "sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w==",
- "requires": {
- "domelementtype": "^2.2.0"
- }
- },
- "domutils": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
- "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
- "requires": {
- "dom-serializer": "^1.0.1",
- "domelementtype": "^2.2.0",
- "domhandler": "^4.2.0"
- }
- },
- "htmlparser2": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
- "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==",
- "requires": {
- "domelementtype": "^2.0.1",
- "domhandler": "^4.0.0",
- "domutils": "^2.5.2",
- "entities": "^2.0.0"
- }
- },
- "nth-check": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
- "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
- "requires": {
- "boolbase": "^1.0.0"
- }
- }
- }
- },
- "repeat-element": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
- "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g=="
- },
- "repeat-string": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
- },
- "replace-ext": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
- "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
- "dev": true
- },
- "request": {
- "version": "2.88.2",
- "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
- "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
- "requires": {
- "aws-sign2": "~0.7.0",
- "aws4": "^1.8.0",
- "caseless": "~0.12.0",
- "combined-stream": "~1.0.6",
- "extend": "~3.0.2",
- "forever-agent": "~0.6.1",
- "form-data": "~2.3.2",
- "har-validator": "~5.1.3",
- "http-signature": "~1.2.0",
- "is-typedarray": "~1.0.0",
- "isstream": "~0.1.2",
- "json-stringify-safe": "~5.0.1",
- "mime-types": "~2.1.19",
- "oauth-sign": "~0.9.0",
- "performance-now": "^2.1.0",
- "qs": "~6.5.2",
- "safe-buffer": "^5.1.2",
- "tough-cookie": "~2.5.0",
- "tunnel-agent": "^0.6.0",
- "uuid": "^3.3.2"
- },
- "dependencies": {
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
- }
- },
- "request-progress": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz",
- "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=",
- "dev": true,
- "requires": {
- "throttleit": "^1.0.0"
- }
- },
- "request-promise-core": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
- "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.19"
- }
- },
- "request-promise-native": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
- "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
- "dev": true,
- "requires": {
- "request-promise-core": "1.1.4",
- "stealthy-require": "^1.1.1",
- "tough-cookie": "^2.3.3"
- }
- },
- "require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
- },
- "require-from-string": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
- "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
- },
- "require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
- },
- "requires-port": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
- "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
- },
- "reselect": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
- "integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
- },
- "resolve": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
- "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
- "requires": {
- "is-core-module": "^2.2.0",
- "path-parse": "^1.0.6"
- }
- },
- "resolve-cwd": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
- "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
- "requires": {
- "resolve-from": "^5.0.0"
- },
- "dependencies": {
- "resolve-from": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
- "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
- }
- }
- },
- "resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
- },
- "resolve-options": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
- "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
- "dev": true,
- "requires": {
- "value-or-function": "^3.0.0"
- }
- },
- "resolve-pathname": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz",
- "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
- },
- "resolve-url": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
- "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo="
- },
- "resolve-url-loader": {
- "version": "3.1.4",
- "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz",
- "integrity": "sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg==",
- "requires": {
- "adjust-sourcemap-loader": "3.0.0",
- "camelcase": "5.3.1",
- "compose-function": "3.0.3",
- "convert-source-map": "1.7.0",
- "es6-iterator": "2.0.3",
- "loader-utils": "1.2.3",
- "postcss": "7.0.36",
- "rework": "1.0.1",
- "rework-visit": "1.0.0",
- "source-map": "0.6.1"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "dependencies": {
- "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"
- }
- }
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "emojis-list": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
- "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
- "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^2.0.0",
- "json5": "^1.0.1"
- }
- },
- "postcss": {
- "version": "7.0.36",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz",
- "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==",
- "requires": {
- "chalk": "^2.4.2",
- "source-map": "^0.6.1",
- "supports-color": "^6.1.0"
- }
- },
- "supports-color": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
- "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "restore-cursor": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
- "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
- "dev": true,
- "requires": {
- "onetime": "^5.1.0",
- "signal-exit": "^3.0.2"
- }
- },
- "ret": {
- "version": "0.1.15",
- "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
- "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
- },
- "retry": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
- "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
- },
- "reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
- },
- "rework": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz",
- "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=",
- "requires": {
- "convert-source-map": "^0.3.3",
- "css": "^2.0.0"
- },
- "dependencies": {
- "convert-source-map": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
- "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA="
- },
- "css": {
- "version": "2.2.4",
- "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
- "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
- "requires": {
- "inherits": "^2.0.3",
- "source-map": "^0.6.1",
- "source-map-resolve": "^0.5.2",
- "urix": "^0.1.0"
- }
- },
- "source-map-resolve": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
- "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
- "requires": {
- "atob": "^2.1.2",
- "decode-uri-component": "^0.2.0",
- "resolve-url": "^0.2.1",
- "source-map-url": "^0.4.0",
- "urix": "^0.1.0"
- }
- }
- }
- },
- "rework-visit": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz",
- "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo="
- },
- "rgb-regex": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
- "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE="
- },
- "rgba-regex": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
- "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM="
- },
- "rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "ripemd160": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
- "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
- "requires": {
- "hash-base": "^3.0.0",
- "inherits": "^2.0.1"
- }
- },
- "rollup": {
- "version": "1.32.1",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz",
- "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==",
- "requires": {
- "@types/estree": "*",
- "@types/node": "*",
- "acorn": "^7.1.0"
- }
- },
- "rollup-plugin-babel": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz",
- "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==",
- "requires": {
- "@babel/helper-module-imports": "^7.0.0",
- "rollup-pluginutils": "^2.8.1"
- }
- },
- "rollup-plugin-terser": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.1.tgz",
- "integrity": "sha512-1pkwkervMJQGFYvM9nscrUoncPwiKR/K+bHdjv6PFgRo3cgPHoRT83y2Aa3GvINj4539S15t/tpFPb775TDs6w==",
- "requires": {
- "@babel/code-frame": "^7.5.5",
- "jest-worker": "^24.9.0",
- "rollup-pluginutils": "^2.8.2",
- "serialize-javascript": "^4.0.0",
- "terser": "^4.6.2"
- },
- "dependencies": {
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "jest-worker": {
- "version": "24.9.0",
- "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
- "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
- "requires": {
- "merge-stream": "^2.0.0",
- "supports-color": "^6.1.0"
- }
- },
- "serialize-javascript": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
- "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
- "supports-color": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
- "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
- }
- },
- "rollup-pluginutils": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
- "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
- "requires": {
- "estree-walker": "^0.6.1"
- },
- "dependencies": {
- "estree-walker": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
- "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="
- }
- }
- },
- "rsvp": {
- "version": "4.8.5",
- "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
- "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA=="
- },
- "run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "requires": {
- "queue-microtask": "^1.2.2"
- }
- },
- "run-queue": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
- "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
- "requires": {
- "aproba": "^1.1.1"
- }
- },
- "rxjs": {
- "version": "6.6.3",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
- "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
- "dev": true,
- "requires": {
- "tslib": "^1.9.0"
- }
- },
- "safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
- },
- "safe-regex": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
- "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
- "requires": {
- "ret": "~0.1.10"
- }
- },
- "safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "sane": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz",
- "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==",
- "requires": {
- "@cnakazawa/watch": "^1.0.3",
- "anymatch": "^2.0.0",
- "capture-exit": "^2.0.0",
- "exec-sh": "^0.3.2",
- "execa": "^1.0.0",
- "fb-watchman": "^2.0.0",
- "micromatch": "^3.1.4",
- "minimist": "^1.1.1",
- "walker": "~1.0.5"
- },
- "dependencies": {
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- }
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
- "sanitize.css": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-10.0.0.tgz",
- "integrity": "sha512-vTxrZz4dX5W86M6oVWVdOVe72ZiPs41Oi7Z6Km4W5Turyz28mrXSJhhEBZoRtzJWIv3833WKVwLSDWWkEfupMg=="
- },
- "sass-graph": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz",
- "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==",
- "requires": {
- "glob": "^7.0.0",
- "lodash": "^4.0.0",
- "scss-tokenizer": "^0.2.3",
- "yargs": "^13.3.2"
- }
- },
- "sass-loader": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.2.0.tgz",
- "integrity": "sha512-kUceLzC1gIHz0zNJPpqRsJyisWatGYNFRmv2CKZK2/ngMJgLqxTbXwe/hJ85luyvZkgqU3VlJ33UVF2T/0g6mw==",
- "requires": {
- "klona": "^2.0.4",
- "loader-utils": "^2.0.0",
- "neo-async": "^2.6.2",
- "schema-utils": "^3.0.0",
- "semver": "^7.3.2"
- },
- "dependencies": {
- "@types/json-schema": {
- "version": "7.0.9",
- "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
- "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
- },
- "schema-utils": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
- "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
- "requires": {
- "@types/json-schema": "^7.0.8",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- },
- "semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
- "requires": {
- "lru-cache": "^6.0.0"
- }
- }
- }
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
- },
- "saxes": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
- "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
- "requires": {
- "xmlchars": "^2.2.0"
- }
- },
- "scheduler": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
- "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
- "requires": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
- "schema-utils": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
- "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
- "requires": {
- "@types/json-schema": "^7.0.5",
- "ajv": "^6.12.4",
- "ajv-keywords": "^3.5.2"
- }
- },
- "scroll": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/scroll/-/scroll-3.0.1.tgz",
- "integrity": "sha512-pz7y517OVls1maEzlirKO5nPYle9AXsFzTMNJrRGmT951mzpIBy7sNHOg5o/0MQd/NqliCiWnAi0kZneMPFLcg=="
- },
- "scrollparent": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/scrollparent/-/scrollparent-2.0.1.tgz",
- "integrity": "sha1-cV1bnMV3YPsivczDvvtb/gaxoxc="
- },
- "scss-tokenizer": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
- "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
- "requires": {
- "js-base64": "^2.1.8",
- "source-map": "^0.4.2"
- },
- "dependencies": {
- "source-map": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
- "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
- "requires": {
- "amdefine": ">=0.0.4"
- }
- }
- }
- },
- "select-hose": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
- "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
- },
- "selfsigned": {
- "version": "1.10.11",
- "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz",
- "integrity": "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==",
- "requires": {
- "node-forge": "^0.10.0"
- }
- },
- "semver": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
- "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
- },
- "semver-compare": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
- "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
- "dev": true
- },
- "send": {
- "version": "0.17.1",
- "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
- "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
- "requires": {
- "debug": "2.6.9",
- "depd": "~1.1.2",
- "destroy": "~1.0.4",
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "http-errors": "~1.7.2",
- "mime": "1.6.0",
- "ms": "2.1.1",
- "on-finished": "~2.3.0",
- "range-parser": "~1.2.1",
- "statuses": "~1.5.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- },
- "dependencies": {
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- }
- }
- },
- "ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
- }
- }
- },
- "serialize-javascript": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz",
- "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==",
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
- "serve-favicon": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
- "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=",
- "dev": true,
- "requires": {
- "etag": "~1.8.1",
- "fresh": "0.5.2",
- "ms": "2.1.1",
- "parseurl": "~1.3.2",
- "safe-buffer": "5.1.1"
- },
- "dependencies": {
- "ms": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
- "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
- "dev": true
- },
- "safe-buffer": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
- "dev": true
- }
- }
- },
- "serve-index": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
- "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
- "requires": {
- "accepts": "~1.3.4",
- "batch": "0.6.1",
- "debug": "2.6.9",
- "escape-html": "~1.0.3",
- "http-errors": "~1.6.2",
- "mime-types": "~2.1.17",
- "parseurl": "~1.3.2"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "http-errors": {
- "version": "1.6.3",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
- "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
- "requires": {
- "depd": "~1.1.2",
- "inherits": "2.0.3",
- "setprototypeof": "1.1.0",
- "statuses": ">= 1.4.0 < 2"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "setprototypeof": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
- "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
- }
- }
- },
- "serve-static": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
- "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
- "requires": {
- "encodeurl": "~1.0.2",
- "escape-html": "~1.0.3",
- "parseurl": "~1.3.3",
- "send": "0.17.1"
- }
- },
- "set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
- },
- "setimmediate": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
- "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
- },
- "setprototypeof": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
- "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
- },
- "sha.js": {
- "version": "2.4.11",
- "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
- "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
- "requires": {
- "inherits": "^2.0.1",
- "safe-buffer": "^5.0.1"
- }
- },
- "shallow-clone": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
- "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
- "dev": true,
- "requires": {
- "kind-of": "^6.0.2"
- }
- },
- "shallow-compare": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/shallow-compare/-/shallow-compare-1.2.2.tgz",
- "integrity": "sha512-LUMFi+RppPlrHzbqmFnINTrazo0lPNwhcgzuAXVVcfy/mqPDrQmHAyz5bvV0gDAuRFrk804V0HpQ6u9sZ0tBeg=="
- },
- "shallow-equal": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-1.2.1.tgz",
- "integrity": "sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA=="
- },
- "shallowequal": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
- "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==",
- "dev": true
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
- },
- "shell-quote": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz",
- "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg=="
- },
- "shellwords": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
- "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
- "optional": true
- },
- "side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "requires": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- }
- },
- "signal-exit": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
- "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
- },
- "simple-swizzle": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
- "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
- "requires": {
- "is-arrayish": "^0.3.1"
- },
- "dependencies": {
- "is-arrayish": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
- "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
- }
- }
- },
- "sisteransi": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
- "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
- },
- "slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
- },
- "slice-ansi": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
- "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "dependencies": {
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- }
- }
- },
- "snapdragon": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
- "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
- "requires": {
- "base": "^0.11.1",
- "debug": "^2.2.0",
- "define-property": "^0.2.5",
- "extend-shallow": "^2.0.1",
- "map-cache": "^0.2.2",
- "source-map": "^0.5.6",
- "source-map-resolve": "^0.5.0",
- "use": "^3.1.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- },
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
- },
- "source-map-resolve": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
- "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
- "requires": {
- "atob": "^2.1.2",
- "decode-uri-component": "^0.2.0",
- "resolve-url": "^0.2.1",
- "source-map-url": "^0.4.0",
- "urix": "^0.1.0"
- }
- }
- }
- },
- "snapdragon-node": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
- "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
- "requires": {
- "define-property": "^1.0.0",
- "isobject": "^3.0.0",
- "snapdragon-util": "^3.0.1"
- },
- "dependencies": {
- "define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
- "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
- "requires": {
- "is-descriptor": "^1.0.0"
- }
- },
- "is-accessor-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
- "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-data-descriptor": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
- "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
- "requires": {
- "kind-of": "^6.0.0"
- }
- },
- "is-descriptor": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
- "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
- "requires": {
- "is-accessor-descriptor": "^1.0.0",
- "is-data-descriptor": "^1.0.0",
- "kind-of": "^6.0.2"
- }
- }
- }
- },
- "snapdragon-util": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
- "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
- "requires": {
- "kind-of": "^3.2.0"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "sockjs": {
- "version": "0.3.21",
- "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz",
- "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==",
- "requires": {
- "faye-websocket": "^0.11.3",
- "uuid": "^3.4.0",
- "websocket-driver": "^0.7.4"
- },
- "dependencies": {
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
- }
- },
- "sockjs-client": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz",
- "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==",
- "requires": {
- "debug": "^3.2.6",
- "eventsource": "^1.0.7",
- "faye-websocket": "^0.11.3",
- "inherits": "^2.0.4",
- "json3": "^3.3.3",
- "url-parse": "^1.5.3"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "sort-keys": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
- "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
- "requires": {
- "is-plain-obj": "^1.0.0"
- },
- "dependencies": {
- "is-plain-obj": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
- "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
- }
- }
- },
- "source-list-map": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
- "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
- },
- "source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
- },
- "source-map-js": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz",
- "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug=="
- },
- "source-map-resolve": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
- "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
- "requires": {
- "atob": "^2.1.2",
- "decode-uri-component": "^0.2.0"
- }
- },
- "source-map-support": {
- "version": "0.5.19",
- "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
- "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
- "requires": {
- "buffer-from": "^1.0.0",
- "source-map": "^0.6.0"
- }
- },
- "source-map-url": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz",
- "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
- },
- "sourcemap-codec": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
- "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
- },
- "space-separated-tokens": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
- "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
- "dev": true
- },
- "spdx-correct": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
- "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
- "requires": {
- "spdx-expression-parse": "^3.0.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-exceptions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
- "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
- },
- "spdx-expression-parse": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
- "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
- "requires": {
- "spdx-exceptions": "^2.1.0",
- "spdx-license-ids": "^3.0.0"
- }
- },
- "spdx-license-ids": {
- "version": "3.0.7",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz",
- "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ=="
- },
- "spdy": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
- "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
- "requires": {
- "debug": "^4.1.0",
- "handle-thing": "^2.0.0",
- "http-deceiver": "^1.2.7",
- "select-hose": "^2.0.0",
- "spdy-transport": "^3.0.0"
- }
- },
- "spdy-transport": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
- "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
- "requires": {
- "debug": "^4.1.0",
- "detect-node": "^2.0.4",
- "hpack.js": "^2.1.6",
- "obuf": "^1.1.2",
- "readable-stream": "^3.0.6",
- "wbuf": "^1.7.3"
- },
- "dependencies": {
- "readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
- "requires": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- }
- }
- }
- },
- "split-string": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
- "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
- "requires": {
- "extend-shallow": "^3.0.0"
- }
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
- },
- "sshpk": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
- "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
- "requires": {
- "asn1": "~0.2.3",
- "assert-plus": "^1.0.0",
- "bcrypt-pbkdf": "^1.0.0",
- "dashdash": "^1.12.0",
- "ecc-jsbn": "~0.1.1",
- "getpass": "^0.1.1",
- "jsbn": "~0.1.0",
- "safer-buffer": "^2.0.2",
- "tweetnacl": "~0.14.0"
- }
- },
- "stable": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
- "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
- },
- "stack-utils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz",
- "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==",
- "requires": {
- "escape-string-regexp": "^2.0.0"
- },
- "dependencies": {
- "escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
- }
- }
- },
- "stackframe": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.2.0.tgz",
- "integrity": "sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA=="
- },
- "state-toggle": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
- "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
- "dev": true
- },
- "static-extend": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
- "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
- "requires": {
- "define-property": "^0.2.5",
- "object-copy": "^0.1.0"
- },
- "dependencies": {
- "define-property": {
- "version": "0.2.5",
- "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
- "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
- "requires": {
- "is-descriptor": "^0.1.0"
- }
- }
- }
- },
- "statuses": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
- "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
- },
- "stdout-stream": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
- "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
- "requires": {
- "readable-stream": "^2.0.1"
- }
- },
- "stealthy-require": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
- "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
- "dev": true
- },
- "store2": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/store2/-/store2-2.13.1.tgz",
- "integrity": "sha512-iJtHSGmNgAUx0b/MCS6ASGxb//hGrHHRgzvN+K5bvkBTN7A9RTpPSf1WSp+nPGvWCJ1jRnvY7MKnuqfoi3OEqg==",
- "dev": true
- },
- "stream-browserify": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
- "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
- "requires": {
- "inherits": "~2.0.1",
- "readable-stream": "^2.0.2"
- }
- },
- "stream-each": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
- "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
- "requires": {
- "end-of-stream": "^1.1.0",
- "stream-shift": "^1.0.0"
- }
- },
- "stream-http": {
- "version": "2.8.3",
- "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
- "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
- "requires": {
- "builtin-status-codes": "^3.0.0",
- "inherits": "^2.0.1",
- "readable-stream": "^2.3.6",
- "to-arraybuffer": "^1.0.0",
- "xtend": "^4.0.0"
- }
- },
- "stream-shift": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
- "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
- },
- "strict-uri-encode": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
- "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
- },
- "string-argv": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
- "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
- "dev": true
- },
- "string-length": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
- "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
- "requires": {
- "char-regex": "^1.0.2",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "string-natural-compare": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz",
- "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw=="
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "string.prototype.matchall": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz",
- "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.18.0-next.2",
- "has-symbols": "^1.0.1",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.3.1",
- "side-channel": "^1.0.4"
- }
- },
- "string.prototype.padend": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz",
- "integrity": "sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "string.prototype.padstart": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/string.prototype.padstart/-/string.prototype.padstart-3.1.3.tgz",
- "integrity": "sha512-NZydyOMtYxpTjGqp0VN5PYUF/tsU15yDMZnUdj16qRUIUiMJkHHSDElYyQFrMu+/WloTpA7MQSiADhBicDfaoA==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.19.1",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz",
- "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.1.1",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-symbols": "^1.0.2",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.4",
- "is-negative-zero": "^2.0.1",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.1",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.1",
- "object-inspect": "^1.11.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.2",
- "string.prototype.trimend": "^1.0.4",
- "string.prototype.trimstart": "^1.0.4",
- "unbox-primitive": "^1.0.1"
- }
- },
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- },
- "is-callable": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
- "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
- "dev": true
- },
- "is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- }
- },
- "is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "requires": {
- "has-tostringtag": "^1.0.0"
- }
- },
- "object-inspect": {
- "version": "1.12.0",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz",
- "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==",
- "dev": true
- }
- }
- },
- "string.prototype.trimend": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz",
- "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "string.prototype.trimstart": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz",
- "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==",
- "requires": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3"
- }
- },
- "string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "requires": {
- "safe-buffer": "~5.1.0"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
- }
- }
- },
- "stringify-object": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
- "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
- "requires": {
- "get-own-enumerable-property-symbols": "^3.0.0",
- "is-obj": "^1.0.1",
- "is-regexp": "^1.0.0"
- },
- "dependencies": {
- "is-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
- "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
- }
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "requires": {
- "ansi-regex": "^2.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- },
- "strip-comments": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/strip-comments/-/strip-comments-1.0.2.tgz",
- "integrity": "sha512-kL97alc47hoyIQSV165tTt9rG5dn4w1dNnBhOQ3bOU1Nc1hel09jnXANaHJ7vzHLd4Ju8kseDGzlev96pghLFw==",
- "requires": {
- "babel-extract-comments": "^1.0.0",
- "babel-plugin-transform-object-rest-spread": "^6.26.0"
- }
- },
- "strip-eof": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
- "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
- },
- "strip-final-newline": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
- "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
- },
- "strip-indent": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
- "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
- "requires": {
- "min-indent": "^1.0.0"
- }
- },
- "strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
- },
- "style-loader": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz",
- "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==",
- "requires": {
- "loader-utils": "^2.0.0",
- "schema-utils": "^2.7.0"
- }
- },
- "style-to-object": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
- "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==",
- "dev": true,
- "requires": {
- "inline-style-parser": "0.1.1"
- }
- },
- "style-value-types": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-4.1.1.tgz",
- "integrity": "sha512-cNLrl6jk+I1T18ZI2KIp/fcqKVuykcNELDrOz7y+TYZR97xmNdN0ewupURvVFnQxVrRJv98TMBq92VMsggq3kw==",
- "requires": {
- "hey-listen": "^1.0.8",
- "tslib": "^1.10.0"
- }
- },
- "stylehacks": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
- "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==",
- "requires": {
- "browserslist": "^4.0.0",
- "postcss": "^7.0.0",
- "postcss-selector-parser": "^3.0.0"
- },
- "dependencies": {
- "browserslist": {
- "version": "4.17.5",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.5.tgz",
- "integrity": "sha512-I3ekeB92mmpctWBoLXe0d5wPS2cBuRvvW0JyyJHMrk9/HmP2ZjrTboNAZ8iuGqaEIlKguljbQY32OkOJIRrgoA==",
- "requires": {
- "caniuse-lite": "^1.0.30001271",
- "electron-to-chromium": "^1.3.878",
- "escalade": "^3.1.1",
- "node-releases": "^2.0.1",
- "picocolors": "^1.0.0"
- }
- },
- "caniuse-lite": {
- "version": "1.0.30001271",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz",
- "integrity": "sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA=="
- },
- "electron-to-chromium": {
- "version": "1.3.880",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.880.tgz",
- "integrity": "sha512-iwIP/6WoeSimzUKJIQtjtpVDsK8Ir8qQCMXsUBwg+rxJR2Uh3wTNSbxoYRfs+3UWx/9MAnPIxVZCyWkm8MT0uw=="
- },
- "node-releases": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
- "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
- },
- "postcss-selector-parser": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
- "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
- "requires": {
- "dot-prop": "^5.2.0",
- "indexes-of": "^1.0.1",
- "uniq": "^1.0.1"
- }
- }
- }
- },
- "stylis": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.7.tgz",
- "integrity": "sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA=="
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "requires": {
- "has-flag": "^4.0.0"
- }
- },
- "supports-hyperlinks": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz",
- "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==",
- "requires": {
- "has-flag": "^4.0.0",
- "supports-color": "^7.0.0"
- }
- },
- "svg-parser": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz",
- "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="
- },
- "svgo": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
- "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
- "requires": {
- "chalk": "^2.4.1",
- "coa": "^2.0.2",
- "css-select": "^2.0.0",
- "css-select-base-adapter": "^0.1.1",
- "css-tree": "1.0.0-alpha.37",
- "csso": "^4.0.2",
- "js-yaml": "^3.13.1",
- "mkdirp": "~0.5.1",
- "object.values": "^1.1.0",
- "sax": "~1.2.4",
- "stable": "^0.1.8",
- "unquote": "~1.1.1",
- "util.promisify": "~1.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "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"
- }
- }
- }
- },
- "symbol-observable": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
- "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ=="
- },
- "symbol-tree": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
- "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
- },
- "symbol.prototype.description": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/symbol.prototype.description/-/symbol.prototype.description-1.0.5.tgz",
- "integrity": "sha512-x738iXRYsrAt9WBhRCVG5BtIC3B7CUkFwbHW2zOvGtwM33s7JjrCDyq8V0zgMYVb5ymsL8+qkzzpANH63CPQaQ==",
- "dev": true,
- "requires": {
- "call-bind": "^1.0.2",
- "get-symbol-description": "^1.0.0",
- "has-symbols": "^1.0.2",
- "object.getownpropertydescriptors": "^2.1.2"
- },
- "dependencies": {
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==",
- "dev": true
- }
- }
- },
- "symlink-or-copy": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz",
- "integrity": "sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==",
- "dev": true
- },
- "synchronous-promise": {
- "version": "2.0.15",
- "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.15.tgz",
- "integrity": "sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==",
- "dev": true
- },
- "table": {
- "version": "6.0.7",
- "resolved": "https://registry.npmjs.org/table/-/table-6.0.7.tgz",
- "integrity": "sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g==",
- "requires": {
- "ajv": "^7.0.2",
- "lodash": "^4.17.20",
- "slice-ansi": "^4.0.0",
- "string-width": "^4.2.0"
- },
- "dependencies": {
- "ajv": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.1.tgz",
- "integrity": "sha512-ga/aqDYnUy/o7vbsRTFhhTsNeXiYb5JWDIcRIeZfwRNCefwjNTVYCGdGSUrEmiu3yDK3vFvNbgJxvrQW4JXrYQ==",
- "requires": {
- "fast-deep-equal": "^3.1.1",
- "json-schema-traverse": "^1.0.0",
- "require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
- }
- },
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
- },
- "json-schema-traverse": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
- "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
- },
- "string-width": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
- "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.0"
- }
- },
- "strip-ansi": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
- "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
- "requires": {
- "ansi-regex": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "tapable": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
- "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
- },
- "tar": {
- "version": "6.1.11",
- "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
- "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
- "requires": {
- "chownr": "^2.0.0",
- "fs-minipass": "^2.0.0",
- "minipass": "^3.0.0",
- "minizlib": "^2.1.1",
- "mkdirp": "^1.0.3",
- "yallist": "^4.0.0"
- },
- "dependencies": {
- "mkdirp": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
- "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
- }
- }
- },
- "telejson": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/telejson/-/telejson-5.3.3.tgz",
- "integrity": "sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==",
- "dev": true,
- "requires": {
- "@types/is-function": "^1.0.0",
- "global": "^4.4.0",
- "is-function": "^1.0.2",
- "is-regex": "^1.1.2",
- "is-symbol": "^1.0.3",
- "isobject": "^4.0.0",
- "lodash": "^4.17.21",
- "memoizerific": "^1.11.3"
- },
- "dependencies": {
- "isobject": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz",
- "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==",
- "dev": true
- }
- }
- },
- "temp-dir": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz",
- "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0="
- },
- "tempy": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/tempy/-/tempy-0.3.0.tgz",
- "integrity": "sha512-WrH/pui8YCwmeiAoxV+lpRH9HpRtgBhSR2ViBPgpGb/wnYDzp21R4MN45fsCGvLROvY67o3byhJRYRONJyImVQ==",
- "requires": {
- "temp-dir": "^1.0.0",
- "type-fest": "^0.3.1",
- "unique-string": "^1.0.0"
- },
- "dependencies": {
- "type-fest": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz",
- "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ=="
- }
- }
- },
- "terminal-link": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz",
- "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==",
- "requires": {
- "ansi-escapes": "^4.2.1",
- "supports-hyperlinks": "^2.0.0"
- }
- },
- "terser": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
- "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
- "requires": {
- "commander": "^2.20.0",
- "source-map": "~0.6.1",
- "source-map-support": "~0.5.12"
- },
- "dependencies": {
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
- }
- }
- },
- "terser-webpack-plugin": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz",
- "integrity": "sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==",
- "requires": {
- "cacache": "^15.0.5",
- "find-cache-dir": "^3.3.1",
- "jest-worker": "^26.5.0",
- "p-limit": "^3.0.2",
- "schema-utils": "^3.0.0",
- "serialize-javascript": "^5.0.1",
- "source-map": "^0.6.1",
- "terser": "^5.3.4",
- "webpack-sources": "^1.4.3"
- },
- "dependencies": {
- "commander": {
- "version": "2.20.3",
- "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
- "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
- },
- "find-cache-dir": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
- "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
- "requires": {
- "commondir": "^1.0.1",
- "make-dir": "^3.0.2",
- "pkg-dir": "^4.1.0"
- }
- },
- "find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "requires": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- }
- },
- "locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "requires": {
- "p-locate": "^4.1.0"
- }
- },
- "make-dir": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
- "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
- "requires": {
- "semver": "^6.0.0"
- }
- },
- "p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "requires": {
- "yocto-queue": "^0.1.0"
- }
- },
- "p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "requires": {
- "p-limit": "^2.2.0"
- },
- "dependencies": {
- "p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "requires": {
- "p-try": "^2.0.0"
- }
- }
- }
- },
- "path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
- },
- "pkg-dir": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
- "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
- "requires": {
- "find-up": "^4.0.0"
- }
- },
- "schema-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
- "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
- "requires": {
- "@types/json-schema": "^7.0.6",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- },
- "terser": {
- "version": "5.7.0",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz",
- "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==",
- "requires": {
- "commander": "^2.20.0",
- "source-map": "~0.7.2",
- "source-map-support": "~0.5.19"
- },
- "dependencies": {
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- }
- }
- }
- }
- },
- "test-exclude": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
- "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
- "requires": {
- "@istanbuljs/schema": "^0.1.2",
- "glob": "^7.1.4",
- "minimatch": "^3.0.4"
- }
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
- },
- "throat": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
- "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="
- },
- "throttle-debounce": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz",
- "integrity": "sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==",
- "dev": true
- },
- "throttleit": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz",
- "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=",
- "dev": true
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
- "dev": true
- },
- "through2": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
- "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
- "requires": {
- "readable-stream": "~2.3.6",
- "xtend": "~4.0.1"
- }
- },
- "through2-filter": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
- "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
- "dev": true,
- "requires": {
- "through2": "~2.0.0",
- "xtend": "~4.0.0"
- }
- },
- "thunky": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
- "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
- },
- "timers-browserify": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
- "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
- "requires": {
- "setimmediate": "^1.0.4"
- }
- },
- "timsort": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
- "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
- },
- "tiny-invariant": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz",
- "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw=="
- },
- "tiny-warning": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
- "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
- },
- "tmp": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
- "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
- "dev": true,
- "requires": {
- "rimraf": "^3.0.0"
- }
- },
- "tmpl": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
- "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="
- },
- "to-absolute-glob": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
- "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
- "dev": true,
- "requires": {
- "is-absolute": "^1.0.0",
- "is-negated-glob": "^1.0.0"
- }
- },
- "to-arraybuffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
- "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
- },
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
- },
- "to-object-path": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
- "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "to-regex": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
- "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
- "requires": {
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "regex-not": "^1.0.2",
- "safe-regex": "^1.1.0"
- }
- },
- "to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "requires": {
- "is-number": "^7.0.0"
- }
- },
- "to-through": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
- "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
- "dev": true,
- "requires": {
- "through2": "^2.0.3"
- }
- },
- "toggle-selection": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
- "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=",
- "dev": true
- },
- "toidentifier": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
- "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
- },
- "tough-cookie": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
- "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
- "requires": {
- "psl": "^1.1.28",
- "punycode": "^2.1.1"
- }
- },
- "tr46": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz",
- "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==",
- "requires": {
- "punycode": "^2.1.1"
- }
- },
- "tree-changes": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/tree-changes/-/tree-changes-0.5.1.tgz",
- "integrity": "sha512-O873xzV2xRZ6N059Mn06QzmGKEE21LlvIPbsk2G+GS9ZX5OCur6PIwuuh0rWpAPvLWQZPj0XObyG27zZyLHUzw==",
- "requires": {
- "deep-diff": "^1.0.2",
- "nested-property": "1.0.1"
- }
- },
- "trim-newlines": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
- "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw=="
- },
- "trim-trailing-lines": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz",
- "integrity": "sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==",
- "dev": true
- },
- "trough": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
- "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA=="
- },
- "true-case-path": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
- "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
- "requires": {
- "glob": "^7.1.2"
- }
- },
- "tryer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
- "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA=="
- },
- "ts-dedent": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz",
- "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
- "dev": true
- },
- "ts-pnp": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
- "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw=="
- },
- "tsconfig-paths": {
- "version": "3.11.0",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz",
- "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==",
- "requires": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.1",
- "minimist": "^1.2.0",
- "strip-bom": "^3.0.0"
- },
- "dependencies": {
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
- }
- }
- },
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "requires": {
- "tslib": "^1.8.1"
- }
- },
- "tty-browserify": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
- "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
- },
- "type": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
- "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
- },
- "type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "requires": {
- "prelude-ls": "^1.2.1"
- }
- },
- "type-detect": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
- "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
- },
- "type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
- },
- "type-is": {
- "version": "1.6.18",
- "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
- "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
- "requires": {
- "media-typer": "0.3.0",
- "mime-types": "~2.1.24"
- }
- },
- "typedarray": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
- "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
- },
- "typedarray-to-buffer": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
- "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
- "requires": {
- "is-typedarray": "^1.0.0"
- }
- },
- "typescript": {
- "version": "3.9.9",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.9.tgz",
- "integrity": "sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w==",
- "dev": true
- },
- "typescript-compare": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
- "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
- "requires": {
- "typescript-logic": "^0.0.0"
- }
- },
- "typescript-logic": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
- "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
- },
- "typescript-tuple": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
- "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
- "requires": {
- "typescript-compare": "^0.0.2"
- }
- },
- "uglify-js": {
- "version": "3.14.5",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz",
- "integrity": "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ==",
- "dev": true,
- "optional": true
- },
- "unbox-primitive": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
- "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==",
- "requires": {
- "function-bind": "^1.1.1",
- "has-bigints": "^1.0.1",
- "has-symbols": "^1.0.2",
- "which-boxed-primitive": "^1.0.2"
- },
- "dependencies": {
- "has-symbols": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
- "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
- }
- }
- },
- "unc-path-regex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
- "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
- "dev": true
- },
- "uncontrollable": {
- "version": "7.2.1",
- "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
- "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
- "requires": {
- "@babel/runtime": "^7.6.3",
- "@types/react": ">=16.9.11",
- "invariant": "^2.2.4",
- "react-lifecycles-compat": "^3.0.4"
- }
- },
- "underscore.string": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz",
- "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==",
- "dev": true,
- "requires": {
- "sprintf-js": "^1.0.3",
- "util-deprecate": "^1.0.2"
- }
- },
- "unfetch": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz",
- "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==",
- "dev": true
- },
- "unherit": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
- "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
- "dev": true,
- "requires": {
- "inherits": "^2.0.0",
- "xtend": "^4.0.0"
- }
- },
- "unicode-canonical-property-names-ecmascript": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
- "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ=="
- },
- "unicode-match-property-ecmascript": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
- "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
- "requires": {
- "unicode-canonical-property-names-ecmascript": "^1.0.4",
- "unicode-property-aliases-ecmascript": "^1.0.4"
- }
- },
- "unicode-match-property-value-ecmascript": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
- "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ=="
- },
- "unicode-property-aliases-ecmascript": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
- "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg=="
- },
- "unified": {
- "version": "9.2.0",
- "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
- "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
- "requires": {
- "bail": "^1.0.0",
- "extend": "^3.0.0",
- "is-buffer": "^2.0.0",
- "is-plain-obj": "^2.0.0",
- "trough": "^1.0.0",
- "vfile": "^4.0.0"
- }
- },
- "union-value": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
- "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
- "requires": {
- "arr-union": "^3.1.0",
- "get-value": "^2.0.6",
- "is-extendable": "^0.1.1",
- "set-value": "^2.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- },
- "set-value": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz",
- "integrity": "sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==",
- "requires": {
- "is-plain-object": "^2.0.4",
- "is-primitive": "^3.0.1"
- }
- }
- }
- },
- "uniq": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
- "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8="
- },
- "uniqs": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
- "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI="
- },
- "unique-filename": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
- "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
- "requires": {
- "unique-slug": "^2.0.0"
- }
- },
- "unique-slug": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
- "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
- "requires": {
- "imurmurhash": "^0.1.4"
- }
- },
- "unique-stream": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
- "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
- "dev": true,
- "requires": {
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "through2-filter": "^3.0.0"
- }
- },
- "unique-string": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
- "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
- "requires": {
- "crypto-random-string": "^1.0.0"
- }
- },
- "unist-builder": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz",
- "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==",
- "dev": true
- },
- "unist-util-generated": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.6.tgz",
- "integrity": "sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==",
- "dev": true
- },
- "unist-util-is": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.4.tgz",
- "integrity": "sha512-3dF39j/u423v4BBQrk1AQ2Ve1FxY5W3JKwXxVFzBODQ6WEvccguhgp802qQLKSnxPODE6WuRZtV+ohlUg4meBA=="
- },
- "unist-util-position": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz",
- "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==",
- "dev": true
- },
- "unist-util-remove": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-2.1.0.tgz",
- "integrity": "sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==",
- "dev": true,
- "requires": {
- "unist-util-is": "^4.0.0"
- }
- },
- "unist-util-remove-position": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
- "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
- "dev": true,
- "requires": {
- "unist-util-visit": "^2.0.0"
- }
- },
- "unist-util-stringify-position": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
- "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
- "requires": {
- "@types/unist": "^2.0.2"
- }
- },
- "unist-util-visit": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
- "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
- "requires": {
- "@types/unist": "^2.0.0",
- "unist-util-is": "^4.0.0",
- "unist-util-visit-parents": "^3.0.0"
- },
- "dependencies": {
- "unist-util-visit-parents": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
- "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
- "requires": {
- "@types/unist": "^2.0.0",
- "unist-util-is": "^4.0.0"
- }
- }
- }
- },
- "unist-util-visit-parents": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz",
- "integrity": "sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q=="
- },
- "universalify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
- "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
- },
- "unquote": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
- "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ="
- },
- "unset-value": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
- "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
- "requires": {
- "has-value": "^0.3.1",
- "isobject": "^3.0.0"
- },
- "dependencies": {
- "has-value": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
- "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
- "requires": {
- "get-value": "^2.0.3",
- "has-values": "^0.1.4",
- "isobject": "^2.0.0"
- },
- "dependencies": {
- "isobject": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
- "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "requires": {
- "isarray": "1.0.0"
- }
- }
- }
- },
- "has-values": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
- "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E="
- }
- }
- },
- "untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true
- },
- "upath": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
- "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
- },
- "uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "requires": {
- "punycode": "^2.1.0"
- }
- },
- "urix": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
- "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI="
- },
- "url": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
- "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
- "requires": {
- "punycode": "1.3.2",
- "querystring": "0.2.0"
- },
- "dependencies": {
- "punycode": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
- "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
- },
- "querystring": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
- "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
- }
- }
- },
- "url-loader": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz",
- "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==",
- "requires": {
- "loader-utils": "^2.0.0",
- "mime-types": "^2.1.27",
- "schema-utils": "^3.0.0"
- },
- "dependencies": {
- "schema-utils": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz",
- "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==",
- "requires": {
- "@types/json-schema": "^7.0.6",
- "ajv": "^6.12.5",
- "ajv-keywords": "^3.5.2"
- }
- }
- }
- },
- "url-parse": {
- "version": "1.5.3",
- "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz",
- "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==",
- "requires": {
- "querystringify": "^2.1.1",
- "requires-port": "^1.0.0"
- }
- },
- "use": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
- "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
- },
- "use-composed-ref": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.2.1.tgz",
- "integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==",
- "dev": true
- },
- "use-isomorphic-layout-effect": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz",
- "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==",
- "dev": true
- },
- "use-latest": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz",
- "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==",
- "dev": true,
- "requires": {
- "use-isomorphic-layout-effect": "^1.0.0"
- }
- },
- "util": {
- "version": "0.11.1",
- "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
- "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
- "requires": {
- "inherits": "2.0.3"
- },
- "dependencies": {
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
- }
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
- },
- "util.promisify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
- "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==",
- "requires": {
- "define-properties": "^1.1.3",
- "es-abstract": "^1.17.2",
- "has-symbols": "^1.0.1",
- "object.getownpropertydescriptors": "^2.1.0"
- },
- "dependencies": {
- "es-abstract": {
- "version": "1.17.7",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
- "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
- "requires": {
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.1",
- "is-callable": "^1.2.2",
- "is-regex": "^1.1.1",
- "object-inspect": "^1.8.0",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.1",
- "string.prototype.trimend": "^1.0.1",
- "string.prototype.trimstart": "^1.0.1"
- }
- }
- }
- },
- "utila": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
- "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw="
- },
- "utils-merge": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
- "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
- },
- "uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
- },
- "uuid-browser": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/uuid-browser/-/uuid-browser-3.1.0.tgz",
- "integrity": "sha1-DwWkCu90+eWVHiDvv0SxGHHlZBA=",
- "dev": true
- },
- "v8-compile-cache": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz",
- "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q=="
- },
- "v8-to-istanbul": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
- "integrity": "sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow==",
- "requires": {
- "@types/istanbul-lib-coverage": "^2.0.1",
- "convert-source-map": "^1.6.0",
- "source-map": "^0.7.3"
- },
- "dependencies": {
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- }
- }
- },
- "validate-npm-package-license": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
- "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
- "requires": {
- "spdx-correct": "^3.0.0",
- "spdx-expression-parse": "^3.0.0"
- }
- },
- "value-equal": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz",
- "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
- },
- "value-or-function": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
- "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
- "dev": true
- },
- "vary": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
- "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
- },
- "vendors": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
- "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w=="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "vfile": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz",
- "integrity": "sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==",
- "requires": {
- "@types/unist": "^2.0.0",
- "is-buffer": "^2.0.0",
- "unist-util-stringify-position": "^2.0.0",
- "vfile-message": "^2.0.0"
- }
- },
- "vfile-location": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.2.0.tgz",
- "integrity": "sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==",
- "dev": true
- },
- "vfile-message": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
- "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
- "requires": {
- "@types/unist": "^2.0.0",
- "unist-util-stringify-position": "^2.0.0"
- }
- },
- "vinyl": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.0.2.tgz",
- "integrity": "sha1-CjcT2NTpIhxY8QyhbAEWyeJe2nw=",
- "dev": true,
- "requires": {
- "clone": "^1.0.0",
- "clone-buffer": "^1.0.0",
- "clone-stats": "^1.0.0",
- "cloneable-readable": "^1.0.0",
- "is-stream": "^1.1.0",
- "remove-trailing-separator": "^1.0.1",
- "replace-ext": "^1.0.0"
- }
- },
- "vinyl-fs": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
- "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
- "dev": true,
- "requires": {
- "fs-mkdirp-stream": "^1.0.0",
- "glob-stream": "^6.1.0",
- "graceful-fs": "^4.0.0",
- "is-valid-glob": "^1.0.0",
- "lazystream": "^1.0.0",
- "lead": "^1.0.0",
- "object.assign": "^4.0.4",
- "pumpify": "^1.3.5",
- "readable-stream": "^2.3.3",
- "remove-bom-buffer": "^3.0.0",
- "remove-bom-stream": "^1.2.0",
- "resolve-options": "^1.1.0",
- "through2": "^2.0.0",
- "to-through": "^2.0.0",
- "value-or-function": "^3.0.0",
- "vinyl": "^2.0.0",
- "vinyl-sourcemap": "^1.1.0"
- }
- },
- "vinyl-sourcemap": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
- "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
- "dev": true,
- "requires": {
- "append-buffer": "^1.0.2",
- "convert-source-map": "^1.5.0",
- "graceful-fs": "^4.1.6",
- "normalize-path": "^2.1.1",
- "now-and-later": "^2.0.0",
- "remove-bom-buffer": "^3.0.0",
- "vinyl": "^2.0.0"
- },
- "dependencies": {
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "dev": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- }
- }
- },
- "vm-browserify": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
- "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
- },
- "void-elements": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
- "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
- },
- "vue-template-compiler": {
- "version": "2.6.12",
- "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz",
- "integrity": "sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==",
- "dev": true,
- "requires": {
- "de-indent": "^1.0.2",
- "he": "^1.1.0"
- }
- },
- "w3c-hr-time": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
- "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
- "requires": {
- "browser-process-hrtime": "^1.0.0"
- }
- },
- "w3c-xmlserializer": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
- "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
- "requires": {
- "xml-name-validator": "^3.0.0"
- }
- },
- "walker": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz",
- "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=",
- "requires": {
- "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.5",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
- "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
- "requires": {
- "chokidar": "^3.4.1",
- "graceful-fs": "^4.1.2",
- "neo-async": "^2.5.0",
- "watchpack-chokidar2": "^2.0.1"
- }
- },
- "watchpack-chokidar2": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
- "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
- "optional": true,
- "requires": {
- "chokidar": "^2.1.8"
- },
- "dependencies": {
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "optional": true,
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- },
- "dependencies": {
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "optional": true,
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- }
- }
- },
- "binary-extensions": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
- "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
- "optional": true
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "optional": true,
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "optional": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "chokidar": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
- "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
- "optional": true,
- "requires": {
- "anymatch": "^2.0.0",
- "async-each": "^1.0.1",
- "braces": "^2.3.2",
- "fsevents": "^1.2.7",
- "glob-parent": "^3.1.0",
- "inherits": "^2.0.3",
- "is-binary-path": "^1.0.0",
- "is-glob": "^4.0.0",
- "normalize-path": "^3.0.0",
- "path-is-absolute": "^1.0.0",
- "readdirp": "^2.2.1",
- "upath": "^1.1.1"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "optional": true,
- "requires": {
- "is-glob": "^4.0.3"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "optional": true,
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "optional": true,
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "optional": true,
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fsevents": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
- "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
- "optional": true,
- "requires": {
- "nan": "^2.12.1"
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "optional": true,
- "requires": {
- "binary-extensions": "^1.0.0"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "optional": true
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "optional": true,
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "optional": true,
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "optional": true,
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "readdirp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
- "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
- "optional": true,
- "requires": {
- "graceful-fs": "^4.1.11",
- "micromatch": "^3.1.10",
- "readable-stream": "^2.0.2"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "optional": true,
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- }
- }
- },
- "wbuf": {
- "version": "1.7.3",
- "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
- "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
- "requires": {
- "minimalistic-assert": "^1.0.0"
- }
- },
- "web-namespaces": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
- "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==",
- "dev": true
- },
- "web-vitals": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.0.tgz",
- "integrity": "sha512-1cx54eRxY/+M0KNKdNpNnuXAXG+vJEvwScV4DiV9rOYDguHoeDIzm09ghBohOPtkqPO5OtPC14FWkNva3SDisg=="
- },
- "webidl-conversions": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
- "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
- },
- "webpack": {
- "version": "4.44.2",
- "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz",
- "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==",
- "requires": {
- "@webassemblyjs/ast": "1.9.0",
- "@webassemblyjs/helper-module-context": "1.9.0",
- "@webassemblyjs/wasm-edit": "1.9.0",
- "@webassemblyjs/wasm-parser": "1.9.0",
- "acorn": "^6.4.1",
- "ajv": "^6.10.2",
- "ajv-keywords": "^3.4.1",
- "chrome-trace-event": "^1.0.2",
- "enhanced-resolve": "^4.3.0",
- "eslint-scope": "^4.0.3",
- "json-parse-better-errors": "^1.0.2",
- "loader-runner": "^2.4.0",
- "loader-utils": "^1.2.3",
- "memory-fs": "^0.4.1",
- "micromatch": "^3.1.10",
- "mkdirp": "^0.5.3",
- "neo-async": "^2.6.1",
- "node-libs-browser": "^2.2.1",
- "schema-utils": "^1.0.0",
- "tapable": "^1.1.3",
- "terser-webpack-plugin": "^1.4.3",
- "watchpack": "^1.7.4",
- "webpack-sources": "^1.4.1"
- },
- "dependencies": {
- "acorn": {
- "version": "6.4.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
- "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ=="
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "cacache": {
- "version": "12.0.4",
- "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
- "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
- "requires": {
- "bluebird": "^3.5.5",
- "chownr": "^1.1.1",
- "figgy-pudding": "^3.5.1",
- "glob": "^7.1.4",
- "graceful-fs": "^4.1.15",
- "infer-owner": "^1.0.3",
- "lru-cache": "^5.1.1",
- "mississippi": "^3.0.0",
- "mkdirp": "^0.5.1",
- "move-concurrently": "^1.0.1",
- "promise-inflight": "^1.0.1",
- "rimraf": "^2.6.3",
- "ssri": "^6.0.1",
- "unique-filename": "^1.1.1",
- "y18n": "^4.0.0"
- },
- "dependencies": {
- "ssri": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
- "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
- "requires": {
- "minipass": "^3.1.1"
- }
- }
- }
- },
- "chownr": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
- "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
- },
- "eslint-scope": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
- "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
- "requires": {
- "esrecurse": "^4.1.0",
- "estraverse": "^4.1.1"
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "is-wsl": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
- "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
- },
- "json5": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
- "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
- "requires": {
- "minimist": "^1.2.0"
- }
- },
- "loader-utils": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
- "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
- "requires": {
- "big.js": "^5.2.2",
- "emojis-list": "^3.0.0",
- "json5": "^1.0.1"
- }
- },
- "lru-cache": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
- "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
- "requires": {
- "yallist": "^3.0.2"
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "requires": {
- "glob": "^7.1.3"
- }
- },
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
- "requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
- }
- },
- "serialize-javascript": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
- "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
- "requires": {
- "randombytes": "^2.1.0"
- }
- },
- "ssri": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
- "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
- "requires": {
- "minipass": "^3.1.1"
- }
- },
- "terser-webpack-plugin": {
- "version": "1.4.5",
- "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
- "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
- "requires": {
- "cacache": "^12.0.2",
- "find-cache-dir": "^2.1.0",
- "is-wsl": "^1.1.0",
- "schema-utils": "^1.0.0",
- "serialize-javascript": "^4.0.0",
- "source-map": "^0.6.1",
- "terser": "^4.1.2",
- "webpack-sources": "^1.4.0",
- "worker-farm": "^1.7.0"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- },
- "yallist": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
- "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
- }
- }
- },
- "webpack-dev-middleware": {
- "version": "3.7.3",
- "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz",
- "integrity": "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==",
- "requires": {
- "memory-fs": "^0.4.1",
- "mime": "^2.4.4",
- "mkdirp": "^0.5.1",
- "range-parser": "^1.2.1",
- "webpack-log": "^2.0.0"
- },
- "dependencies": {
- "mime": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
- "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
- }
- }
- },
- "webpack-dev-server": {
- "version": "3.11.1",
- "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.1.tgz",
- "integrity": "sha512-u4R3mRzZkbxQVa+MBWi2uVpB5W59H3ekZAJsQlKUTdl7Elcah2EhygTPLmeFXybQkf9i2+L0kn7ik9SnXa6ihQ==",
- "requires": {
- "ansi-html": "0.0.7",
- "bonjour": "^3.5.0",
- "chokidar": "^2.1.8",
- "compression": "^1.7.4",
- "connect-history-api-fallback": "^1.6.0",
- "debug": "^4.1.1",
- "del": "^4.1.1",
- "express": "^4.17.1",
- "html-entities": "^1.3.1",
- "http-proxy-middleware": "0.19.1",
- "import-local": "^2.0.0",
- "internal-ip": "^4.3.0",
- "ip": "^1.1.5",
- "is-absolute-url": "^3.0.3",
- "killable": "^1.0.1",
- "loglevel": "^1.6.8",
- "opn": "^5.5.0",
- "p-retry": "^3.0.1",
- "portfinder": "^1.0.26",
- "schema-utils": "^1.0.0",
- "selfsigned": "^1.10.8",
- "semver": "^6.3.0",
- "serve-index": "^1.9.1",
- "sockjs": "^0.3.21",
- "sockjs-client": "^1.5.0",
- "spdy": "^4.0.2",
- "strip-ansi": "^3.0.1",
- "supports-color": "^6.1.0",
- "url": "^0.11.0",
- "webpack-dev-middleware": "^3.7.2",
- "webpack-log": "^2.0.0",
- "ws": "^6.2.1",
- "yargs": "^13.3.2"
- },
- "dependencies": {
- "anymatch": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
- "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
- "requires": {
- "micromatch": "^3.1.4",
- "normalize-path": "^2.1.1"
- },
- "dependencies": {
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "requires": {
- "remove-trailing-separator": "^1.0.1"
- }
- }
- }
- },
- "binary-extensions": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
- "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
- },
- "braces": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
- "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
- "requires": {
- "arr-flatten": "^1.1.0",
- "array-unique": "^0.3.2",
- "extend-shallow": "^2.0.1",
- "fill-range": "^4.0.0",
- "isobject": "^3.0.1",
- "repeat-element": "^1.1.2",
- "snapdragon": "^0.8.1",
- "snapdragon-node": "^2.0.1",
- "split-string": "^3.0.2",
- "to-regex": "^3.0.1"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "chokidar": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
- "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
- "requires": {
- "anymatch": "^2.0.0",
- "async-each": "^1.0.1",
- "braces": "^2.3.2",
- "fsevents": "^1.2.7",
- "glob-parent": "^3.1.0",
- "inherits": "^2.0.3",
- "is-binary-path": "^1.0.0",
- "is-glob": "^4.0.0",
- "normalize-path": "^3.0.0",
- "path-is-absolute": "^1.0.0",
- "readdirp": "^2.2.1",
- "upath": "^1.1.1"
- },
- "dependencies": {
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "requires": {
- "is-glob": "^4.0.3"
- },
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- }
- }
- },
- "fill-range": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
- "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
- "requires": {
- "extend-shallow": "^2.0.1",
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1",
- "to-regex-range": "^2.1.0"
- },
- "dependencies": {
- "extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
- "requires": {
- "is-extendable": "^0.1.0"
- }
- }
- }
- },
- "fsevents": {
- "version": "1.2.13",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
- "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
- "optional": true,
- "requires": {
- "nan": "^2.12.1"
- }
- },
- "glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dependencies": {
- "is-glob": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
- "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
- "requires": {
- "is-extglob": "^2.1.0"
- }
- }
- }
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
- },
- "import-local": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
- "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
- "requires": {
- "pkg-dir": "^3.0.0",
- "resolve-cwd": "^2.0.0"
- }
- },
- "is-absolute-url": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
- "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q=="
- },
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "requires": {
- "binary-extensions": "^1.0.0"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "^3.0.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "^1.1.5"
- }
- }
- }
- },
- "micromatch": {
- "version": "3.1.10",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
- "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
- "requires": {
- "arr-diff": "^4.0.0",
- "array-unique": "^0.3.2",
- "braces": "^2.3.1",
- "define-property": "^2.0.2",
- "extend-shallow": "^3.0.2",
- "extglob": "^2.0.4",
- "fragment-cache": "^0.2.1",
- "kind-of": "^6.0.2",
- "nanomatch": "^1.2.9",
- "object.pick": "^1.3.0",
- "regex-not": "^1.0.0",
- "snapdragon": "^0.8.1",
- "to-regex": "^3.0.2"
- }
- },
- "readdirp": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
- "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
- "requires": {
- "graceful-fs": "^4.1.11",
- "micromatch": "^3.1.10",
- "readable-stream": "^2.0.2"
- }
- },
- "resolve-cwd": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
- "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
- "requires": {
- "resolve-from": "^3.0.0"
- }
- },
- "resolve-from": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
- },
- "schema-utils": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
- "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
- "requires": {
- "ajv": "^6.1.0",
- "ajv-errors": "^1.0.0",
- "ajv-keywords": "^3.1.0"
- }
- },
- "semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
- },
- "supports-color": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
- "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- },
- "to-regex-range": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
- "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
- "requires": {
- "is-number": "^3.0.0",
- "repeat-string": "^1.6.1"
- }
- },
- "ws": {
- "version": "6.2.2",
- "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz",
- "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==",
- "requires": {
- "async-limiter": "~1.0.0"
- }
- }
- }
- },
- "webpack-filter-warnings-plugin": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/webpack-filter-warnings-plugin/-/webpack-filter-warnings-plugin-1.2.1.tgz",
- "integrity": "sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==",
- "dev": true
- },
- "webpack-hot-middleware": {
- "version": "2.25.1",
- "resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.25.1.tgz",
- "integrity": "sha512-Koh0KyU/RPYwel/khxbsDz9ibDivmUbrRuKSSQvW42KSDdO4w23WI3SkHpSUKHE76LrFnnM/L7JCrpBwu8AXYw==",
- "dev": true,
- "requires": {
- "ansi-html-community": "0.0.8",
- "html-entities": "^2.1.0",
- "querystring": "^0.2.0",
- "strip-ansi": "^6.0.0"
- },
- "dependencies": {
- "html-entities": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz",
- "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==",
- "dev": true
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "webpack-log": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
- "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
- "requires": {
- "ansi-colors": "^3.0.0",
- "uuid": "^3.3.2"
- },
- "dependencies": {
- "ansi-colors": {
- "version": "3.2.4",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
- "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA=="
- },
- "uuid": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
- "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
- }
- }
- },
- "webpack-manifest-plugin": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-2.2.0.tgz",
- "integrity": "sha512-9S6YyKKKh/Oz/eryM1RyLVDVmy3NSPV0JXMRhZ18fJsq+AwGxUY34X54VNwkzYcEmEkDwNxuEOboCZEebJXBAQ==",
- "requires": {
- "fs-extra": "^7.0.0",
- "lodash": ">=3.5 <5",
- "object.entries": "^1.1.0",
- "tapable": "^1.0.0"
- },
- "dependencies": {
- "fs-extra": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
- "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
- "requires": {
- "graceful-fs": "^4.1.2",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
- }
- }
- },
- "webpack-sources": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
- "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
- "requires": {
- "source-list-map": "^2.0.0",
- "source-map": "~0.6.1"
- }
- },
- "webpack-virtual-modules": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.2.2.tgz",
- "integrity": "sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==",
- "dev": true,
- "requires": {
- "debug": "^3.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "requires": {
- "ms": "^2.1.1"
- }
- }
- }
- },
- "websocket-driver": {
- "version": "0.7.4",
- "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
- "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
- "requires": {
- "http-parser-js": ">=0.5.1",
- "safe-buffer": ">=5.1.0",
- "websocket-extensions": ">=0.1.1"
- }
- },
- "websocket-extensions": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
- "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="
- },
- "whatwg-encoding": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
- "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==",
- "requires": {
- "iconv-lite": "0.4.24"
- }
- },
- "whatwg-fetch": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz",
- "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA=="
- },
- "whatwg-mimetype": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
- "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
- },
- "whatwg-url": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz",
- "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==",
- "requires": {
- "lodash": "^4.7.0",
- "tr46": "^2.1.0",
- "webidl-conversions": "^6.1.0"
- }
- },
- "which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "requires": {
- "isexe": "^2.0.0"
- }
- },
- "which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "requires": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- }
- },
- "which-module": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
- "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
- },
- "wicg-inert": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/wicg-inert/-/wicg-inert-3.1.1.tgz",
- "integrity": "sha512-PhBaNh8ur9Xm4Ggy4umelwNIP6pPP1bv3EaWaKqfb/QNme2rdLjm7wIInvV4WhxVHhzA4Spgw9qNSqWtB/ca2A=="
- },
- "wide-align": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
- "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
- "requires": {
- "string-width": "^1.0.2 || 2"
- }
- },
- "widest-line": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
- "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
- "dev": true,
- "requires": {
- "string-width": "^4.0.0"
- },
- "dependencies": {
- "emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true
- },
- "string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "requires": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- }
- },
- "strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "requires": {
- "ansi-regex": "^5.0.1"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true
- }
- }
- }
- }
- },
- "word-wrap": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
- "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
- },
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
- "dev": true
- },
- "workbox-background-sync": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-5.1.4.tgz",
- "integrity": "sha512-AH6x5pYq4vwQvfRDWH+vfOePfPIYQ00nCEB7dJRU1e0n9+9HMRyvI63FlDvtFT2AvXVRsXvUt7DNMEToyJLpSA==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-broadcast-update": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-5.1.4.tgz",
- "integrity": "sha512-HTyTWkqXvHRuqY73XrwvXPud/FN6x3ROzkfFPsRjtw/kGZuZkPzfeH531qdUGfhtwjmtO/ZzXcWErqVzJNdXaA==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-build": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-build/-/workbox-build-5.1.4.tgz",
- "integrity": "sha512-xUcZn6SYU8usjOlfLb9Y2/f86Gdo+fy1fXgH8tJHjxgpo53VVsqRX0lUDw8/JuyzNmXuo8vXX14pXX2oIm9Bow==",
- "requires": {
- "@babel/core": "^7.8.4",
- "@babel/preset-env": "^7.8.4",
- "@babel/runtime": "^7.8.4",
- "@hapi/joi": "^15.1.0",
- "@rollup/plugin-node-resolve": "^7.1.1",
- "@rollup/plugin-replace": "^2.3.1",
- "@surma/rollup-plugin-off-main-thread": "^1.1.1",
- "common-tags": "^1.8.0",
- "fast-json-stable-stringify": "^2.1.0",
- "fs-extra": "^8.1.0",
- "glob": "^7.1.6",
- "lodash.template": "^4.5.0",
- "pretty-bytes": "^5.3.0",
- "rollup": "^1.31.1",
- "rollup-plugin-babel": "^4.3.3",
- "rollup-plugin-terser": "^5.3.1",
- "source-map": "^0.7.3",
- "source-map-url": "^0.4.0",
- "stringify-object": "^3.3.0",
- "strip-comments": "^1.0.2",
- "tempy": "^0.3.0",
- "upath": "^1.2.0",
- "workbox-background-sync": "^5.1.4",
- "workbox-broadcast-update": "^5.1.4",
- "workbox-cacheable-response": "^5.1.4",
- "workbox-core": "^5.1.4",
- "workbox-expiration": "^5.1.4",
- "workbox-google-analytics": "^5.1.4",
- "workbox-navigation-preload": "^5.1.4",
- "workbox-precaching": "^5.1.4",
- "workbox-range-requests": "^5.1.4",
- "workbox-routing": "^5.1.4",
- "workbox-strategies": "^5.1.4",
- "workbox-streams": "^5.1.4",
- "workbox-sw": "^5.1.4",
- "workbox-window": "^5.1.4"
- },
- "dependencies": {
- "fs-extra": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
- "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
- "requires": {
- "graceful-fs": "^4.2.0",
- "jsonfile": "^4.0.0",
- "universalify": "^0.1.0"
- }
- },
- "jsonfile": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
- "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
- "requires": {
- "graceful-fs": "^4.1.6"
- }
- },
- "source-map": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
- "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
- },
- "universalify": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
- "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
- }
- }
- },
- "workbox-cacheable-response": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-5.1.4.tgz",
- "integrity": "sha512-0bfvMZs0Of1S5cdswfQK0BXt6ulU5kVD4lwer2CeI+03czHprXR3V4Y8lPTooamn7eHP8Iywi5QjyAMjw0qauA==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-core": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-5.1.4.tgz",
- "integrity": "sha512-+4iRQan/1D8I81nR2L5vcbaaFskZC2CL17TLbvWVzQ4qiF/ytOGF6XeV54pVxAvKUtkLANhk8TyIUMtiMw2oDg=="
- },
- "workbox-expiration": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-5.1.4.tgz",
- "integrity": "sha512-oDO/5iC65h2Eq7jctAv858W2+CeRW5e0jZBMNRXpzp0ZPvuT6GblUiHnAsC5W5lANs1QS9atVOm4ifrBiYY7AQ==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-google-analytics": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-5.1.4.tgz",
- "integrity": "sha512-0IFhKoEVrreHpKgcOoddV+oIaVXBFKXUzJVBI+nb0bxmcwYuZMdteBTp8AEDJacENtc9xbR0wa9RDCnYsCDLjA==",
- "requires": {
- "workbox-background-sync": "^5.1.4",
- "workbox-core": "^5.1.4",
- "workbox-routing": "^5.1.4",
- "workbox-strategies": "^5.1.4"
- }
- },
- "workbox-navigation-preload": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-5.1.4.tgz",
- "integrity": "sha512-Wf03osvK0wTflAfKXba//QmWC5BIaIZARU03JIhAEO2wSB2BDROWI8Q/zmianf54kdV7e1eLaIEZhth4K4MyfQ==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-precaching": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-5.1.4.tgz",
- "integrity": "sha512-gCIFrBXmVQLFwvAzuGLCmkUYGVhBb7D1k/IL7pUJUO5xacjLcFUaLnnsoVepBGAiKw34HU1y/YuqvTKim9qAZA==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-range-requests": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-5.1.4.tgz",
- "integrity": "sha512-1HSujLjgTeoxHrMR2muDW2dKdxqCGMc1KbeyGcmjZZAizJTFwu7CWLDmLv6O1ceWYrhfuLFJO+umYMddk2XMhw==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-routing": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-5.1.4.tgz",
- "integrity": "sha512-8ljknRfqE1vEQtnMtzfksL+UXO822jJlHTIR7+BtJuxQ17+WPZfsHqvk1ynR/v0EHik4x2+826Hkwpgh4GKDCw==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "workbox-strategies": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-5.1.4.tgz",
- "integrity": "sha512-VVS57LpaJTdjW3RgZvPwX0NlhNmscR7OQ9bP+N/34cYMDzXLyA6kqWffP6QKXSkca1OFo/v6v7hW7zrrguo6EA==",
- "requires": {
- "workbox-core": "^5.1.4",
- "workbox-routing": "^5.1.4"
- }
- },
- "workbox-streams": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-streams/-/workbox-streams-5.1.4.tgz",
- "integrity": "sha512-xU8yuF1hI/XcVhJUAfbQLa1guQUhdLMPQJkdT0kn6HP5CwiPOGiXnSFq80rAG4b1kJUChQQIGPrq439FQUNVrw==",
- "requires": {
- "workbox-core": "^5.1.4",
- "workbox-routing": "^5.1.4"
- }
- },
- "workbox-sw": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-sw/-/workbox-sw-5.1.4.tgz",
- "integrity": "sha512-9xKnKw95aXwSNc8kk8gki4HU0g0W6KXu+xks7wFuC7h0sembFnTrKtckqZxbSod41TDaGh+gWUA5IRXrL0ECRA=="
- },
- "workbox-webpack-plugin": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-5.1.4.tgz",
- "integrity": "sha512-PZafF4HpugZndqISi3rZ4ZK4A4DxO8rAqt2FwRptgsDx7NF8TVKP86/huHquUsRjMGQllsNdn4FNl8CD/UvKmQ==",
- "requires": {
- "@babel/runtime": "^7.5.5",
- "fast-json-stable-stringify": "^2.0.0",
- "source-map-url": "^0.4.0",
- "upath": "^1.1.2",
- "webpack-sources": "^1.3.0",
- "workbox-build": "^5.1.4"
- }
- },
- "workbox-window": {
- "version": "5.1.4",
- "resolved": "https://registry.npmjs.org/workbox-window/-/workbox-window-5.1.4.tgz",
- "integrity": "sha512-vXQtgTeMCUq/4pBWMfQX8Ee7N2wVC4Q7XYFqLnfbXJ2hqew/cU1uMTD2KqGEgEpE4/30luxIxgE+LkIa8glBYw==",
- "requires": {
- "workbox-core": "^5.1.4"
- }
- },
- "worker-farm": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
- "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
- "requires": {
- "errno": "~0.1.7"
- }
- },
- "worker-rpc": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/worker-rpc/-/worker-rpc-0.1.1.tgz",
- "integrity": "sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==",
- "requires": {
- "microevent.ts": "~0.1.1"
- }
- },
- "wrap-ansi": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
- "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
- "requires": {
- "ansi-styles": "^3.2.0",
- "string-width": "^3.0.0",
- "strip-ansi": "^5.0.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "requires": {
- "ansi-regex": "^4.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
- "requires": {
- "imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
- }
- },
- "ws": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
- "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w=="
- },
- "xml-name-validator": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
- "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
- },
- "xmlchars": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
- "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
- },
- "xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
- },
- "y18n": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz",
- "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ=="
- },
- "yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
- "yaml": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
- "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg=="
- },
- "yargs": {
- "version": "13.3.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
- "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
- "requires": {
- "cliui": "^5.0.0",
- "find-up": "^3.0.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^3.0.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^13.1.2"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- },
- "find-up": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
- "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
- "requires": {
- "locate-path": "^3.0.0"
- }
- },
- "is-fullwidth-code-point": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
- },
- "string-width": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
- "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
- "requires": {
- "emoji-regex": "^7.0.1",
- "is-fullwidth-code-point": "^2.0.0",
- "strip-ansi": "^5.1.0"
- }
- },
- "strip-ansi": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
- "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
- "requires": {
- "ansi-regex": "^4.1.0"
- },
- "dependencies": {
- "ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
- }
- }
- }
- }
- },
- "yargs-parser": {
- "version": "13.1.2",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
- "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
- "requires": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- },
- "dependencies": {
- "camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
- }
- }
- },
- "yauzl": {
- "version": "2.10.0",
- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
- "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
- "dev": true,
- "requires": {
- "buffer-crc32": "~0.2.3",
- "fd-slicer": "~1.1.0"
- }
- },
- "yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
- },
- "zwitch": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
- "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
- "dev": true
- }
- }
-}
diff --git a/packages/webapp/package.json b/packages/webapp/package.json
index dc23efa991..86e6f25c70 100644
--- a/packages/webapp/package.json
+++ b/packages/webapp/package.json
@@ -1,153 +1,119 @@
{
- "name": "webapp",
- "version": "3.1.1",
- "private": true,
+ "name": "litefarm-webapp",
+ "version": "3.2.0",
+ "description": "LiteFarm Web application",
+ "scripts": {
+ "dev": "CYPRESS_COVERAGE=TRUE vite",
+ "build": "tsc && vite build",
+ "preview": "vite preview",
+ "lint": "eslint src",
+ "i18n": "npx i18next 'src/**/*.{js,jsx,ts,tsx}' -c 'src/locales/i18next-parser.config.js'",
+ "chromatic": "npx chromatic --project-token gb9nrdyzl8b",
+ "chromatic-local": "./node_modules/.bin/chromatic --project-token 594bdec1c518",
+ "format": "npx prettier --write ./src",
+ "storybook": "start-storybook -p 6006 public",
+ "build-storybook": "build-storybook",
+ "precommit": "lint-staged"
+ },
+ "lint-staged": {
+ "*.{js, jsx}": [
+ "eslint --quiet --fix"
+ ],
+ "*.{js,jsx,ts,tsx,json,md,html}": "prettier --write"
+ },
+ "pnpm": {
+ "peerDependencyRules": {
+ "ignoreMissing": [
+ "@babel/core",
+ "@storybook/core-common",
+ "babel-loader",
+ "prettier",
+ "webpack"
+ ],
+ "allowedVersions": {
+ "react": "17",
+ "react-dom": "17",
+ "acorn": "7"
+ }
+ }
+ },
"dependencies": {
+ "@emotion/react": "^11.7.1",
"@googlemaps/markerclustererplus": "^1.1.0",
"@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2",
- "@reduxjs/toolkit": "^1.6.0",
+ "@reactour/tour": "^2.9.0",
+ "@reduxjs/toolkit": "^1.7.2",
"@sentry/react": "^6.4.1",
"@sentry/tracing": "^6.4.1",
- "@testing-library/jest-dom": "^5.11.4",
- "@testing-library/react": "^11.1.0",
- "@testing-library/user-event": "^12.1.10",
- "axios": "^0.24.0",
- "bootstrap": "^4.6.0",
- "chart.js": "^2.9.3",
- "cleave.js": "^1.6.0",
+ "@tsndr/cloudflare-worker-jwt": "^1.1.5",
+ "axios": "^0.25.0",
"clsx": "^1.1.1",
"compressorjs": "^1.0.7",
- "convert-units": "^2.3.4",
- "dotenv": "^8.2.0",
- "framer-motion": "^3.10.0",
+ "convert-units": "^3.0.0-beta.2",
+ "d3": "^7.3.0",
+ "file-saver": "^2.0.5",
+ "framer-motion": "^6.2.4",
"google-map-react": "^2.1.9",
- "history": "^4.10.1",
+ "history": "^5.2.0",
"html2canvas": "^1.0.0-rc.7",
- "i18next": "^19.8.7",
+ "i18next": "^21.6.11",
"i18next-browser-languagedetector": "^6.0.1",
"i18next-xhr-backend": "^3.2.2",
- "immer": "^9.0.6",
- "jsonwebtoken": "^8.5.1",
+ "immer": "^9.0.12",
"moment": "^2.29.1",
"moment-range": "^4.0.2",
- "node-sass": "^6.0.1",
"notistack": "^1.0.9",
- "nuka-carousel": "^4.5.12",
"prop-types": "^15.7.2",
"rc-year-calendar": "^1.0.2",
"react": "^17.0.2",
- "react-bootstrap": "^1.4.3",
- "react-chartkick": "^0.3.3",
"react-dom": "^17.0.2",
- "react-floater": "^0.7.2",
"react-google-login": "^5.1.25",
- "react-hook-form": "^7.13.0-next.0",
- "react-i18next": "^11.8.5",
- "react-icons": "^4.2.0",
- "react-joyride": "^2.2.1",
- "react-load-script": "0.0.6",
- "react-markdown": "^5.0.2",
- "react-player": "^1.15.3",
- "react-redux": "^7.2.4",
+ "react-hook-form": "^7.26.1",
+ "react-i18next": "^11.15.4",
+ "react-icons": "^4.3.1",
+ "react-load-script": "^0.0.6",
+ "react-redux": "^7.2.6",
"react-redux-form": "^1.16.14",
- "react-responsive": "^8.1.0",
"react-router-dom": "^4.3.1",
- "react-scripts": "^4.0.3",
- "react-select": "^4.2.1",
+ "react-select": "^5.2.2",
"react-table": "^6.11.5",
- "react-tabs-redux": "^4.0.0",
- "redux": "^4.1.0",
- "redux-persist": "^5.10.0",
+ "redux": "^4.1.2",
+ "redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
- "redux-thunk": "^2.3.0",
- "reselect": "^4.0.0",
- "uuid": "^8.3.1",
- "web-vitals": "^1.0.1"
- },
- "scripts": {
- "start": "react-scripts start",
- "build": "react-scripts build",
- "test": "react-scripts test",
- "eject": "react-scripts eject",
- "lint": "eslint src",
- "i18n": "npx i18next 'src/**/*.js' -c 'src/locales/i18next-parser.config.js'",
- "chromatic": "npx chromatic --project-token gb9nrdyzl8b",
- "chromatic-local": "./node_modules/.bin/chromatic --project-token 594bdec1c518",
- "format": "npx prettier --write ./src",
- "storybook": "start-storybook -p 6006 -s public",
- "build-storybook": "build-storybook -s public",
- "precommit": "lint-staged",
- "npm6install": "npx -p npm@6 npm install",
- "preinstall": "npx npm-force-resolutions"
- },
- "lint-staged": {
- "*.{js}": [
- "eslint --quiet --fix"
- ],
- "*.{js,json,md,html}": [
- "prettier --write"
- ]
- },
- "jest": {
- "collectCoverageFrom": [
- "src/**/*.{js,jsx,mjs}"
- ],
- "testMatch": [
- "/src/stories/**/?(*.)(spec|test).{js,jsx,mjs}"
- ],
- "transform": {},
- "transformIgnorePatterns": [
- "node_modules/(?!@ngrx|(?!deck.gl)|ng-dynamic)"
- ]
- },
- "eslintConfig": {
- "extends": [
- "react-app",
- "react-app/jest"
- ]
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
+ "reselect": "^4.1.5",
+ "uuid": "^8.3.2"
},
"devDependencies": {
- "@storybook/addon-a11y": "^6.4.13",
- "@storybook/addon-actions": "^6.4.13",
- "@storybook/addon-essentials": "^6.4.13",
- "@storybook/addon-jest": "^6.4.13",
- "@storybook/addon-links": "^6.4.13",
- "@storybook/addon-storyshots": "^6.4.13",
- "@storybook/addon-storysource": "^6.4.13",
- "@storybook/node-logger": "^6.4.13",
- "@storybook/preset-create-react-app": "^3.2.0",
- "@storybook/react": "^6.4.13",
- "chromatic": "^6.0.4",
- "cypress": "^8.7.0",
- "eslint": "^7.19.0",
- "eslint-config-prettier": "^6.15.0",
- "eslint-plugin-react": "^7.22.0",
- "i18next-parser": "^3.6.0",
- "jest-environment-jsdom-fourteen": "1.0.1",
- "jest-resolve": "24.9.0",
- "jest-watch-typeahead": "^0.6.5",
- "lint-staged": "^10.5.4"
- },
- "resolutions": {
- "ssri": "^8.0.1",
- "ansi-regex": "^5.0.1",
- "nth-check": "^2.0.1",
- "set-value": "^4.1.0",
- "immer": "^9.0.6",
- "glob-parent": "^6.0.2",
- "trim": "^1.0.1"
+ "@cypress/code-coverage": "^3.9.12",
+ "@emotion/babel-plugin": "^11.7.2",
+ "@mdx-js/mdx": "^1.6.22",
+ "@mdx-js/react": "^1.6.22",
+ "@storybook/addon-a11y": "^6.4.18",
+ "@storybook/addon-actions": "^6.4.18",
+ "@storybook/addon-essentials": "^6.4.18",
+ "@storybook/addon-links": "^6.4.18",
+ "@storybook/react": "^6.4.18",
+ "@types/d3": "^7.1.0",
+ "@types/react": "^17.0.39",
+ "@types/react-dom": "^17.0.11",
+ "@typescript-eslint/parser": "^5.11.0",
+ "@vitejs/plugin-react": "^1.1.4",
+ "chromatic": "^6.4.3",
+ "cypress": "^9.5.2",
+ "cypress-react-selector": "^2.3.16",
+ "eslint": "^8.8.0",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-prettier": "^4.0.0",
+ "eslint-plugin-react": "^7.28.0",
+ "i18next-parser": "^5.4.0",
+ "lint-staged": "^12.3.3",
+ "sass": "^1.49.7",
+ "storybook-builder-vite": "^0.1.15",
+ "typescript": "^4.5.5",
+ "vite": "^2.7.13",
+ "vite-plugin-istanbul": "^2.7.1",
+ "vite-plugin-mdx": "^3.5.10",
+ "vite-plugin-svgr": "^1.0.1"
}
}
diff --git a/packages/webapp/pnpm-lock.yaml b/packages/webapp/pnpm-lock.yaml
new file mode 100644
index 0000000000..81e913c03d
--- /dev/null
+++ b/packages/webapp/pnpm-lock.yaml
@@ -0,0 +1,15815 @@
+lockfileVersion: 5.4
+
+specifiers:
+ '@cypress/code-coverage': ^3.9.12
+ '@emotion/babel-plugin': ^11.7.2
+ '@emotion/react': ^11.7.1
+ '@googlemaps/markerclustererplus': ^1.1.0
+ '@material-ui/core': ^4.11.3
+ '@material-ui/icons': ^4.11.2
+ '@mdx-js/mdx': ^1.6.22
+ '@mdx-js/react': ^1.6.22
+ '@reactour/tour': ^2.9.0
+ '@reduxjs/toolkit': ^1.7.2
+ '@sentry/react': ^6.4.1
+ '@sentry/tracing': ^6.4.1
+ '@storybook/addon-a11y': ^6.4.18
+ '@storybook/addon-actions': ^6.4.18
+ '@storybook/addon-essentials': ^6.4.18
+ '@storybook/addon-links': ^6.4.18
+ '@storybook/react': ^6.4.18
+ '@tsndr/cloudflare-worker-jwt': ^1.1.5
+ '@types/d3': ^7.1.0
+ '@types/react': ^17.0.39
+ '@types/react-dom': ^17.0.11
+ '@typescript-eslint/parser': ^5.11.0
+ '@vitejs/plugin-react': ^1.1.4
+ axios: ^0.25.0
+ chromatic: ^6.4.3
+ clsx: ^1.1.1
+ compressorjs: ^1.0.7
+ convert-units: ^3.0.0-beta.2
+ cypress: ^9.5.2
+ cypress-react-selector: ^2.3.16
+ d3: ^7.3.0
+ eslint: ^8.8.0
+ eslint-config-prettier: ^8.3.0
+ eslint-plugin-prettier: ^4.0.0
+ eslint-plugin-react: ^7.28.0
+ file-saver: ^2.0.5
+ framer-motion: ^6.2.4
+ google-map-react: ^2.1.9
+ history: ^5.2.0
+ html2canvas: ^1.0.0-rc.7
+ i18next: ^21.6.11
+ i18next-browser-languagedetector: ^6.0.1
+ i18next-parser: ^5.4.0
+ i18next-xhr-backend: ^3.2.2
+ immer: ^9.0.12
+ lint-staged: ^12.3.3
+ moment: ^2.29.1
+ moment-range: ^4.0.2
+ notistack: ^1.0.9
+ prop-types: ^15.7.2
+ rc-year-calendar: ^1.0.2
+ react: ^17.0.2
+ react-dom: ^17.0.2
+ react-google-login: ^5.1.25
+ react-hook-form: ^7.26.1
+ react-i18next: ^11.15.4
+ react-icons: ^4.3.1
+ react-load-script: ^0.0.6
+ react-redux: ^7.2.6
+ react-redux-form: ^1.16.14
+ react-router-dom: ^4.3.1
+ react-select: ^5.2.2
+ react-table: ^6.11.5
+ redux: ^4.1.2
+ redux-persist: ^6.0.0
+ redux-saga: ^1.1.3
+ reselect: ^4.1.5
+ sass: ^1.49.7
+ storybook-builder-vite: ^0.1.15
+ typescript: ^4.5.5
+ uuid: ^8.3.2
+ vite: ^2.7.13
+ vite-plugin-istanbul: ^2.7.1
+ vite-plugin-mdx: ^3.5.10
+ vite-plugin-svgr: ^1.0.1
+
+dependencies:
+ '@emotion/react': 11.7.1_udcsdvdzjr5ns727jqoeu7kyda
+ '@googlemaps/markerclustererplus': 1.2.10
+ '@material-ui/core': 4.12.3_xd63vgjm47lzoal5ybyqmsdesy
+ '@material-ui/icons': 4.11.2_kwoupvnfnqlomq253rqvbhpoba
+ '@reactour/tour': 2.9.0_phausblcypdf55k6wezkg7rzwq
+ '@reduxjs/toolkit': 1.7.2_g7iv2n2puphpvmcbz4lgg4le54
+ '@sentry/react': 6.17.5_react@17.0.2
+ '@sentry/tracing': 6.17.5
+ '@tsndr/cloudflare-worker-jwt': 1.1.5
+ axios: 0.25.0
+ clsx: 1.1.1
+ compressorjs: 1.1.1
+ convert-units: 3.0.0-beta.3
+ d3: 7.3.0
+ file-saver: 2.0.5
+ framer-motion: 6.2.4_sfoxds7t5ydpegc3knd667wn6m
+ google-map-react: 2.1.10_sfoxds7t5ydpegc3knd667wn6m
+ history: 5.2.0
+ html2canvas: 1.4.1
+ i18next: 21.6.11
+ i18next-browser-languagedetector: 6.1.3
+ i18next-xhr-backend: 3.2.2
+ immer: 9.0.12
+ moment: 2.29.1
+ moment-range: 4.0.2_moment@2.29.1
+ notistack: 1.0.10_7twteiegzuck7mfw73wj5btjea
+ prop-types: 15.8.1
+ rc-year-calendar: 1.0.2_at7mkepldmzoo6silmqc5bca74
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-google-login: 5.2.2_sfoxds7t5ydpegc3knd667wn6m
+ react-hook-form: 7.26.1_react@17.0.2
+ react-i18next: 11.15.4_h63ejkrqcivap6la2z72khlnye
+ react-icons: 4.3.1_react@17.0.2
+ react-load-script: 0.0.6_at7mkepldmzoo6silmqc5bca74
+ react-redux: 7.2.6_sfoxds7t5ydpegc3knd667wn6m
+ react-redux-form: 1.16.14_63tzpzdcuxiupedwoo4b6s3rxy
+ react-router-dom: 4.3.1_react@17.0.2
+ react-select: 5.2.2_xd63vgjm47lzoal5ybyqmsdesy
+ react-table: 6.11.5_oxfzelaz5ynxsop2v2nu2h2m64
+ redux: 4.1.2
+ redux-persist: 6.0.0_redux@4.1.2
+ redux-saga: 1.1.3
+ reselect: 4.1.5
+ uuid: 8.3.2
+
+devDependencies:
+ '@cypress/code-coverage': 3.9.12_cypress@9.5.2
+ '@emotion/babel-plugin': 11.7.2
+ '@mdx-js/mdx': 1.6.22
+ '@mdx-js/react': 1.6.22_react@17.0.2
+ '@storybook/addon-a11y': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-actions': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-essentials': 6.4.18_srnw6goump5hkbz5yr7u3w6rwa
+ '@storybook/addon-links': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/react': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ '@types/d3': 7.1.0
+ '@types/react': 17.0.39
+ '@types/react-dom': 17.0.11
+ '@typescript-eslint/parser': 5.11.0_txwvkng2juu2h6yeaibqmql3uy
+ '@vitejs/plugin-react': 1.1.4
+ chromatic: 6.4.3
+ cypress: 9.5.2
+ cypress-react-selector: 2.3.16
+ eslint: 8.8.0
+ eslint-config-prettier: 8.3.0_eslint@8.8.0
+ eslint-plugin-prettier: 4.0.0_punao7uarsvpb6gm4i6ih2skcq
+ eslint-plugin-react: 7.28.0_eslint@8.8.0
+ i18next-parser: 5.4.0
+ lint-staged: 12.3.3
+ sass: 1.49.7
+ storybook-builder-vite: 0.1.15_tittu3jxgxganfythqbtfovvv4
+ typescript: 4.5.5
+ vite: 2.7.13_sass@1.49.7
+ vite-plugin-istanbul: 2.7.1
+ vite-plugin-mdx: 3.5.10_k4bmpxmaqlgvoeub2z775fx6ma
+ vite-plugin-svgr: 1.0.1_vite@2.7.13
+
+packages:
+
+ /@alloc/quick-lru/5.2.0:
+ resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /@ampproject/remapping/2.1.0:
+ resolution: {integrity: sha512-d5RysTlJ7hmw5Tw4UxgxcY3lkMe92n8sXCcuLPAyIAHK6j8DefDwtGnVVDgOnv+RnEosulDJ9NPKQL27bDId0g==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ '@jridgewell/trace-mapping': 0.3.2
+ dev: true
+
+ /@babel/code-frame/7.16.7:
+ resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/highlight': 7.16.10
+ dev: true
+
+ /@babel/compat-data/7.17.0:
+ resolution: {integrity: sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/core/7.12.9:
+ resolution: {integrity: sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ '@babel/generator': 7.17.0
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helpers': 7.17.0
+ '@babel/parser': 7.17.0
+ '@babel/template': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ convert-source-map: 1.8.0
+ debug: 4.3.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.0
+ lodash: 4.17.21
+ resolve: 1.22.0
+ semver: 5.7.1
+ source-map: 0.5.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/core/7.17.0:
+ resolution: {integrity: sha512-x/5Ea+RO5MvF9ize5DeVICJoVrNv0Mi2RnIABrZEKYvPEpldXwauPkgvYA17cKa6WpU3LoYvYbuEMFtSNFsarA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@ampproject/remapping': 2.1.0
+ '@babel/code-frame': 7.16.7
+ '@babel/generator': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helpers': 7.17.0
+ '@babel/parser': 7.17.0
+ '@babel/template': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ convert-source-map: 1.8.0
+ debug: 4.3.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/generator/7.17.0:
+ resolution: {integrity: sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ jsesc: 2.5.2
+ source-map: 0.5.7
+ dev: true
+
+ /@babel/helper-annotate-as-pure/7.16.7:
+ resolution: {integrity: sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-builder-binary-assignment-operator-visitor/7.16.7:
+ resolution: {integrity: sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-explode-assignable-expression': 7.16.7
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-compilation-targets/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/compat-data': 7.17.0
+ '@babel/core': 7.17.0
+ '@babel/helper-validator-option': 7.16.7
+ browserslist: 4.19.1
+ semver: 6.3.0
+ dev: true
+
+ /@babel/helper-create-class-features-plugin/7.17.1_@babel+core@7.17.0:
+ resolution: {integrity: sha512-JBdSr/LtyYIno/pNnJ75lBcqc3Z1XXujzPanHqjvvrhOA+DTceTFuJi8XjmWTZh4r3fsdfqaCMN0iZemdkxZHQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-environment-visitor': 7.16.7
+ '@babel/helper-function-name': 7.16.7
+ '@babel/helper-member-expression-to-functions': 7.16.7
+ '@babel/helper-optimise-call-expression': 7.16.7
+ '@babel/helper-replace-supers': 7.16.7
+ '@babel/helper-split-export-declaration': 7.16.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-create-regexp-features-plugin/7.17.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ regexpu-core: 5.0.1
+ dev: true
+
+ /@babel/helper-define-polyfill-provider/0.1.5_@babel+core@7.17.0:
+ resolution: {integrity: sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==}
+ peerDependencies:
+ '@babel/core': ^7.4.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/traverse': 7.17.0
+ debug: 4.3.3
+ lodash.debounce: 4.0.8
+ resolve: 1.22.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-define-polyfill-provider/0.3.1_@babel+core@7.17.0:
+ resolution: {integrity: sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==}
+ peerDependencies:
+ '@babel/core': ^7.4.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/traverse': 7.17.0
+ debug: 4.3.3
+ lodash.debounce: 4.0.8
+ resolve: 1.22.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-environment-visitor/7.16.7:
+ resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-explode-assignable-expression/7.16.7:
+ resolution: {integrity: sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-function-name/7.16.7:
+ resolution: {integrity: sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-get-function-arity': 7.16.7
+ '@babel/template': 7.16.7
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-get-function-arity/7.16.7:
+ resolution: {integrity: sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-hoist-variables/7.16.7:
+ resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-member-expression-to-functions/7.16.7:
+ resolution: {integrity: sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-module-imports/7.16.7:
+ resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-module-transforms/7.16.7:
+ resolution: {integrity: sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-environment-visitor': 7.16.7
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-simple-access': 7.16.7
+ '@babel/helper-split-export-declaration': 7.16.7
+ '@babel/helper-validator-identifier': 7.16.7
+ '@babel/template': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-optimise-call-expression/7.16.7:
+ resolution: {integrity: sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-plugin-utils/7.10.4:
+ resolution: {integrity: sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==}
+ dev: true
+
+ /@babel/helper-plugin-utils/7.16.7:
+ resolution: {integrity: sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-remap-async-to-generator/7.16.8:
+ resolution: {integrity: sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-wrap-function': 7.16.8
+ '@babel/types': 7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-replace-supers/7.16.7:
+ resolution: {integrity: sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-environment-visitor': 7.16.7
+ '@babel/helper-member-expression-to-functions': 7.16.7
+ '@babel/helper-optimise-call-expression': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helper-simple-access/7.16.7:
+ resolution: {integrity: sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-skip-transparent-expression-wrappers/7.16.0:
+ resolution: {integrity: sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-split-export-declaration/7.16.7:
+ resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/helper-validator-identifier/7.16.7:
+ resolution: {integrity: sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-validator-option/7.16.7:
+ resolution: {integrity: sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /@babel/helper-wrap-function/7.16.8:
+ resolution: {integrity: sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-function-name': 7.16.7
+ '@babel/template': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/helpers/7.17.0:
+ resolution: {integrity: sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/template': 7.16.7
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/highlight/7.16.10:
+ resolution: {integrity: sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.16.7
+ chalk: 2.4.2
+ js-tokens: 4.0.0
+ dev: true
+
+ /@babel/parser/7.17.0:
+ resolution: {integrity: sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dev: true
+
+ /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.13.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.16.0
+ '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-async-generator-functions/7.16.8_@babel+core@7.17.0:
+ resolution: {integrity: sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-remap-async-to-generator': 7.16.8
+ '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-class-properties/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-class-static-block/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.12.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-decorators/7.17.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-JR8HTf3T1CsdMqfENrZ9pqncwsH4sPcvsyDLpvmv8iIbpDmeyBD7HPfGAIqkQph2j5d3B84hTm+m3qHPAedaPw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-replace-supers': 7.16.7
+ '@babel/plugin-syntax-decorators': 7.17.0_@babel+core@7.17.0
+ charcodes: 0.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-dynamic-import/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-export-default-from/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-+cENpW1rgIjExn+o5c8Jw/4BuH4eGKKYvkMB8/0ZxFQ9mC0t4z09VsPIwNg6waF69QYC81zxGeAsREGuqQoKeg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-export-default-from': 7.16.7_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-export-namespace-from/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-json-strings/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-logical-assignment-operators/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-nullish-coalescing-operator/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-numeric-separator/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-object-rest-spread/7.12.1_@babel+core@7.12.9:
+ resolution: {integrity: sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.12.9
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.12.9
+ dev: true
+
+ /@babel/plugin-proposal-object-rest-spread/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/compat-data': 7.17.0
+ '@babel/core': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-optional-catch-binding/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-optional-chaining/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.16.0
+ '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-proposal-private-methods/7.16.11_@babel+core@7.17.0:
+ resolution: {integrity: sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-private-property-in-object/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-proposal-unicode-property-regex/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-regexp-features-plugin': 7.17.0_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.17.0:
+ resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.17.0:
+ resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-class-static-block/7.14.5_@babel+core@7.17.0:
+ resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-decorators/7.17.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-qWe85yCXsvDEluNP0OyeQjH63DlhAR3W7K9BxxU1MvbDb48tgBG+Ao6IJJ6smPDrrVzSQZrbF6donpkFBMcs3A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-dynamic-import/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-export-default-from/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-4C3E4NsrLOgftKaTYTULhHsuQrGv3FHrBzOMDiS7UYKIpgGBkAdawg4h+EI8zPeK9M0fiIIh72hIwsI24K7MbA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-export-namespace-from/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-flow/7.16.7:
+ resolution: {integrity: sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-jsx/7.12.1_@babel+core@7.12.9:
+ resolution: {integrity: sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-jsx/7.16.7:
+ resolution: {integrity: sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-jsx/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.17.0:
+ resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.17.0:
+ resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.12.9:
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.17.0:
+ resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-private-property-in-object/7.14.5_@babel+core@7.17.0:
+ resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.17.0:
+ resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-syntax-typescript/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-arrow-functions/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-async-to-generator/7.16.8_@babel+core@7.17.0:
+ resolution: {integrity: sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-remap-async-to-generator': 7.16.8
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-block-scoped-functions/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-block-scoping/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-classes/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-environment-visitor': 7.16.7
+ '@babel/helper-function-name': 7.16.7
+ '@babel/helper-optimise-call-expression': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-replace-supers': 7.16.7
+ '@babel/helper-split-export-declaration': 7.16.7
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-computed-properties/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-destructuring/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-dotall-regex/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-regexp-features-plugin': 7.17.0_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-duplicate-keys/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-exponentiation-operator/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-builder-binary-assignment-operator-visitor': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-flow-strip-types/7.16.7:
+ resolution: {integrity: sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-flow': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-for-of/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-function-name/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-function-name': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-literals/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-member-expression-literals/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-modules-amd/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ babel-plugin-dynamic-import-node: 2.3.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-commonjs/7.16.8_@babel+core@7.17.0:
+ resolution: {integrity: sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-simple-access': 7.16.7
+ babel-plugin-dynamic-import-node: 2.3.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-systemjs/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-hoist-variables': 7.16.7
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-identifier': 7.16.7
+ babel-plugin-dynamic-import-node: 2.3.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-modules-umd/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-module-transforms': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-named-capturing-groups-regex/7.16.8_@babel+core@7.17.0:
+ resolution: {integrity: sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-regexp-features-plugin': 7.17.0_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-transform-new-target/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-object-super/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-replace-supers': 7.16.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-parameters/7.16.7_@babel+core@7.12.9:
+ resolution: {integrity: sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-parameters/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-property-literals/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-display-name/7.16.7:
+ resolution: {integrity: sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-display-name/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-development/7.16.7:
+ resolution: {integrity: sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/plugin-transform-react-jsx': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-development/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.17.0
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-self/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-jsx-source/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-jsx/7.16.7:
+ resolution: {integrity: sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-jsx': 7.16.7
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/plugin-transform-react-jsx/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-jsx': 7.16.7_@babel+core@7.17.0
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/plugin-transform-react-pure-annotations/7.16.7:
+ resolution: {integrity: sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-react-pure-annotations/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-annotate-as-pure': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-regenerator/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ regenerator-transform: 0.14.5
+ dev: true
+
+ /@babel/plugin-transform-reserved-words/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-runtime/7.17.10_@babel+core@7.17.0:
+ resolution: {integrity: sha512-6jrMilUAJhktTr56kACL8LnWC5hx3Lf27BS0R0DSyW/OoJfb/iTHeE96V3b1dgKG3FSFdd/0culnYWMkjcKCig==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/helper-plugin-utils': 7.16.7
+ babel-plugin-polyfill-corejs2: 0.3.1_@babel+core@7.17.0
+ babel-plugin-polyfill-corejs3: 0.5.2_@babel+core@7.17.0
+ babel-plugin-polyfill-regenerator: 0.3.1_@babel+core@7.17.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-shorthand-properties/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-spread/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-skip-transparent-expression-wrappers': 7.16.0
+ dev: true
+
+ /@babel/plugin-transform-sticky-regex/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-template-literals/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-typeof-symbol/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-typescript/7.16.8_@babel+core@7.17.0:
+ resolution: {integrity: sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-class-features-plugin': 7.17.1_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-syntax-typescript': 7.16.7_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/plugin-transform-unicode-escapes/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/plugin-transform-unicode-regex/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-create-regexp-features-plugin': 7.17.0_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ dev: true
+
+ /@babel/preset-env/7.16.11_@babel+core@7.17.0:
+ resolution: {integrity: sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/compat-data': 7.17.0
+ '@babel/core': 7.17.0
+ '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-option': 7.16.7
+ '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-async-generator-functions': 7.16.8_@babel+core@7.17.0
+ '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-class-static-block': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-dynamic-import': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-export-namespace-from': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-json-strings': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-logical-assignment-operators': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-numeric-separator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-object-rest-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-optional-catch-binding': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-private-methods': 7.16.11_@babel+core@7.17.0
+ '@babel/plugin-proposal-private-property-in-object': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-unicode-property-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.17.0
+ '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.17.0
+ '@babel/plugin-syntax-class-static-block': 7.14.5_@babel+core@7.17.0
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-export-namespace-from': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.17.0
+ '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.17.0
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-syntax-private-property-in-object': 7.14.5_@babel+core@7.17.0
+ '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.17.0
+ '@babel/plugin-transform-arrow-functions': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-async-to-generator': 7.16.8_@babel+core@7.17.0
+ '@babel/plugin-transform-block-scoped-functions': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-block-scoping': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-classes': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-computed-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-destructuring': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-dotall-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-duplicate-keys': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-exponentiation-operator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-for-of': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-function-name': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-member-expression-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-modules-amd': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-modules-commonjs': 7.16.8_@babel+core@7.17.0
+ '@babel/plugin-transform-modules-systemjs': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-modules-umd': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-named-capturing-groups-regex': 7.16.8_@babel+core@7.17.0
+ '@babel/plugin-transform-new-target': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-object-super': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-property-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-regenerator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-reserved-words': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-shorthand-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-sticky-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-template-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-typeof-symbol': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-unicode-escapes': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-unicode-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-modules': 0.1.5_@babel+core@7.17.0
+ '@babel/types': 7.17.0
+ babel-plugin-polyfill-corejs2: 0.3.1_@babel+core@7.17.0
+ babel-plugin-polyfill-corejs3: 0.5.2_@babel+core@7.17.0
+ babel-plugin-polyfill-regenerator: 0.3.1_@babel+core@7.17.0
+ core-js-compat: 3.21.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/preset-flow/7.16.7:
+ resolution: {integrity: sha512-6ceP7IyZdUYQ3wUVqyRSQXztd1YmFHWI4Xv11MIqAlE4WqxBSd/FZ61V9k+TS5Gd4mkHOtQtPp9ymRpxH4y1Ug==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-option': 7.16.7
+ '@babel/plugin-transform-flow-strip-types': 7.16.7
+ dev: true
+
+ /@babel/preset-modules/0.1.5_@babel+core@7.17.0:
+ resolution: {integrity: sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/plugin-proposal-unicode-property-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-dotall-regex': 7.16.7_@babel+core@7.17.0
+ '@babel/types': 7.17.0
+ esutils: 2.0.3
+ dev: true
+
+ /@babel/preset-react/7.16.7:
+ resolution: {integrity: sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-option': 7.16.7
+ '@babel/plugin-transform-react-display-name': 7.16.7
+ '@babel/plugin-transform-react-jsx': 7.16.7
+ '@babel/plugin-transform-react-jsx-development': 7.16.7
+ '@babel/plugin-transform-react-pure-annotations': 7.16.7
+ dev: true
+
+ /@babel/preset-react/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-option': 7.16.7
+ '@babel/plugin-transform-react-display-name': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-jsx-development': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-pure-annotations': 7.16.7_@babel+core@7.17.0
+ dev: true
+
+ /@babel/preset-typescript/7.16.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-plugin-utils': 7.16.7
+ '@babel/helper-validator-option': 7.16.7
+ '@babel/plugin-transform-typescript': 7.16.8_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/register/7.17.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-UNZsMAZ7uKoGHo1HlEXfteEOYssf64n/PNLHGqOKq/bgYcu/4LrQWAHJwSCb3BRZK8Hi5gkJdRcwrGTO2wtRCg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ clone-deep: 4.0.1
+ find-cache-dir: 2.1.0
+ make-dir: 2.1.0
+ pirates: 4.0.5
+ source-map-support: 0.5.21
+ dev: true
+
+ /@babel/runtime/7.17.0:
+ resolution: {integrity: sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ regenerator-runtime: 0.13.9
+
+ /@babel/template/7.16.7:
+ resolution: {integrity: sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ '@babel/parser': 7.17.0
+ '@babel/types': 7.17.0
+ dev: true
+
+ /@babel/traverse/7.17.0:
+ resolution: {integrity: sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ '@babel/generator': 7.17.0
+ '@babel/helper-environment-visitor': 7.16.7
+ '@babel/helper-function-name': 7.16.7
+ '@babel/helper-hoist-variables': 7.16.7
+ '@babel/helper-split-export-declaration': 7.16.7
+ '@babel/parser': 7.17.0
+ '@babel/types': 7.17.0
+ debug: 4.3.3
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@babel/types/7.17.0:
+ resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ '@babel/helper-validator-identifier': 7.16.7
+ to-fast-properties: 2.0.0
+ dev: true
+
+ /@base2/pretty-print-object/1.0.1:
+ resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==}
+ dev: true
+
+ /@bcoe/v8-coverage/0.2.3:
+ resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
+ dev: true
+
+ /@cnakazawa/watch/1.0.4:
+ resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==}
+ engines: {node: '>=0.1.95'}
+ hasBin: true
+ dependencies:
+ exec-sh: 0.3.6
+ minimist: 1.2.5
+ dev: true
+
+ /@cypress/browserify-preprocessor/3.0.2:
+ resolution: {integrity: sha512-y6mlFR+IR2cqcm3HabSp7AEcX9QfF1EUL4eOaw/7xexdhmdQU8ez6piyRopZQob4BK8oKTsc9PkupsU2rzjqMA==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-object-rest-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-runtime': 7.17.10_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@babel/runtime': 7.17.0
+ babel-plugin-add-module-exports: 1.0.4
+ babelify: 10.0.0_@babel+core@7.17.0
+ bluebird: 3.7.2
+ browserify: 16.5.2
+ coffeeify: 3.0.1_coffeescript@1.12.7
+ coffeescript: 1.12.7
+ debug: 4.3.3
+ fs-extra: 9.1.0
+ lodash.clonedeep: 4.5.0
+ through2: 2.0.5
+ watchify: 4.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@cypress/code-coverage/3.9.12_cypress@9.5.2:
+ resolution: {integrity: sha512-2QuDSQ2ovz2ZsbQImM917q+9JmEq4afC4kpgHe2o3rTQxUrs7CdHM84rT8XKl0gJIXmbMcNq2rZqe40/eFmCFw==}
+ peerDependencies:
+ cypress: '*'
+ dependencies:
+ '@cypress/browserify-preprocessor': 3.0.2
+ chalk: 4.1.2
+ cypress: 9.5.2
+ dayjs: 1.10.7
+ debug: 4.3.3
+ execa: 4.1.0
+ globby: 11.0.4
+ istanbul-lib-coverage: 3.0.0
+ js-yaml: 3.14.1
+ nyc: 15.1.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@cypress/request/2.88.10:
+ resolution: {integrity: sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==}
+ engines: {node: '>= 6'}
+ dependencies:
+ aws-sign2: 0.7.0
+ aws4: 1.11.0
+ caseless: 0.12.0
+ combined-stream: 1.0.8
+ extend: 3.0.2
+ forever-agent: 0.6.1
+ form-data: 2.3.3
+ http-signature: 1.3.6
+ is-typedarray: 1.0.0
+ isstream: 0.1.2
+ json-stringify-safe: 5.0.1
+ mime-types: 2.1.34
+ performance-now: 2.1.0
+ qs: 6.5.3
+ safe-buffer: 5.2.1
+ tough-cookie: 2.5.0
+ tunnel-agent: 0.6.0
+ uuid: 8.3.2
+ dev: true
+
+ /@cypress/xvfb/1.2.4:
+ resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==}
+ dependencies:
+ debug: 3.2.7
+ lodash.once: 4.1.1
+ dev: true
+
+ /@discoveryjs/json-ext/0.5.6:
+ resolution: {integrity: sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==}
+ engines: {node: '>=10.0.0'}
+ dev: true
+
+ /@emotion/babel-plugin/11.7.2:
+ resolution: {integrity: sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/helper-module-imports': 7.16.7
+ '@babel/plugin-syntax-jsx': 7.16.7
+ '@babel/runtime': 7.17.0
+ '@emotion/hash': 0.8.0
+ '@emotion/memoize': 0.7.5
+ '@emotion/serialize': 1.0.2
+ babel-plugin-macros: 2.8.0
+ convert-source-map: 1.8.0
+ escape-string-regexp: 4.0.0
+ find-root: 1.1.0
+ source-map: 0.5.7
+ stylis: 4.0.13
+ dev: true
+
+ /@emotion/cache/10.0.29:
+ resolution: {integrity: sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==}
+ dependencies:
+ '@emotion/sheet': 0.9.4
+ '@emotion/stylis': 0.8.5
+ '@emotion/utils': 0.11.3
+ '@emotion/weak-memoize': 0.2.5
+ dev: true
+
+ /@emotion/cache/11.7.1:
+ resolution: {integrity: sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==}
+ dependencies:
+ '@emotion/memoize': 0.7.5
+ '@emotion/sheet': 1.1.0
+ '@emotion/utils': 1.0.0
+ '@emotion/weak-memoize': 0.2.5
+ stylis: 4.0.13
+ dev: false
+
+ /@emotion/core/10.3.1_react@17.0.2:
+ resolution: {integrity: sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==}
+ peerDependencies:
+ react: '>=16.3.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/cache': 10.0.29
+ '@emotion/css': 10.0.27
+ '@emotion/serialize': 0.11.16
+ '@emotion/sheet': 0.9.4
+ '@emotion/utils': 0.11.3
+ react: 17.0.2
+ dev: true
+
+ /@emotion/css/10.0.27:
+ resolution: {integrity: sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==}
+ dependencies:
+ '@emotion/serialize': 0.11.16
+ '@emotion/utils': 0.11.3
+ babel-plugin-emotion: 10.2.2
+ dev: true
+
+ /@emotion/hash/0.8.0:
+ resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==}
+
+ /@emotion/is-prop-valid/0.8.8:
+ resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
+ dependencies:
+ '@emotion/memoize': 0.7.4
+
+ /@emotion/memoize/0.7.4:
+ resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
+
+ /@emotion/memoize/0.7.5:
+ resolution: {integrity: sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==}
+
+ /@emotion/react/11.7.1_udcsdvdzjr5ns727jqoeu7kyda:
+ resolution: {integrity: sha512-DV2Xe3yhkF1yT4uAUoJcYL1AmrnO5SVsdfvu+fBuS7IbByDeTVx9+wFmvx9Idzv7/78+9Mgx2Hcmr7Fex3tIyw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ '@types/react': '*'
+ react: '>=16.8.0 || 17'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/cache': 11.7.1
+ '@emotion/serialize': 1.0.2
+ '@emotion/sheet': 1.1.0
+ '@emotion/utils': 1.0.0
+ '@emotion/weak-memoize': 0.2.5
+ '@types/react': 17.0.39
+ hoist-non-react-statics: 3.3.2
+ react: 17.0.2
+ dev: false
+
+ /@emotion/serialize/0.11.16:
+ resolution: {integrity: sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==}
+ dependencies:
+ '@emotion/hash': 0.8.0
+ '@emotion/memoize': 0.7.4
+ '@emotion/unitless': 0.7.5
+ '@emotion/utils': 0.11.3
+ csstype: 2.6.19
+ dev: true
+
+ /@emotion/serialize/1.0.2:
+ resolution: {integrity: sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==}
+ dependencies:
+ '@emotion/hash': 0.8.0
+ '@emotion/memoize': 0.7.5
+ '@emotion/unitless': 0.7.5
+ '@emotion/utils': 1.0.0
+ csstype: 3.0.10
+
+ /@emotion/sheet/0.9.4:
+ resolution: {integrity: sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==}
+ dev: true
+
+ /@emotion/sheet/1.1.0:
+ resolution: {integrity: sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==}
+ dev: false
+
+ /@emotion/styled-base/10.3.0_gfrer23gq2rp2t523t6qbxrx6m:
+ resolution: {integrity: sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==}
+ peerDependencies:
+ '@emotion/core': ^10.0.28
+ react: '>=16.3.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/core': 10.3.1_react@17.0.2
+ '@emotion/is-prop-valid': 0.8.8
+ '@emotion/serialize': 0.11.16
+ '@emotion/utils': 0.11.3
+ react: 17.0.2
+ dev: true
+
+ /@emotion/styled/10.3.0_gfrer23gq2rp2t523t6qbxrx6m:
+ resolution: {integrity: sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==}
+ peerDependencies:
+ '@emotion/core': ^10.0.27
+ react: '>=16.3.0 || 17'
+ dependencies:
+ '@emotion/core': 10.3.1_react@17.0.2
+ '@emotion/styled-base': 10.3.0_gfrer23gq2rp2t523t6qbxrx6m
+ babel-plugin-emotion: 10.2.2
+ react: 17.0.2
+ dev: true
+
+ /@emotion/stylis/0.8.5:
+ resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==}
+ dev: true
+
+ /@emotion/unitless/0.7.5:
+ resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==}
+
+ /@emotion/utils/0.11.3:
+ resolution: {integrity: sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==}
+ dev: true
+
+ /@emotion/utils/1.0.0:
+ resolution: {integrity: sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==}
+
+ /@emotion/weak-memoize/0.2.5:
+ resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==}
+
+ /@eslint/eslintrc/1.0.5:
+ resolution: {integrity: sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ ajv: 6.12.6
+ debug: 4.3.3
+ espree: 9.3.0
+ globals: 13.12.1
+ ignore: 4.0.6
+ import-fresh: 3.3.0
+ js-yaml: 4.1.0
+ minimatch: 3.0.5
+ strip-json-comments: 3.1.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@gar/promisify/1.1.2:
+ resolution: {integrity: sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw==}
+ dev: true
+
+ /@googlemaps/js-api-loader/1.13.4:
+ resolution: {integrity: sha512-KB5G+k9b6cyQnGQmcKRXxtmkDrNomfvZfCdz8fVk9gKb7esQsJ+Sl+NTfPjXxSXJTEXi1eWi5z0cZrwivDcLDg==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ dev: false
+
+ /@googlemaps/markerclustererplus/1.2.10:
+ resolution: {integrity: sha512-HY4ev+D3kO1+9oQjtKTojxVtJIS/kSWJfry6cpKoXC97kBQc5Vguqu5x6pLnh+70N0Au+16Yl7iu4LZaIOTstw==}
+ dev: false
+
+ /@humanwhocodes/config-array/0.9.3:
+ resolution: {integrity: sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==}
+ engines: {node: '>=10.10.0'}
+ dependencies:
+ '@humanwhocodes/object-schema': 1.2.1
+ debug: 4.3.3
+ minimatch: 3.0.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@humanwhocodes/object-schema/1.2.1:
+ resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
+ dev: true
+
+ /@istanbuljs/load-nyc-config/1.1.0:
+ resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ camelcase: 5.3.1
+ find-up: 4.1.0
+ get-package-type: 0.1.0
+ js-yaml: 3.14.1
+ resolve-from: 5.0.0
+ dev: true
+
+ /@istanbuljs/schema/0.1.3:
+ resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /@jest/transform/26.6.2:
+ resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==}
+ engines: {node: '>= 10.14.2'}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@jest/types': 26.6.2
+ babel-plugin-istanbul: 6.1.1
+ chalk: 4.1.2
+ convert-source-map: 1.8.0
+ fast-json-stable-stringify: 2.1.0
+ graceful-fs: 4.2.9
+ jest-haste-map: 26.6.2
+ jest-regex-util: 26.0.0
+ jest-util: 26.6.2
+ micromatch: 4.0.4
+ pirates: 4.0.5
+ slash: 3.0.0
+ source-map: 0.6.1
+ write-file-atomic: 3.0.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@jest/types/26.6.2:
+ resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==}
+ engines: {node: '>= 10.14.2'}
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.4
+ '@types/istanbul-reports': 3.0.1
+ '@types/node': 17.0.16
+ '@types/yargs': 15.0.14
+ chalk: 4.1.2
+ dev: true
+
+ /@joshwooding/vite-plugin-react-docgen-typescript/0.0.2_opd4ws7dumj54hnyecb3t4fnpq:
+ resolution: {integrity: sha512-0hbsoX2c7Z3lJKY+88ToduiQDyh+Mggpd6Go0vVV3PchMRyE9iOCVUBiqd4FFfgNdFdk6iNKrO9bdIiHOpW6jA==}
+ peerDependencies:
+ typescript: '>= 4.3.x'
+ vite: '>2.0.0-0'
+ dependencies:
+ glob: 7.2.0
+ glob-promise: 4.2.2_glob@7.2.0
+ react-docgen-typescript: 2.2.2_typescript@4.5.5
+ typescript: 4.5.5
+ vite: 2.7.13_sass@1.49.7
+ dev: true
+
+ /@jridgewell/resolve-uri/3.0.4:
+ resolution: {integrity: sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==}
+ engines: {node: '>=6.0.0'}
+ dev: true
+
+ /@jridgewell/sourcemap-codec/1.4.10:
+ resolution: {integrity: sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==}
+ dev: true
+
+ /@jridgewell/trace-mapping/0.3.2:
+ resolution: {integrity: sha512-9KzzH4kMjA2XmBRHfqG2/Vtl7s92l6uNDd0wW7frDE+EUvQFGqNXhWp0UGJjSkt3v2AYjzOZn1QO9XaTNJIt1Q==}
+ dependencies:
+ '@jridgewell/resolve-uri': 3.0.4
+ '@jridgewell/sourcemap-codec': 1.4.10
+ dev: true
+
+ /@mapbox/point-geometry/0.1.0:
+ resolution: {integrity: sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI=}
+ dev: false
+
+ /@material-ui/core/4.12.3_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==}
+ engines: {node: '>=8.0.0'}
+ deprecated: 'You can now upgrade to @mui/material. See the guide: https://mui.com/guides/migration-v4/'
+ peerDependencies:
+ '@types/react': ^16.8.6 || ^17.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@material-ui/styles': 4.11.4_xd63vgjm47lzoal5ybyqmsdesy
+ '@material-ui/system': 4.12.1_xd63vgjm47lzoal5ybyqmsdesy
+ '@material-ui/types': 5.1.0_@types+react@17.0.39
+ '@material-ui/utils': 4.11.2_sfoxds7t5ydpegc3knd667wn6m
+ '@types/react': 17.0.39
+ '@types/react-transition-group': 4.4.4
+ clsx: 1.1.1
+ hoist-non-react-statics: 3.3.2
+ popper.js: 1.16.1-lts
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-is: 17.0.2
+ react-transition-group: 4.4.2_sfoxds7t5ydpegc3knd667wn6m
+ dev: false
+
+ /@material-ui/icons/4.11.2_kwoupvnfnqlomq253rqvbhpoba:
+ resolution: {integrity: sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==}
+ engines: {node: '>=8.0.0'}
+ peerDependencies:
+ '@material-ui/core': ^4.0.0
+ '@types/react': ^16.8.6 || ^17.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@material-ui/core': 4.12.3_xd63vgjm47lzoal5ybyqmsdesy
+ '@types/react': 17.0.39
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /@material-ui/styles/4.11.4_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==}
+ engines: {node: '>=8.0.0'}
+ peerDependencies:
+ '@types/react': ^16.8.6 || ^17.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/hash': 0.8.0
+ '@material-ui/types': 5.1.0_@types+react@17.0.39
+ '@material-ui/utils': 4.11.2_sfoxds7t5ydpegc3knd667wn6m
+ '@types/react': 17.0.39
+ clsx: 1.1.1
+ csstype: 2.6.19
+ hoist-non-react-statics: 3.3.2
+ jss: 10.9.0
+ jss-plugin-camel-case: 10.9.0
+ jss-plugin-default-unit: 10.9.0
+ jss-plugin-global: 10.9.0
+ jss-plugin-nested: 10.9.0
+ jss-plugin-props-sort: 10.9.0
+ jss-plugin-rule-value-function: 10.9.0
+ jss-plugin-vendor-prefixer: 10.9.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /@material-ui/system/4.12.1_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==}
+ engines: {node: '>=8.0.0'}
+ peerDependencies:
+ '@types/react': ^16.8.6 || ^17.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@material-ui/utils': 4.11.2_sfoxds7t5ydpegc3knd667wn6m
+ '@types/react': 17.0.39
+ csstype: 2.6.19
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /@material-ui/types/5.1.0_@types+react@17.0.39:
+ resolution: {integrity: sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==}
+ peerDependencies:
+ '@types/react': '*'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 17.0.39
+ dev: false
+
+ /@material-ui/utils/4.11.2_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==}
+ engines: {node: '>=8.0.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-is: 17.0.2
+ dev: false
+
+ /@mdx-js/loader/1.6.22_react@17.0.2:
+ resolution: {integrity: sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==}
+ dependencies:
+ '@mdx-js/mdx': 1.6.22
+ '@mdx-js/react': 1.6.22_react@17.0.2
+ loader-utils: 2.0.0
+ transitivePeerDependencies:
+ - react
+ - supports-color
+ dev: true
+
+ /@mdx-js/mdx/1.6.22:
+ resolution: {integrity: sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==}
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/plugin-syntax-jsx': 7.12.1_@babel+core@7.12.9
+ '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.12.9
+ '@mdx-js/util': 1.6.22
+ babel-plugin-apply-mdx-type-prop: 1.6.22_@babel+core@7.12.9
+ babel-plugin-extract-import-names: 1.6.22
+ camelcase-css: 2.0.1
+ detab: 2.0.4
+ hast-util-raw: 6.0.1
+ lodash.uniq: 4.5.0
+ mdast-util-to-hast: 10.0.1
+ remark-footnotes: 2.0.0
+ remark-mdx: 1.6.22
+ remark-parse: 8.0.3
+ remark-squeeze-paragraphs: 4.0.0
+ style-to-object: 0.3.0
+ unified: 9.2.0
+ unist-builder: 2.0.3
+ unist-util-visit: 2.0.3
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@mdx-js/react/1.6.22_react@17.0.2:
+ resolution: {integrity: sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==}
+ peerDependencies:
+ react: ^16.13.1 || ^17.0.0 || 17
+ dependencies:
+ react: 17.0.2
+ dev: true
+
+ /@mdx-js/util/1.6.22:
+ resolution: {integrity: sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==}
+ dev: true
+
+ /@mrmlnc/readdir-enhanced/2.2.1:
+ resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==}
+ engines: {node: '>=4'}
+ dependencies:
+ call-me-maybe: 1.0.1
+ glob-to-regexp: 0.3.0
+ dev: true
+
+ /@nodelib/fs.scandir/2.1.5:
+ resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ run-parallel: 1.2.0
+ dev: true
+
+ /@nodelib/fs.stat/1.1.3:
+ resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /@nodelib/fs.stat/2.0.5:
+ resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /@nodelib/fs.walk/1.2.8:
+ resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ '@nodelib/fs.scandir': 2.1.5
+ fastq: 1.13.0
+ dev: true
+
+ /@npmcli/fs/1.1.0:
+ resolution: {integrity: sha512-VhP1qZLXcrXRIaPoqb4YA55JQxLNF3jNR4T55IdOJa3+IFJKNYHtPvtXx8slmeMavj37vCzCfrqQM1vWLsYKLA==}
+ engines: {node: ^12.13.0 || ^14.15.0 || >=16}
+ dependencies:
+ '@gar/promisify': 1.1.2
+ semver: 7.3.5
+ dev: true
+
+ /@npmcli/move-file/1.1.2:
+ resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==}
+ engines: {node: '>=10'}
+ dependencies:
+ mkdirp: 1.0.4
+ rimraf: 3.0.2
+ dev: true
+
+ /@pmmmwh/react-refresh-webpack-plugin/0.5.4_a3gyllrqvxpec3fpybsrposvju:
+ resolution: {integrity: sha512-zZbZeHQDnoTlt2AF+diQT0wsSXpvWiaIOZwBRdltNFhG1+I3ozyaw7U/nBiUwyJ0D+zwdXp0E3bWOl38Ag2BMw==}
+ engines: {node: '>= 10.13'}
+ peerDependencies:
+ '@types/webpack': 4.x || 5.x
+ react-refresh: '>=0.10.0 <1.0.0'
+ sockjs-client: ^1.4.0
+ type-fest: '>=0.17.0 <3.0.0'
+ webpack: '>=4.43.0 <6.0.0'
+ webpack-dev-server: 3.x || 4.x
+ webpack-hot-middleware: 2.x
+ webpack-plugin-serve: 0.x || 1.x
+ peerDependenciesMeta:
+ '@types/webpack':
+ optional: true
+ sockjs-client:
+ optional: true
+ type-fest:
+ optional: true
+ webpack:
+ optional: true
+ webpack-dev-server:
+ optional: true
+ webpack-hot-middleware:
+ optional: true
+ webpack-plugin-serve:
+ optional: true
+ dependencies:
+ ansi-html-community: 0.0.8
+ common-path-prefix: 3.0.0
+ core-js-pure: 3.21.0
+ error-stack-parser: 2.0.6
+ find-up: 5.0.0
+ html-entities: 2.3.2
+ loader-utils: 2.0.2
+ react-refresh: 0.11.0
+ schema-utils: 3.1.1
+ source-map: 0.7.3
+ webpack: 4.46.0
+ dev: true
+
+ /@popperjs/core/2.11.2:
+ resolution: {integrity: sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==}
+ dev: true
+
+ /@react-aria/focus/3.5.0_react@17.0.2:
+ resolution: {integrity: sha512-Eib75Q6QgQdn8VVVByg5Vipaaj/C//8Bs++sQY7nkomRx4sdArOnXbDppul3YHP6mRfU9VRLvAigEUlReQF/Xw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@react-aria/interactions': 3.7.0_react@17.0.2
+ '@react-aria/utils': 3.11.0_react@17.0.2
+ '@react-types/shared': 3.10.1_react@17.0.2
+ clsx: 1.1.1
+ react: 17.0.2
+ dev: false
+
+ /@react-aria/interactions/3.7.0_react@17.0.2:
+ resolution: {integrity: sha512-Xomchjb9bqvh3ocil+QCEYFSxsTy8PHEz43mNP6z2yuu3UqTpl2FsWfyKgF/Yy0WKVkyV2dO2uz758KJTCLZhw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@react-aria/utils': 3.11.0_react@17.0.2
+ '@react-types/shared': 3.10.1_react@17.0.2
+ react: 17.0.2
+ dev: false
+
+ /@react-aria/ssr/3.1.0_react@17.0.2:
+ resolution: {integrity: sha512-RxqQKmE8sO7TGdrcSlHTcVzMP450hqowtBSd2bBS9oPlcokVkaGq28c3Rwa8ty5ctw4EBCjXqjP7xdcKMGDzug==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ react: 17.0.2
+ dev: false
+
+ /@react-aria/utils/3.11.0_react@17.0.2:
+ resolution: {integrity: sha512-4yFA8E9xqDCUlolYSsoyp/qxrkiQrnEqx1BQOrKDuicpW7MBJ39pJC23YFMpyK2a6xEptc6xJEeIEFJXp57jJw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@react-aria/ssr': 3.1.0_react@17.0.2
+ '@react-stately/utils': 3.3.0_react@17.0.2
+ '@react-types/shared': 3.10.1_react@17.0.2
+ clsx: 1.1.1
+ react: 17.0.2
+ dev: false
+
+ /@react-stately/utils/3.3.0_react@17.0.2:
+ resolution: {integrity: sha512-f//Y8q0+FFcS04xvCNvbba7WWRLHzj2AegLgdgwTxsnk9Gb+AyuasdRrRY7bGQhdHuEJ7OIiQZ9EQWndDbrTcg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ react: 17.0.2
+ dev: false
+
+ /@react-types/shared/3.10.1_react@17.0.2:
+ resolution: {integrity: sha512-U3dLJtstvOiZ8XLrWdNv9WXuruoDyfIfSXguTs9N0naDdO+M0MIbt/1Hg7Toe43ueAe56GM14IFL+S0/jhv8ow==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0-rc.1 || 17
+ dependencies:
+ react: 17.0.2
+ dev: false
+
+ /@reactour/mask/0.4.0_phausblcypdf55k6wezkg7rzwq:
+ resolution: {integrity: sha512-yD2MPMtxSXJvlHaoIv0IScUZKtyeT0COnnfDJkf9fPHWAsx3vS5y+rLJFL2BltmtDeMfvDlem7Ac/59LYPF7Dg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@emotion/react': ^11
+ react: 16.x || 17.x || 17
+ dependencies:
+ '@emotion/react': 11.7.1_udcsdvdzjr5ns727jqoeu7kyda
+ '@reactour/utils': 0.3.0_react@17.0.2
+ react: 17.0.2
+ dev: false
+
+ /@reactour/popover/0.4.0_phausblcypdf55k6wezkg7rzwq:
+ resolution: {integrity: sha512-UQ7QyNZN/kxuesb3bLU01iYyQG5PTN+bZ/PazUak1tC3dey/dTMnsbbKwH0Yjub+5W8F9YnZAmFXylRWE9jsCg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@emotion/react': ^11
+ react: 16.x || 17.x || 17
+ dependencies:
+ '@emotion/react': 11.7.1_udcsdvdzjr5ns727jqoeu7kyda
+ '@reactour/utils': 0.3.0_react@17.0.2
+ react: 17.0.2
+ dev: false
+
+ /@reactour/tour/2.9.0_phausblcypdf55k6wezkg7rzwq:
+ resolution: {integrity: sha512-4uvVlVrH30fax+VMs3Zsa2ht3H22S9kLF+aEjHDCDStagUIZQ1iZbZGck/Av4pCHJ0WG4iimt2eqrb/0pqs0OA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@emotion/react': ^11
+ react: 16.x || 17.x || 17
+ dependencies:
+ '@emotion/react': 11.7.1_udcsdvdzjr5ns727jqoeu7kyda
+ '@react-aria/focus': 3.5.0_react@17.0.2
+ '@reactour/mask': 0.4.0_phausblcypdf55k6wezkg7rzwq
+ '@reactour/popover': 0.4.0_phausblcypdf55k6wezkg7rzwq
+ '@reactour/utils': 0.3.0_react@17.0.2
+ react: 17.0.2
+ dev: false
+
+ /@reactour/utils/0.3.0_react@17.0.2:
+ resolution: {integrity: sha512-3pukl5fY5ju9/4GUykiXbqIQAd2RWDBpo1XKTy9nWndqvn51hL31lGUVAnWakQ+qvJhTA2Jb3RvvHqcWW6ZvCA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: 16.x || 17.x || 17
+ dependencies:
+ '@rooks/use-mutation-observer': 4.11.2_react@17.0.2
+ react: 17.0.2
+ resize-observer-polyfill: 1.5.1
+ dev: false
+
+ /@redux-saga/core/1.1.3:
+ resolution: {integrity: sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@redux-saga/deferred': 1.1.2
+ '@redux-saga/delay-p': 1.1.2
+ '@redux-saga/is': 1.1.2
+ '@redux-saga/symbols': 1.1.2
+ '@redux-saga/types': 1.1.0
+ redux: 4.1.2
+ typescript-tuple: 2.2.1
+ dev: false
+
+ /@redux-saga/deferred/1.1.2:
+ resolution: {integrity: sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ==}
+ dev: false
+
+ /@redux-saga/delay-p/1.1.2:
+ resolution: {integrity: sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==}
+ dependencies:
+ '@redux-saga/symbols': 1.1.2
+ dev: false
+
+ /@redux-saga/is/1.1.2:
+ resolution: {integrity: sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==}
+ dependencies:
+ '@redux-saga/symbols': 1.1.2
+ '@redux-saga/types': 1.1.0
+ dev: false
+
+ /@redux-saga/symbols/1.1.2:
+ resolution: {integrity: sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ==}
+ dev: false
+
+ /@redux-saga/types/1.1.0:
+ resolution: {integrity: sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg==}
+ dev: false
+
+ /@reduxjs/toolkit/1.7.2_g7iv2n2puphpvmcbz4lgg4le54:
+ resolution: {integrity: sha512-wwr3//Ar8ZhM9bS58O+HCIaMlR4Y6SNHfuszz9hKnQuFIKvwaL3Kmjo6fpDKUOjo4Lv54Yi299ed8rofCJ/Vjw==}
+ peerDependencies:
+ react: ^16.9.0 || ^17.0.0 || 18.0.0-beta || 17
+ react-redux: ^7.2.1 || ^8.0.0-beta
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-redux:
+ optional: true
+ dependencies:
+ immer: 9.0.12
+ react: 17.0.2
+ react-redux: 7.2.6_sfoxds7t5ydpegc3knd667wn6m
+ redux: 4.1.2
+ redux-thunk: 2.4.1_redux@4.1.2
+ reselect: 4.1.5
+ dev: false
+
+ /@rollup/pluginutils/4.1.2:
+ resolution: {integrity: sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==}
+ engines: {node: '>= 8.0.0'}
+ dependencies:
+ estree-walker: 2.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /@rooks/use-mutation-observer/4.11.2_react@17.0.2:
+ resolution: {integrity: sha512-vpsdrZdr6TkB1zZJcHx+fR1YC/pHs2BaqcuYiEGjBVbwY5xcC49+h0hAUtQKHth3oJqXfIX/Ng8S7s5HFHdM/A==}
+ peerDependencies:
+ react: '>=16.8.0 || 17'
+ dependencies:
+ react: 17.0.2
+ dev: false
+
+ /@sentry/browser/6.17.5:
+ resolution: {integrity: sha512-3xZ+6HgEnnQpXEk+3YJyfHlsJzMbOBEnjs3ImAiJvKJLdPnRjhixbQwsiV9Fm2SG43o2bFABpGSE337rvy4JuA==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/core': 6.17.5
+ '@sentry/types': 6.17.5
+ '@sentry/utils': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/core/6.17.5:
+ resolution: {integrity: sha512-G1bYvZsWM5n0QYbnv89a24HCXex3rMWUnHWFysNqcWmw2YfiQ9RX5SakGbesewBj2Br2XpaDH0pED3QBUrC7yA==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/hub': 6.17.5
+ '@sentry/minimal': 6.17.5
+ '@sentry/types': 6.17.5
+ '@sentry/utils': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/hub/6.17.5:
+ resolution: {integrity: sha512-jBRrG0v3nHrymyj13Dv28aRS6xgQjWup45E0rljeksCxDL9frc734C0QGzGjE2MG7vZWtvd2CgP8uNbgYpwlTw==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/types': 6.17.5
+ '@sentry/utils': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/minimal/6.17.5:
+ resolution: {integrity: sha512-WY/IQh2tb4XDkvr/2/8LB0mO8W3cgL6S2Uv+YfVRqogGJRdg5wD67aQ9zypNMq+D84cPwRuR/+51Npj6daox4w==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/hub': 6.17.5
+ '@sentry/types': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/react/6.17.5_react@17.0.2:
+ resolution: {integrity: sha512-ryE3NkRDfPdIdMkh6cdtFI7+0a0XL7SetpScRwMi8PjUp6EV1fxbGPM7ETicJvt4V4yknPQeFXUG+vOqEuaLmg==}
+ engines: {node: '>=6'}
+ peerDependencies:
+ react: 15.x || 16.x || 17.x || 17
+ dependencies:
+ '@sentry/browser': 6.17.5
+ '@sentry/minimal': 6.17.5
+ '@sentry/types': 6.17.5
+ '@sentry/utils': 6.17.5
+ hoist-non-react-statics: 3.3.2
+ react: 17.0.2
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/tracing/6.17.5:
+ resolution: {integrity: sha512-SVIDFL/QbNAlv+Rhgq14TqtTBp9WGipkjQXXaD/Pbqcj3/Oil7ZHHKYesW8Z+gtKQs73oQ9a0nCgraLFcQ68PQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/hub': 6.17.5
+ '@sentry/minimal': 6.17.5
+ '@sentry/types': 6.17.5
+ '@sentry/utils': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@sentry/types/6.17.5:
+ resolution: {integrity: sha512-mn7qKuOvmZRTomJ7BiJEw6DM8femAVQcuHa8hdvK1F6ldMfFVLen5Z2LYGE7iY36GEa1Ba/AGGEKyF8D29y2/Q==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /@sentry/utils/6.17.5:
+ resolution: {integrity: sha512-MMCFCNWW73HRnqPVRGGSaMfSxtvvlNDgu1JFAOT2vnNkuf0mXvH301lyrh4pFJfntrtXOOk4bnGMhyWRlPADdA==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@sentry/types': 6.17.5
+ tslib: 1.14.1
+ dev: false
+
+ /@storybook/addon-a11y/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-sqsA5pXXKKDsquSXu5KC8WxQ1gg5ZoNIltWRgmJCEt4a0bkGUzn2iz+uW/gbt4NOVWGPXKvmMBLT/q4Q9gb+og==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ axe-core: 4.4.1
+ core-js: 3.21.0
+ global: 4.4.0
+ lodash: 4.17.21
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-sizeme: 3.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-actions/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-qPw5qfbWPmyOdaXxAVAbdVLVVE31gRrkH0ESUps+FXVNypRz1/0lJ6M2VrtOHMrFbGBl94SALdqsHOx6OYZKwg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ lodash: 4.17.21
+ polished: 4.1.4
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-inspector: 5.1.1_react@17.0.2
+ regenerator-runtime: 0.13.9
+ telejson: 5.3.3
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ uuid-browser: 3.1.0
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-backgrounds/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-LAonQO0s77CkbGx7l8qyeEevOBWDuYZKl9iJ0BSPogU48+4JVEYVSBiystIXPJXcGeEy+M0qFmwg5nHWjf9/cA==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ global: 4.4.0
+ memoizerific: 1.11.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-controls/6.4.18_6tswtrdbbtx76xutylfphb2nta:
+ resolution: {integrity: sha512-nP7JCiAES4S5mn8PYfmPZZG9VpsPV7eeQQRPuiPgdidhH93cmsW/FYj8V739lrm5QJc0JSI6uY/y9qHa9rh43w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/node-logger': 6.4.18
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ lodash: 4.17.21
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ ts-dedent: 2.2.0
+ transitivePeerDependencies:
+ - '@types/react'
+ - eslint
+ - supports-color
+ - typescript
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/addon-docs/6.4.18_srnw6goump5hkbz5yr7u3w6rwa:
+ resolution: {integrity: sha512-NcGcrW+2hrzoyWHEaDmw6wxqyV/FDsdLaOS0XZrIQuBaj1rve0IfA1jqggfNo8owqmXXGp8cQBnFbhRES1a7nQ==}
+ peerDependencies:
+ '@storybook/angular': 6.4.18
+ '@storybook/html': 6.4.18
+ '@storybook/react': 6.4.18
+ '@storybook/vue': 6.4.18
+ '@storybook/vue3': 6.4.18
+ '@storybook/web-components': 6.4.18
+ lit: ^2.0.0
+ lit-html: ^1.4.1 || ^2.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ svelte: ^3.31.2
+ sveltedoc-parser: ^4.1.0
+ vue: ^2.6.10 || ^3.0.0
+ webpack: '*'
+ peerDependenciesMeta:
+ '@storybook/angular':
+ optional: true
+ '@storybook/html':
+ optional: true
+ '@storybook/react':
+ optional: true
+ '@storybook/vue':
+ optional: true
+ '@storybook/vue3':
+ optional: true
+ '@storybook/web-components':
+ optional: true
+ lit:
+ optional: true
+ lit-html:
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ svelte:
+ optional: true
+ sveltedoc-parser:
+ optional: true
+ vue:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/generator': 7.17.0
+ '@babel/parser': 7.17.0
+ '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@jest/transform': 26.6.2
+ '@mdx-js/loader': 1.6.22_react@17.0.2
+ '@mdx-js/mdx': 1.6.22
+ '@mdx-js/react': 1.6.22_react@17.0.2
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/builder-webpack4': 6.4.18_xi2bcknbnmjsry4xsg5z5mcrou
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core': 6.4.18_xi2bcknbnmjsry4xsg5z5mcrou
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/csf-tools': 6.4.18
+ '@storybook/node-logger': 6.4.18
+ '@storybook/postinstall': 6.4.18
+ '@storybook/preview-web': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/react': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ '@storybook/source-loader': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ acorn: 7.4.1
+ acorn-jsx: 5.3.2_acorn@7.4.1
+ acorn-walk: 7.2.0
+ core-js: 3.21.0
+ doctrine: 3.0.0
+ escodegen: 2.0.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ html-tags: 3.1.0
+ js-string-escape: 1.0.1
+ loader-utils: 2.0.2
+ lodash: 4.17.21
+ nanoid: 3.2.0
+ p-limit: 3.1.0
+ prettier: 2.3.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-element-to-jsx-string: 14.3.4_sfoxds7t5ydpegc3knd667wn6m
+ regenerator-runtime: 0.13.9
+ remark-external-links: 8.0.0
+ remark-slug: 6.1.0
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ transitivePeerDependencies:
+ - '@storybook/builder-webpack5'
+ - '@storybook/manager-webpack5'
+ - '@types/react'
+ - bufferutil
+ - encoding
+ - eslint
+ - supports-color
+ - typescript
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/addon-essentials/6.4.18_srnw6goump5hkbz5yr7u3w6rwa:
+ resolution: {integrity: sha512-AWKF0Gn7HagzB4ZbZdSXauJ8rgjbIB0Y1jgNCYtReZ//9QDSmF9yrFE0fLJi8O0WBHiQOTeV8Vj+yooGGWRRWQ==}
+ peerDependencies:
+ '@babel/core': ^7.9.6
+ '@storybook/vue': 6.4.18
+ '@storybook/web-components': 6.4.18
+ babel-loader: ^8.0.0
+ lit-html: ^1.4.1 || ^2.0.0-rc.3
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ webpack: '*'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ '@storybook/vue':
+ optional: true
+ '@storybook/web-components':
+ optional: true
+ babel-loader:
+ optional: true
+ lit-html:
+ optional: true
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@storybook/addon-actions': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-backgrounds': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-controls': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ '@storybook/addon-docs': 6.4.18_srnw6goump5hkbz5yr7u3w6rwa
+ '@storybook/addon-measure': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-outline': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-toolbars': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addon-viewport': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/node-logger': 6.4.18
+ core-js: 3.21.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ transitivePeerDependencies:
+ - '@storybook/angular'
+ - '@storybook/builder-webpack5'
+ - '@storybook/html'
+ - '@storybook/manager-webpack5'
+ - '@storybook/react'
+ - '@storybook/vue3'
+ - '@types/react'
+ - bufferutil
+ - encoding
+ - eslint
+ - lit
+ - supports-color
+ - svelte
+ - sveltedoc-parser
+ - typescript
+ - utf-8-validate
+ - vue
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/addon-links/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-yIbL57+tV1Ei2b7zTGU/T7muBFByTPm/8IN5SA5tSFYRTR9VtFuvBXco6I9Wz9GLN/REyVa4+AoDahokk7+vPQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/qs': 6.9.7
+ core-js: 3.21.0
+ global: 4.4.0
+ prop-types: 15.8.1
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ dev: true
+
+ /@storybook/addon-measure/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-a9bFiQ/QK/5guxWscwOJN+sszhClPTTn2pTX77SKs+bzZUmckCfneto4NUavsHpj/XTxjwAwidowewwqFV1jTQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ core-js: 3.21.0
+ global: 4.4.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-outline/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-FyADdeD7x/25OkjCR7oIXDgrlwM5RB0tbslC0qrRMxKXSjZFTJjr3Qwge0bg8I9QbxDRz+blVzBv3xIhOiDNzQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ core-js: 3.21.0
+ global: 4.4.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-toolbars/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-Vvj8mvorZhoXvYDuUUKqFpcsNNkVJZmhojdLZ4ULPcvjN3z5MWGwtlJfV+9vkVmJWuR1WG93dVK1+PnitYDZAQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addon-viewport/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-gWSJAdtUaVrpsbdBveFTkz4V3moGnKxS3iwR8djcIWhTqdRVJxGu0gFtxNpKvdOEMIqF4yNmXYj79oLuNZNkcQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ global: 4.4.0
+ memoizerific: 1.11.3
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/addons/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-fd3S79P4jJCYZNA2JxA1Xnkj0UlHGQ4Vg72aroWy4OQFlgGQor1LgPfM6RaJ9rh/4k4BXYPXsS7wzI0UWKG3Lw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/webpack-env': 1.16.3
+ core-js: 3.21.0
+ global: 4.4.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ dev: true
+
+ /@storybook/api/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-tSbsHKklBysuSmw4T+cKzMj6mQh/42m9F8+2iJns2XG/IUKpMAzFg/9dlgCTW+ay6dJwsR79JGIc9ccIe4SMgQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/semver': 7.3.2
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ lodash: 4.17.21
+ memoizerific: 1.11.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ store2: 2.13.1
+ telejson: 5.3.3
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /@storybook/builder-webpack4/6.4.18_6tswtrdbbtx76xutylfphb2nta:
+ resolution: {integrity: sha512-N/OGjTnc7CpVoDnfoI49uMjAIpGqh2lWHFYNIWaUoG1DNnTt1nCc49hw9awjFc5KgaYOwJmVg1SYYE8Afssu+Q==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-decorators': 7.17.0_@babel+core@7.17.0
+ '@babel/plugin-proposal-export-default-from': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-object-rest-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-private-methods': 7.16.11_@babel+core@7.17.0
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-transform-arrow-functions': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-block-scoping': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-classes': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-destructuring': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-for-of': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-shorthand-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-template-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-typescript': 7.16.7_@babel+core@7.17.0
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/channels': 6.4.18
+ '@storybook/client-api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/core-events': 6.4.18
+ '@storybook/node-logger': 6.4.18
+ '@storybook/preview-web': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/semver': 7.3.2
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@types/node': 14.18.10
+ '@types/webpack': 4.41.32
+ autoprefixer: 9.8.8
+ babel-loader: 8.2.3_u5fzby2crnk75aqgypigfhaoii
+ babel-plugin-macros: 2.8.0
+ babel-plugin-polyfill-corejs3: 0.1.7_@babel+core@7.17.0
+ case-sensitive-paths-webpack-plugin: 2.4.0
+ core-js: 3.21.0
+ css-loader: 3.6.0_webpack@4.46.0
+ file-loader: 6.2.0_webpack@4.46.0
+ find-up: 5.0.0
+ fork-ts-checker-webpack-plugin: 4.1.6
+ glob: 7.2.0
+ glob-promise: 3.4.0_glob@7.2.0
+ global: 4.4.0
+ html-webpack-plugin: 4.5.2_webpack@4.46.0
+ pnp-webpack-plugin: 1.6.4_typescript@4.5.5
+ postcss: 7.0.39
+ postcss-flexbugs-fixes: 4.2.1
+ postcss-loader: 4.3.0_gzaxsinx64nntyd3vmdqwl7coe
+ raw-loader: 4.0.2_webpack@4.46.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ stable: 0.1.8
+ style-loader: 1.3.0_webpack@4.46.0
+ terser-webpack-plugin: 4.2.3_webpack@4.46.0
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ webpack-dev-middleware: 3.7.3_webpack@4.46.0
+ webpack-filter-warnings-plugin: 1.2.1_webpack@4.46.0
+ webpack-hot-middleware: 2.25.1
+ webpack-virtual-modules: 0.2.2
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - eslint
+ - supports-color
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/builder-webpack4/6.4.18_xi2bcknbnmjsry4xsg5z5mcrou:
+ resolution: {integrity: sha512-N/OGjTnc7CpVoDnfoI49uMjAIpGqh2lWHFYNIWaUoG1DNnTt1nCc49hw9awjFc5KgaYOwJmVg1SYYE8Afssu+Q==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-decorators': 7.17.0_@babel+core@7.17.0
+ '@babel/plugin-proposal-export-default-from': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-object-rest-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-private-methods': 7.16.11_@babel+core@7.17.0
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-transform-arrow-functions': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-block-scoping': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-classes': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-destructuring': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-for-of': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-shorthand-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-template-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-typescript': 7.16.7_@babel+core@7.17.0
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/channels': 6.4.18
+ '@storybook/client-api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/core-events': 6.4.18
+ '@storybook/node-logger': 6.4.18
+ '@storybook/preview-web': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/semver': 7.3.2
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@types/node': 14.18.10
+ '@types/webpack': 4.41.32
+ autoprefixer: 9.8.8
+ babel-loader: 8.2.3_u5fzby2crnk75aqgypigfhaoii
+ babel-plugin-macros: 2.8.0
+ babel-plugin-polyfill-corejs3: 0.1.7_@babel+core@7.17.0
+ case-sensitive-paths-webpack-plugin: 2.4.0
+ core-js: 3.21.0
+ css-loader: 3.6.0_webpack@4.46.0
+ file-loader: 6.2.0_webpack@4.46.0
+ find-up: 5.0.0
+ fork-ts-checker-webpack-plugin: 4.1.6
+ glob: 7.2.0
+ glob-promise: 3.4.0_glob@7.2.0
+ global: 4.4.0
+ html-webpack-plugin: 4.5.2_webpack@4.46.0
+ pnp-webpack-plugin: 1.6.4_typescript@4.5.5
+ postcss: 7.0.39
+ postcss-flexbugs-fixes: 4.2.1
+ postcss-loader: 4.3.0_gzaxsinx64nntyd3vmdqwl7coe
+ raw-loader: 4.0.2_webpack@4.46.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ stable: 0.1.8
+ style-loader: 1.3.0_webpack@4.46.0
+ terser-webpack-plugin: 4.2.3_acorn@7.4.1+webpack@4.46.0
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ webpack-dev-middleware: 3.7.3_webpack@4.46.0
+ webpack-filter-warnings-plugin: 1.2.1_webpack@4.46.0
+ webpack-hot-middleware: 2.25.1
+ webpack-virtual-modules: 0.2.2
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - eslint
+ - supports-color
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/channel-postmessage/6.4.18:
+ resolution: {integrity: sha512-SKapUREPkqzKoBMpOJrZddE9PCR8CJkPTcDpjDqcRsTvToRWsux3pvzmuW4iGYnHNh+GQml7Rz9x85WfMIpfyQ==}
+ dependencies:
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ core-js: 3.21.0
+ global: 4.4.0
+ qs: 6.10.3
+ telejson: 5.3.3
+ dev: true
+
+ /@storybook/channel-websocket/6.4.18:
+ resolution: {integrity: sha512-ROqNZAFB1gP9u8dmlM4KxykXHsd1ifunBgFY3ncQKeRi2Oh30OMVB2ZhNdoIF8i8X5ZBwSpId1o6nQhL2e/EJA==}
+ dependencies:
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ core-js: 3.21.0
+ global: 4.4.0
+ telejson: 5.3.3
+ dev: true
+
+ /@storybook/channels/6.4.18:
+ resolution: {integrity: sha512-Bh4l7VKKR2ImLbZ9XgL/DzT3lFv9+SLiCu1ozfpBZGHUCOLyHRnkG/h8wYvRkF9s3tpNwOtaCaqD1vkkZfr3uw==}
+ dependencies:
+ core-js: 3.21.0
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /@storybook/client-api/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-ua2Q692Fz2b3q5M/Qzjixg2LArwrcHGBmht06bNw/jrRfyFeTUHOhh5BT7LxSEetUgHATH/Y1GW40xza9rXFNw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/qs': 6.9.7
+ '@types/webpack-env': 1.16.3
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ lodash: 4.17.21
+ memoizerific: 1.11.3
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ store2: 2.13.1
+ synchronous-promise: 2.0.15
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /@storybook/client-logger/6.4.18:
+ resolution: {integrity: sha512-ciBaASMaB2ZPksbuyDbp3++5SZxbhcihEpl+RQcAVV8g+TUyBZKIcHt8HNHicTczz5my1EydZovMh1IkSBMICA==}
+ dependencies:
+ core-js: 3.21.0
+ global: 4.4.0
+ dev: true
+
+ /@storybook/components/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-LAPKYWgB6S10Vzt0IWa1Ihf9EAuQOGxlqehTuxYLOwMOKbto8iEbGRse/XaQfxdZf/RbmOL4u+7nVRROWgOEjg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@popperjs/core': 2.11.2
+ '@storybook/client-logger': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/color-convert': 2.0.0
+ '@types/overlayscrollbars': 1.12.1
+ '@types/react-syntax-highlighter': 11.0.5
+ color-convert: 2.0.1
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ lodash: 4.17.21
+ markdown-to-jsx: 7.1.6_react@17.0.2
+ memoizerific: 1.11.3
+ overlayscrollbars: 1.13.1
+ polished: 4.1.4
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-colorful: 5.5.1_sfoxds7t5ydpegc3knd667wn6m
+ react-dom: 17.0.2_react@17.0.2
+ react-popper-tooltip: 3.1.1_sfoxds7t5ydpegc3knd667wn6m
+ react-syntax-highlighter: 13.5.3_react@17.0.2
+ react-textarea-autosize: 8.3.3_udcsdvdzjr5ns727jqoeu7kyda
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/core-client/6.4.18_6vyqf2n3rwd4gcuudsutusvxn4:
+ resolution: {integrity: sha512-F9CqW31Mr9Qde90uqPorpkiS+P7UteKYmdHlV0o0czeWaL+MEhpY+3pRJuRIIjX5C7Vc89TvljMqs37Khakmdg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ webpack: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/channel-websocket': 6.4.18
+ '@storybook/client-api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/preview-web': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ airbnb-js-shims: 2.2.1
+ ansi-to-html: 0.6.15
+ core-js: 3.21.0
+ global: 4.4.0
+ lodash: 4.17.21
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ unfetch: 4.2.0
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/core-client/6.4.18_igr5dxqfwrldc53v35bxgmdn3e:
+ resolution: {integrity: sha512-F9CqW31Mr9Qde90uqPorpkiS+P7UteKYmdHlV0o0czeWaL+MEhpY+3pRJuRIIjX5C7Vc89TvljMqs37Khakmdg==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ webpack: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/channel-websocket': 6.4.18
+ '@storybook/client-api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/preview-web': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ airbnb-js-shims: 2.2.1
+ ansi-to-html: 0.6.15
+ core-js: 3.21.0
+ global: 4.4.0
+ lodash: 4.17.21
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ unfetch: 4.2.0
+ util-deprecate: 1.0.2
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@storybook/core-common/6.4.18_pjnqtmgajjo5adqladomtpq5hq:
+ resolution: {integrity: sha512-y4e43trNyQ3/v0Wpi240on7yVooUQvJBhJxOGEfcxAMRtcDa0ZCxHO4vAFX3k3voQOSmiXItXfJ1eGo/K+u0Fw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-proposal-class-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-decorators': 7.17.0_@babel+core@7.17.0
+ '@babel/plugin-proposal-export-default-from': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-nullish-coalescing-operator': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-object-rest-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-optional-chaining': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-proposal-private-methods': 7.16.11_@babel+core@7.17.0
+ '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.17.0
+ '@babel/plugin-transform-arrow-functions': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-block-scoping': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-classes': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-destructuring': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-for-of': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-parameters': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-shorthand-properties': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-spread': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-typescript': 7.16.7_@babel+core@7.17.0
+ '@babel/register': 7.17.0_@babel+core@7.17.0
+ '@storybook/node-logger': 6.4.18
+ '@storybook/semver': 7.3.2
+ '@types/node': 14.18.10
+ '@types/pretty-hrtime': 1.0.1
+ babel-loader: 8.2.3_u5fzby2crnk75aqgypigfhaoii
+ babel-plugin-macros: 3.1.0
+ babel-plugin-polyfill-corejs3: 0.1.7_@babel+core@7.17.0
+ chalk: 4.1.2
+ core-js: 3.21.0
+ express: 4.17.2
+ file-system-cache: 1.0.5
+ find-up: 5.0.0
+ fork-ts-checker-webpack-plugin: 6.5.0_q5wy7dh6g63ozjytk4pnktq6de
+ fs-extra: 9.1.0
+ glob: 7.2.0
+ handlebars: 4.7.7
+ interpret: 2.2.0
+ json5: 2.2.0
+ lazy-universal-dotenv: 3.0.1
+ picomatch: 2.3.1
+ pkg-dir: 5.0.0
+ pretty-hrtime: 1.0.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ resolve-from: 5.0.0
+ slash: 3.0.0
+ telejson: 5.3.3
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ transitivePeerDependencies:
+ - eslint
+ - supports-color
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/core-events/6.4.18:
+ resolution: {integrity: sha512-lCT3l0rFs6CuVpD8+mwmj1lUTomGErySTxi0KmVd2AWQj8kJL90EfS0jHSU5JIXScDvuwXDXLLmvMfqNU+zHdg==}
+ dependencies:
+ core-js: 3.21.0
+ dev: true
+
+ /@storybook/core-server/6.4.18_6tswtrdbbtx76xutylfphb2nta:
+ resolution: {integrity: sha512-7e2QUtD8/TE14P9X/xsBDMBbNVi/etTtMKKhsG2TG25daRz+6qadbM9tNP0YwvIDk452cNYJkjflV48mf5+ZEA==}
+ peerDependencies:
+ '@storybook/builder-webpack5': 6.4.18
+ '@storybook/manager-webpack5': 6.4.18
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ '@storybook/builder-webpack5':
+ optional: true
+ '@storybook/manager-webpack5':
+ optional: true
+ typescript:
+ optional: true
+ dependencies:
+ '@discoveryjs/json-ext': 0.5.6
+ '@storybook/builder-webpack4': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ '@storybook/core-client': 6.4.18_6vyqf2n3rwd4gcuudsutusvxn4
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/csf-tools': 6.4.18
+ '@storybook/manager-webpack4': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ '@storybook/node-logger': 6.4.18
+ '@storybook/semver': 7.3.2
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/node': 14.18.10
+ '@types/node-fetch': 2.5.12
+ '@types/pretty-hrtime': 1.0.1
+ '@types/webpack': 4.41.32
+ better-opn: 2.1.1
+ boxen: 5.1.2
+ chalk: 4.1.2
+ cli-table3: 0.6.1
+ commander: 6.2.1
+ compression: 1.7.4
+ core-js: 3.21.0
+ cpy: 8.1.2
+ detect-port: 1.3.0
+ express: 4.17.2
+ file-system-cache: 1.0.5
+ fs-extra: 9.1.0
+ globby: 11.1.0
+ ip: 1.1.5
+ lodash: 4.17.21
+ node-fetch: 2.6.7
+ pretty-hrtime: 1.0.3
+ prompts: 2.4.2
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ serve-favicon: 2.5.0
+ slash: 3.0.0
+ telejson: 5.3.3
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ util-deprecate: 1.0.2
+ watchpack: 2.3.1
+ webpack: 4.46.0
+ ws: 8.5.0
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - bufferutil
+ - encoding
+ - eslint
+ - supports-color
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/core-server/6.4.18_xi2bcknbnmjsry4xsg5z5mcrou:
+ resolution: {integrity: sha512-7e2QUtD8/TE14P9X/xsBDMBbNVi/etTtMKKhsG2TG25daRz+6qadbM9tNP0YwvIDk452cNYJkjflV48mf5+ZEA==}
+ peerDependencies:
+ '@storybook/builder-webpack5': 6.4.18
+ '@storybook/manager-webpack5': 6.4.18
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ '@storybook/builder-webpack5':
+ optional: true
+ '@storybook/manager-webpack5':
+ optional: true
+ typescript:
+ optional: true
+ dependencies:
+ '@discoveryjs/json-ext': 0.5.6
+ '@storybook/builder-webpack4': 6.4.18_xi2bcknbnmjsry4xsg5z5mcrou
+ '@storybook/core-client': 6.4.18_6vyqf2n3rwd4gcuudsutusvxn4
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/csf-tools': 6.4.18
+ '@storybook/manager-webpack4': 6.4.18_xi2bcknbnmjsry4xsg5z5mcrou
+ '@storybook/node-logger': 6.4.18
+ '@storybook/semver': 7.3.2
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/node': 14.18.10
+ '@types/node-fetch': 2.5.12
+ '@types/pretty-hrtime': 1.0.1
+ '@types/webpack': 4.41.32
+ better-opn: 2.1.1
+ boxen: 5.1.2
+ chalk: 4.1.2
+ cli-table3: 0.6.1
+ commander: 6.2.1
+ compression: 1.7.4
+ core-js: 3.21.0
+ cpy: 8.1.2
+ detect-port: 1.3.0
+ express: 4.17.2
+ file-system-cache: 1.0.5
+ fs-extra: 9.1.0
+ globby: 11.1.0
+ ip: 1.1.5
+ lodash: 4.17.21
+ node-fetch: 2.6.7
+ pretty-hrtime: 1.0.3
+ prompts: 2.4.2
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ serve-favicon: 2.5.0
+ slash: 3.0.0
+ telejson: 5.3.3
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ util-deprecate: 1.0.2
+ watchpack: 2.3.1
+ webpack: 4.46.0
+ ws: 8.5.0
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - bufferutil
+ - encoding
+ - eslint
+ - supports-color
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/core/6.4.18_e7ynmpxt2x5sijdz5wrml3il4q:
+ resolution: {integrity: sha512-7DTMAEXiBIwd1jgalbsZiXCiS2Be9MKKsr6GQdf3WaBm0WYV067oN9jcUY5IgNtJX06arT4Ykp+CGG/TR+sLlw==}
+ peerDependencies:
+ '@storybook/builder-webpack5': 6.4.18
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ webpack: '*'
+ peerDependenciesMeta:
+ '@storybook/builder-webpack5':
+ optional: true
+ typescript:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@storybook/core-client': 6.4.18_6vyqf2n3rwd4gcuudsutusvxn4
+ '@storybook/core-server': 6.4.18_6tswtrdbbtx76xutylfphb2nta
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ typescript: 4.5.5
+ webpack: 4.46.0
+ transitivePeerDependencies:
+ - '@storybook/manager-webpack5'
+ - '@types/react'
+ - acorn
+ - bufferutil
+ - encoding
+ - eslint
+ - supports-color
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/core/6.4.18_xi2bcknbnmjsry4xsg5z5mcrou:
+ resolution: {integrity: sha512-7DTMAEXiBIwd1jgalbsZiXCiS2Be9MKKsr6GQdf3WaBm0WYV067oN9jcUY5IgNtJX06arT4Ykp+CGG/TR+sLlw==}
+ peerDependencies:
+ '@storybook/builder-webpack5': 6.4.18
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ webpack: '*'
+ peerDependenciesMeta:
+ '@storybook/builder-webpack5':
+ optional: true
+ typescript:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@storybook/core-client': 6.4.18_igr5dxqfwrldc53v35bxgmdn3e
+ '@storybook/core-server': 6.4.18_xi2bcknbnmjsry4xsg5z5mcrou
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ typescript: 4.5.5
+ transitivePeerDependencies:
+ - '@storybook/manager-webpack5'
+ - '@types/react'
+ - acorn
+ - bufferutil
+ - encoding
+ - eslint
+ - supports-color
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/csf-tools/6.4.18:
+ resolution: {integrity: sha512-KtwxKrkndEyvyAiBliI6m4yMFMvnyI4fOjU8t1qCit/0gjutOF5JxmmZ+H8FSI5dIyibEOzQmzHe0MyStAjCEQ==}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/generator': 7.17.0
+ '@babel/parser': 7.17.0
+ '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-env': 7.16.11_@babel+core@7.17.0
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ '@mdx-js/mdx': 1.6.22
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ core-js: 3.21.0
+ fs-extra: 9.1.0
+ global: 4.4.0
+ js-string-escape: 1.0.1
+ lodash: 4.17.21
+ prettier: 2.3.0
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@storybook/csf/0.0.2--canary.87bc651.0:
+ resolution: {integrity: sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw==}
+ dependencies:
+ lodash: 4.17.21
+ dev: true
+
+ /@storybook/manager-webpack4/6.4.18_6tswtrdbbtx76xutylfphb2nta:
+ resolution: {integrity: sha512-6oX1KrIJBoY4vdZiMftJNusv+Bm8pegVjdJ+aZcbr/41x7ufP3tu5UKebEXDH0UURXtLw0ffl+OgojewGdpC1Q==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-transform-template-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/core-client': 6.4.18_6vyqf2n3rwd4gcuudsutusvxn4
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/node-logger': 6.4.18
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@types/node': 14.18.10
+ '@types/webpack': 4.41.32
+ babel-loader: 8.2.3_u5fzby2crnk75aqgypigfhaoii
+ case-sensitive-paths-webpack-plugin: 2.4.0
+ chalk: 4.1.2
+ core-js: 3.21.0
+ css-loader: 3.6.0_webpack@4.46.0
+ express: 4.17.2
+ file-loader: 6.2.0_webpack@4.46.0
+ file-system-cache: 1.0.5
+ find-up: 5.0.0
+ fs-extra: 9.1.0
+ html-webpack-plugin: 4.5.2_webpack@4.46.0
+ node-fetch: 2.6.7
+ pnp-webpack-plugin: 1.6.4_typescript@4.5.5
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ read-pkg-up: 7.0.1
+ regenerator-runtime: 0.13.9
+ resolve-from: 5.0.0
+ style-loader: 1.3.0_webpack@4.46.0
+ telejson: 5.3.3
+ terser-webpack-plugin: 4.2.3_webpack@4.46.0
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ webpack-dev-middleware: 3.7.3_webpack@4.46.0
+ webpack-virtual-modules: 0.2.2
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - encoding
+ - eslint
+ - supports-color
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/manager-webpack4/6.4.18_xi2bcknbnmjsry4xsg5z5mcrou:
+ resolution: {integrity: sha512-6oX1KrIJBoY4vdZiMftJNusv+Bm8pegVjdJ+aZcbr/41x7ufP3tu5UKebEXDH0UURXtLw0ffl+OgojewGdpC1Q==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-transform-template-literals': 7.16.7_@babel+core@7.17.0
+ '@babel/preset-react': 7.16.7_@babel+core@7.17.0
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/core-client': 6.4.18_6vyqf2n3rwd4gcuudsutusvxn4
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/node-logger': 6.4.18
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/ui': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@types/node': 14.18.10
+ '@types/webpack': 4.41.32
+ babel-loader: 8.2.3_u5fzby2crnk75aqgypigfhaoii
+ case-sensitive-paths-webpack-plugin: 2.4.0
+ chalk: 4.1.2
+ core-js: 3.21.0
+ css-loader: 3.6.0_webpack@4.46.0
+ express: 4.17.2
+ file-loader: 6.2.0_webpack@4.46.0
+ file-system-cache: 1.0.5
+ find-up: 5.0.0
+ fs-extra: 9.1.0
+ html-webpack-plugin: 4.5.2_webpack@4.46.0
+ node-fetch: 2.6.7
+ pnp-webpack-plugin: 1.6.4_typescript@4.5.5
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ read-pkg-up: 7.0.1
+ regenerator-runtime: 0.13.9
+ resolve-from: 5.0.0
+ style-loader: 1.3.0_webpack@4.46.0
+ telejson: 5.3.3
+ terser-webpack-plugin: 4.2.3_acorn@7.4.1+webpack@4.46.0
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy
+ util-deprecate: 1.0.2
+ webpack: 4.46.0
+ webpack-dev-middleware: 3.7.3_webpack@4.46.0
+ webpack-virtual-modules: 0.2.2
+ transitivePeerDependencies:
+ - '@types/react'
+ - acorn
+ - encoding
+ - eslint
+ - supports-color
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ dev: true
+
+ /@storybook/node-logger/6.4.18:
+ resolution: {integrity: sha512-wY1qt4XOXtJJdQ+DrO3RijtiwVFqWuWetvCY4RV4lge5yk0FP5Q+MTpmjazYodAvGPUIP0LK9bvEDLwXa0JUfw==}
+ dependencies:
+ '@types/npmlog': 4.1.4
+ chalk: 4.1.2
+ core-js: 3.21.0
+ npmlog: 5.0.1
+ pretty-hrtime: 1.0.3
+ dev: true
+
+ /@storybook/postinstall/6.4.18:
+ resolution: {integrity: sha512-eS91pFvnuC1rFXMhDj3smXJ1OTwt2K5HS1+QtWi3NuE4XRvtdwDA/wZ4KQJWZszWuY/k2HgFfJYbQEumJxVrCQ==}
+ dependencies:
+ core-js: 3.21.0
+ dev: true
+
+ /@storybook/preview-web/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-0x64uLdGhIOk9hIuRKTHFdP7+iEHyjAOi5U4jtwqFfDtG4n4zxEGSsUWij7pTR2rAYf7g2NWIbAM7qb1AqqcLQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channel-postmessage': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ ansi-to-html: 0.6.15
+ core-js: 3.21.0
+ global: 4.4.0
+ lodash: 4.17.21
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ synchronous-promise: 2.0.15
+ ts-dedent: 2.2.0
+ unfetch: 4.2.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /@storybook/react-docgen-typescript-plugin/1.0.2-canary.253f8c1.0_ulm5vdg34btfvcm7osvrzev2ve:
+ resolution: {integrity: sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==}
+ peerDependencies:
+ typescript: '>= 3.x'
+ webpack: '>= 4'
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ debug: 4.3.3
+ endent: 2.1.0
+ find-cache-dir: 3.3.2
+ flat-cache: 3.0.4
+ micromatch: 4.0.4
+ react-docgen-typescript: 2.2.2_typescript@4.5.5
+ tslib: 2.3.1
+ typescript: 4.5.5
+ webpack: 4.46.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@storybook/react/6.4.18_6tswtrdbbtx76xutylfphb2nta:
+ resolution: {integrity: sha512-dKxwsvJEGTm/aNIJSJMI4MImsI4EhmBa42FtwVvtFkrokuMf2CsmTJsaaAh+1or9SKGTiFuGsYDGhX5joE3XUQ==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ peerDependencies:
+ '@babel/core': ^7.11.5
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ typescript: '*'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ typescript:
+ optional: true
+ dependencies:
+ '@babel/preset-flow': 7.16.7
+ '@babel/preset-react': 7.16.7
+ '@pmmmwh/react-refresh-webpack-plugin': 0.5.4_a3gyllrqvxpec3fpybsrposvju
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/core': 6.4.18_e7ynmpxt2x5sijdz5wrml3il4q
+ '@storybook/core-common': 6.4.18_pjnqtmgajjo5adqladomtpq5hq
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ '@storybook/node-logger': 6.4.18
+ '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0_ulm5vdg34btfvcm7osvrzev2ve
+ '@storybook/semver': 7.3.2
+ '@storybook/store': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@types/webpack-env': 1.16.3
+ babel-plugin-add-react-displayname: 0.0.5
+ babel-plugin-named-asset-import: 0.3.8
+ babel-plugin-react-docgen: 4.2.1
+ core-js: 3.21.0
+ global: 4.4.0
+ lodash: 4.17.21
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-refresh: 0.11.0
+ read-pkg-up: 7.0.1
+ regenerator-runtime: 0.13.9
+ ts-dedent: 2.2.0
+ typescript: 4.5.5
+ webpack: 4.46.0
+ transitivePeerDependencies:
+ - '@storybook/builder-webpack5'
+ - '@storybook/manager-webpack5'
+ - '@types/react'
+ - '@types/webpack'
+ - acorn
+ - bufferutil
+ - encoding
+ - eslint
+ - sockjs-client
+ - supports-color
+ - type-fest
+ - utf-8-validate
+ - vue-template-compiler
+ - webpack-cli
+ - webpack-command
+ - webpack-dev-server
+ - webpack-hot-middleware
+ - webpack-plugin-serve
+ dev: true
+
+ /@storybook/router/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-itvSWHhG1X/NV1sMlwP1qKtF0HfiIaAHImr0LwQ2K2F6/CI11W68dJAs4WBUdwzA0+H0Joyu/2a/6mCQHcee1A==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/client-logger': 6.4.18
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ history: 5.0.0
+ lodash: 4.17.21
+ memoizerific: 1.11.3
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-router: 6.2.1_react@17.0.2
+ react-router-dom: 6.2.1_sfoxds7t5ydpegc3knd667wn6m
+ ts-dedent: 2.2.0
+ dev: true
+
+ /@storybook/semver/7.3.2:
+ resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ core-js: 3.21.0
+ find-up: 4.1.0
+ dev: true
+
+ /@storybook/source-loader/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-sjKvngCCYDbBwjjFTjAXO6VsAzKkjy+UctseeULXxEN3cKIsz/R3y7MrrN9yBrwyYcn0k3pqa9d9e3gE+Jv2Tw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ core-js: 3.21.0
+ estraverse: 5.3.0
+ global: 4.4.0
+ loader-utils: 2.0.2
+ lodash: 4.17.21
+ prettier: 2.3.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ dev: true
+
+ /@storybook/store/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-Vl5oCs/9fP1gUgfgMHTBsnYbwAAoaR93/bzDBeOHI3eo5x9uzzJtA4zcRmEiKahR/wgwGacpWy90JrIX469PDQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/client-logger': 6.4.18
+ '@storybook/core-events': 6.4.18
+ '@storybook/csf': 0.0.2--canary.87bc651.0
+ core-js: 3.21.0
+ fast-deep-equal: 3.1.3
+ global: 4.4.0
+ lodash: 4.17.21
+ memoizerific: 1.11.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ regenerator-runtime: 0.13.9
+ slash: 3.0.0
+ stable: 0.1.8
+ synchronous-promise: 2.0.15
+ ts-dedent: 2.2.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /@storybook/theming/6.4.18_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-1o0w2eP+8sXUesdtXpZR4Yvayp1h3xvK7l9+wuHh+1uCy+EvD5UI9d1HvU5kt5fw7XAJJcInaVAmyAbpwct0TQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@emotion/core': 10.3.1_react@17.0.2
+ '@emotion/is-prop-valid': 0.8.8
+ '@emotion/styled': 10.3.0_gfrer23gq2rp2t523t6qbxrx6m
+ '@storybook/client-logger': 6.4.18
+ core-js: 3.21.0
+ deep-object-diff: 1.1.7
+ emotion-theming: 10.3.0_gfrer23gq2rp2t523t6qbxrx6m
+ global: 4.4.0
+ memoizerific: 1.11.3
+ polished: 4.1.4
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ resolve-from: 5.0.0
+ ts-dedent: 2.2.0
+ dev: true
+
+ /@storybook/ui/6.4.18_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-f2ckcLvEyA9CRcu6W2I2CyEbUnU4j3h5Nz0N40YZ2uRMVNQY2xPywAFZVySZIJAaum/5phDfnOD0Feap/Q6zVQ==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@emotion/core': 10.3.1_react@17.0.2
+ '@storybook/addons': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/api': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/channels': 6.4.18
+ '@storybook/client-logger': 6.4.18
+ '@storybook/components': 6.4.18_xd63vgjm47lzoal5ybyqmsdesy
+ '@storybook/core-events': 6.4.18
+ '@storybook/router': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@storybook/semver': 7.3.2
+ '@storybook/theming': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ copy-to-clipboard: 3.3.1
+ core-js: 3.21.0
+ core-js-pure: 3.21.0
+ downshift: 6.1.7_react@17.0.2
+ emotion-theming: 10.3.0_gfrer23gq2rp2t523t6qbxrx6m
+ fuse.js: 3.6.1
+ global: 4.4.0
+ lodash: 4.17.21
+ markdown-to-jsx: 7.1.6_react@17.0.2
+ memoizerific: 1.11.3
+ polished: 4.1.4
+ qs: 6.10.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-draggable: 4.4.4_sfoxds7t5ydpegc3knd667wn6m
+ react-helmet-async: 1.2.2_sfoxds7t5ydpegc3knd667wn6m
+ react-sizeme: 3.0.2
+ regenerator-runtime: 0.13.9
+ resolve-from: 5.0.0
+ store2: 2.13.1
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /@svgr/babel-plugin-add-jsx-attribute/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-MdPdhdWLtQsjd29Wa4pABdhWbaRMACdM1h31BY+c6FghTZqNGT7pEYdBoaGeKtdTOBC/XNFQaKVj+r/Ei2ryWA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-remove-jsx-attribute/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-aVdtfx9jlaaxc3unA6l+M9YRnKIZjOhQPthLKqmTXC8UVkBLDRGwPKo+r8n3VZN8B34+yVajzPTZ+ptTSuZZCw==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-remove-jsx-empty-expression/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-Ccj42ApsePD451AZJJf1QzTD1B/BOU392URJTeXFxSK709i0KUsGtbwyiqsKu7vsYxpTM0IA5clAKDyf9RCZyA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-replace-jsx-attribute-value/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-88V26WGyt1Sfd1emBYmBJRWMmgarrExpKNVmI9vVozha4kqs6FzQJ/Kp5+EYli1apgX44518/0+t9+NU36lThQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-svg-dynamic-title/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-F7YXNLfGze+xv0KMQxrl2vkNbI9kzT9oDK55/kUuymh1ACyXkMV+VZWX1zEhSTfEKh7VkHVZGmVtHg8eTZ6PRg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-svg-em-dimensions/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-+rghFXxdIqJNLQK08kwPBD3Z22/0b2tEZ9lKiL/yTfuyj1wW8HUXu4bo/XkogATIYuXSghVQOOCwURXzHGKyZA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-transform-react-native-svg/6.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-VaphyHZ+xIKv5v0K0HCzyfAaLhPGJXSk2HkpYfXIOKb7DjLBv0soHDxNv6X0vr2titsxE7klb++u7iOf7TSrFQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-plugin-transform-svg-component/6.2.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-bhYIpsORb++wpsp91fymbFkf09Z/YEKR0DnFjxvN+8JHeCUD2unnh18jIMKnDJTWtvpTaGYPXELVe4OOzFI0xg==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /@svgr/babel-preset/6.2.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-4WQNY0J71JIaL03DRn0vLiz87JXx0b9dYm2aA8XHlQJQoixMl4r/soYHm8dsaJZ3jWtkCiOYy48dp9izvXhDkQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@svgr/babel-plugin-add-jsx-attribute': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-remove-jsx-attribute': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-remove-jsx-empty-expression': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-replace-jsx-attribute-value': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-svg-dynamic-title': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-svg-em-dimensions': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-transform-react-native-svg': 6.0.0_@babel+core@7.17.0
+ '@svgr/babel-plugin-transform-svg-component': 6.2.0_@babel+core@7.17.0
+ dev: true
+
+ /@svgr/core/6.2.1:
+ resolution: {integrity: sha512-NWufjGI2WUyrg46mKuySfviEJ6IxHUOm/8a3Ph38VCWSp+83HBraCQrpEM3F3dB6LBs5x8OElS8h3C0oOJaJAA==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@svgr/plugin-jsx': 6.2.1_@svgr+core@6.2.1
+ camelcase: 6.3.0
+ cosmiconfig: 7.0.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@svgr/hast-util-to-babel-ast/6.2.1:
+ resolution: {integrity: sha512-pt7MMkQFDlWJVy9ULJ1h+hZBDGFfSCwlBNW1HkLnVi7jUhyEXUaGYWi1x6bM2IXuAR9l265khBT4Av4lPmaNLQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@babel/types': 7.17.0
+ entities: 3.0.1
+ dev: true
+
+ /@svgr/plugin-jsx/6.2.1_@svgr+core@6.2.1:
+ resolution: {integrity: sha512-u+MpjTsLaKo6r3pHeeSVsh9hmGRag2L7VzApWIaS8imNguqoUwDq/u6U/NDmYs/KAsrmtBjOEaAAPbwNGXXp1g==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@svgr/core': ^6.0.0
+ dependencies:
+ '@babel/core': 7.17.0
+ '@svgr/babel-preset': 6.2.0_@babel+core@7.17.0
+ '@svgr/core': 6.2.1
+ '@svgr/hast-util-to-babel-ast': 6.2.1
+ svg-parser: 2.0.4
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@tsndr/cloudflare-worker-jwt/1.1.5:
+ resolution: {integrity: sha512-+q0siASepCuFboIQrdgykBIESzttfWz3qXQ8Lx36mjMJpaS1XgErRvQ2+BPU8miXlBbslbxThRaMCW2o8nFtug==}
+ dev: false
+
+ /@types/color-convert/2.0.0:
+ resolution: {integrity: sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==}
+ dependencies:
+ '@types/color-name': 1.1.1
+ dev: true
+
+ /@types/color-name/1.1.1:
+ resolution: {integrity: sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==}
+ dev: true
+
+ /@types/d3-array/3.0.2:
+ resolution: {integrity: sha512-5mjGjz6XOXKOCdTajXTZ/pMsg236RdiwKPrRPWAEf/2S/+PzwY+LLYShUpeysWaMvsdS7LArh6GdUefoxpchsQ==}
+ dev: true
+
+ /@types/d3-axis/3.0.1:
+ resolution: {integrity: sha512-zji/iIbdd49g9WN0aIsGcwcTBUkgLsCSwB+uH+LPVDAiKWENMtI3cJEWt+7/YYwelMoZmbBfzA3qCdrZ2XFNnw==}
+ dependencies:
+ '@types/d3-selection': 3.0.2
+ dev: true
+
+ /@types/d3-brush/3.0.1:
+ resolution: {integrity: sha512-B532DozsiTuQMHu2YChdZU0qsFJSio3Q6jmBYGYNp3gMDzBmuFFgPt9qKA4VYuLZMp4qc6eX7IUFUEsvHiXZAw==}
+ dependencies:
+ '@types/d3-selection': 3.0.2
+ dev: true
+
+ /@types/d3-chord/3.0.1:
+ resolution: {integrity: sha512-eQfcxIHrg7V++W8Qxn6QkqBNBokyhdWSAS73AbkbMzvLQmVVBviknoz2SRS/ZJdIOmhcmmdCRE/NFOm28Z1AMw==}
+ dev: true
+
+ /@types/d3-color/3.0.2:
+ resolution: {integrity: sha512-WVx6zBiz4sWlboCy7TCgjeyHpNjMsoF36yaagny1uXfbadc9f+5BeBf7U+lRmQqY3EHbGQpP8UdW8AC+cywSwQ==}
+ dev: true
+
+ /@types/d3-contour/3.0.1:
+ resolution: {integrity: sha512-C3zfBrhHZvrpAAK3YXqLWVAGo87A4SvJ83Q/zVJ8rFWJdKejUnDYaWZPkA8K84kb2vDA/g90LTQAz7etXcgoQQ==}
+ dependencies:
+ '@types/d3-array': 3.0.2
+ '@types/geojson': 7946.0.8
+ dev: true
+
+ /@types/d3-delaunay/6.0.0:
+ resolution: {integrity: sha512-iGm7ZaGLq11RK3e69VeMM6Oqj2SjKUB9Qhcyd1zIcqn2uE8w9GFB445yCY46NOQO3ByaNyktX1DK+Etz7ZaX+w==}
+ dev: true
+
+ /@types/d3-dispatch/3.0.1:
+ resolution: {integrity: sha512-NhxMn3bAkqhjoxabVJWKryhnZXXYYVQxaBnbANu0O94+O/nX9qSjrA1P1jbAQJxJf+VC72TxDX/YJcKue5bRqw==}
+ dev: true
+
+ /@types/d3-drag/3.0.1:
+ resolution: {integrity: sha512-o1Va7bLwwk6h03+nSM8dpaGEYnoIG19P0lKqlic8Un36ymh9NSkNFX1yiXMKNMx8rJ0Kfnn2eovuFaL6Jvj0zA==}
+ dependencies:
+ '@types/d3-selection': 3.0.2
+ dev: true
+
+ /@types/d3-dsv/3.0.0:
+ resolution: {integrity: sha512-o0/7RlMl9p5n6FQDptuJVMxDf/7EDEv2SYEO/CwdG2tr1hTfUVi0Iavkk2ax+VpaQ/1jVhpnj5rq1nj8vwhn2A==}
+ dev: true
+
+ /@types/d3-ease/3.0.0:
+ resolution: {integrity: sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==}
+ dev: true
+
+ /@types/d3-fetch/3.0.1:
+ resolution: {integrity: sha512-toZJNOwrOIqz7Oh6Q7l2zkaNfXkfR7mFSJvGvlD/Ciq/+SQ39d5gynHJZ/0fjt83ec3WL7+u3ssqIijQtBISsw==}
+ dependencies:
+ '@types/d3-dsv': 3.0.0
+ dev: true
+
+ /@types/d3-force/3.0.3:
+ resolution: {integrity: sha512-z8GteGVfkWJMKsx6hwC3SiTSLspL98VNpmvLpEFJQpZPq6xpA1I8HNBDNSpukfK0Vb0l64zGFhzunLgEAcBWSA==}
+ dev: true
+
+ /@types/d3-format/3.0.1:
+ resolution: {integrity: sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==}
+ dev: true
+
+ /@types/d3-geo/3.0.2:
+ resolution: {integrity: sha512-DbqK7MLYA8LpyHQfv6Klz0426bQEf7bRTvhMy44sNGVyZoWn//B0c+Qbeg8Osi2Obdc9BLLXYAKpyWege2/7LQ==}
+ dependencies:
+ '@types/geojson': 7946.0.8
+ dev: true
+
+ /@types/d3-hierarchy/3.0.2:
+ resolution: {integrity: sha512-+krnrWOZ+aQB6v+E+jEkmkAx9HvsNAD+1LCD0vlBY3t+HwjKnsBFbpVLx6WWzDzCIuiTWdAxXMEnGnVXpB09qQ==}
+ dev: true
+
+ /@types/d3-interpolate/3.0.1:
+ resolution: {integrity: sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==}
+ dependencies:
+ '@types/d3-color': 3.0.2
+ dev: true
+
+ /@types/d3-path/3.0.0:
+ resolution: {integrity: sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==}
+ dev: true
+
+ /@types/d3-polygon/3.0.0:
+ resolution: {integrity: sha512-D49z4DyzTKXM0sGKVqiTDTYr+DHg/uxsiWDAkNrwXYuiZVd9o9wXZIo+YsHkifOiyBkmSWlEngHCQme54/hnHw==}
+ dev: true
+
+ /@types/d3-quadtree/3.0.2:
+ resolution: {integrity: sha512-QNcK8Jguvc8lU+4OfeNx+qnVy7c0VrDJ+CCVFS9srBo2GL9Y18CnIxBdTF3v38flrGy5s1YggcoAiu6s4fLQIw==}
+ dev: true
+
+ /@types/d3-random/3.0.1:
+ resolution: {integrity: sha512-IIE6YTekGczpLYo/HehAy3JGF1ty7+usI97LqraNa8IiDur+L44d0VOjAvFQWJVdZOJHukUJw+ZdZBlgeUsHOQ==}
+ dev: true
+
+ /@types/d3-scale-chromatic/3.0.0:
+ resolution: {integrity: sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==}
+ dev: true
+
+ /@types/d3-scale/4.0.2:
+ resolution: {integrity: sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==}
+ dependencies:
+ '@types/d3-time': 3.0.0
+ dev: true
+
+ /@types/d3-selection/3.0.2:
+ resolution: {integrity: sha512-d29EDd0iUBrRoKhPndhDY6U/PYxOWqgIZwKTooy2UkBfU7TNZNpRho0yLWPxlatQrFWk2mnTu71IZQ4+LRgKlQ==}
+ dev: true
+
+ /@types/d3-shape/3.0.2:
+ resolution: {integrity: sha512-5+ButCmIfNX8id5seZ7jKj3igdcxx+S9IDBiT35fQGTLZUfkFgTv+oBH34xgeoWDKpWcMITSzBILWQtBoN5Piw==}
+ dependencies:
+ '@types/d3-path': 3.0.0
+ dev: true
+
+ /@types/d3-time-format/4.0.0:
+ resolution: {integrity: sha512-yjfBUe6DJBsDin2BMIulhSHmr5qNR5Pxs17+oW4DoVPyVIXZ+m6bs7j1UVKP08Emv6jRmYrYqxYzO63mQxy1rw==}
+ dev: true
+
+ /@types/d3-time/3.0.0:
+ resolution: {integrity: sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==}
+ dev: true
+
+ /@types/d3-timer/3.0.0:
+ resolution: {integrity: sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==}
+ dev: true
+
+ /@types/d3-transition/3.0.1:
+ resolution: {integrity: sha512-Sv4qEI9uq3bnZwlOANvYK853zvpdKEm1yz9rcc8ZTsxvRklcs9Fx4YFuGA3gXoQN/c/1T6QkVNjhaRO/cWj94g==}
+ dependencies:
+ '@types/d3-selection': 3.0.2
+ dev: true
+
+ /@types/d3-zoom/3.0.1:
+ resolution: {integrity: sha512-7s5L9TjfqIYQmQQEUcpMAcBOahem7TRoSO/+Gkz02GbMVuULiZzjF2BOdw291dbO2aNon4m2OdFsRGaCq2caLQ==}
+ dependencies:
+ '@types/d3-interpolate': 3.0.1
+ '@types/d3-selection': 3.0.2
+ dev: true
+
+ /@types/d3/7.1.0:
+ resolution: {integrity: sha512-gYWvgeGjEl+zmF8c+U1RNIKqe7sfQwIXeLXO5Os72TjDjCEtgpvGBvZ8dXlAuSS1m6B90Y1Uo6Bm36OGR/OtCA==}
+ dependencies:
+ '@types/d3-array': 3.0.2
+ '@types/d3-axis': 3.0.1
+ '@types/d3-brush': 3.0.1
+ '@types/d3-chord': 3.0.1
+ '@types/d3-color': 3.0.2
+ '@types/d3-contour': 3.0.1
+ '@types/d3-delaunay': 6.0.0
+ '@types/d3-dispatch': 3.0.1
+ '@types/d3-drag': 3.0.1
+ '@types/d3-dsv': 3.0.0
+ '@types/d3-ease': 3.0.0
+ '@types/d3-fetch': 3.0.1
+ '@types/d3-force': 3.0.3
+ '@types/d3-format': 3.0.1
+ '@types/d3-geo': 3.0.2
+ '@types/d3-hierarchy': 3.0.2
+ '@types/d3-interpolate': 3.0.1
+ '@types/d3-path': 3.0.0
+ '@types/d3-polygon': 3.0.0
+ '@types/d3-quadtree': 3.0.2
+ '@types/d3-random': 3.0.1
+ '@types/d3-scale': 4.0.2
+ '@types/d3-scale-chromatic': 3.0.0
+ '@types/d3-selection': 3.0.2
+ '@types/d3-shape': 3.0.2
+ '@types/d3-time': 3.0.0
+ '@types/d3-time-format': 4.0.0
+ '@types/d3-timer': 3.0.0
+ '@types/d3-transition': 3.0.1
+ '@types/d3-zoom': 3.0.1
+ dev: true
+
+ /@types/geojson/7946.0.8:
+ resolution: {integrity: sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==}
+ dev: true
+
+ /@types/glob/7.2.0:
+ resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
+ dependencies:
+ '@types/minimatch': 3.0.5
+ '@types/node': 17.0.16
+ dev: true
+
+ /@types/graceful-fs/4.1.5:
+ resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==}
+ dependencies:
+ '@types/node': 17.0.16
+ dev: true
+
+ /@types/hast/2.3.4:
+ resolution: {integrity: sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: true
+
+ /@types/hoist-non-react-statics/3.3.1:
+ resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
+ dependencies:
+ '@types/react': 17.0.39
+ hoist-non-react-statics: 3.3.2
+ dev: false
+
+ /@types/html-minifier-terser/5.1.2:
+ resolution: {integrity: sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==}
+ dev: true
+
+ /@types/is-function/1.0.1:
+ resolution: {integrity: sha512-A79HEEiwXTFtfY+Bcbo58M2GRYzCr9itHWzbzHVFNEYCcoU/MMGwYYf721gBrnhpj1s6RGVVha/IgNFnR0Iw/Q==}
+ dev: true
+
+ /@types/istanbul-lib-coverage/2.0.4:
+ resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==}
+ dev: true
+
+ /@types/istanbul-lib-report/3.0.0:
+ resolution: {integrity: sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==}
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.4
+ dev: true
+
+ /@types/istanbul-reports/3.0.1:
+ resolution: {integrity: sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==}
+ dependencies:
+ '@types/istanbul-lib-report': 3.0.0
+ dev: true
+
+ /@types/json-schema/7.0.9:
+ resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==}
+ dev: true
+
+ /@types/mdast/3.0.10:
+ resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: true
+
+ /@types/minimatch/3.0.5:
+ resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==}
+ dev: true
+
+ /@types/node-fetch/2.5.12:
+ resolution: {integrity: sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==}
+ dependencies:
+ '@types/node': 14.18.10
+ form-data: 3.0.1
+ dev: true
+
+ /@types/node/14.18.10:
+ resolution: {integrity: sha512-6iihJ/Pp5fsFJ/aEDGyvT4pHGmCpq7ToQ/yf4bl5SbVAvwpspYJ+v3jO7n8UyjhQVHTy+KNszOozDdv+O6sovQ==}
+ dev: true
+
+ /@types/node/17.0.16:
+ resolution: {integrity: sha512-ydLaGVfQOQ6hI1xK2A5nVh8bl0OGoIfYMxPWHqqYe9bTkWCfqiVvZoh2I/QF2sNSkZzZyROBoTefIEI+PB6iIA==}
+ dev: true
+
+ /@types/normalize-package-data/2.4.1:
+ resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==}
+ dev: true
+
+ /@types/npmlog/4.1.4:
+ resolution: {integrity: sha512-WKG4gTr8przEZBiJ5r3s8ZIAoMXNbOgQ+j/d5O4X3x6kZJRLNvyUJuUK/KoG3+8BaOHPhp2m7WC6JKKeovDSzQ==}
+ dev: true
+
+ /@types/overlayscrollbars/1.12.1:
+ resolution: {integrity: sha512-V25YHbSoKQN35UasHf0EKD9U2vcmexRSp78qa8UglxFH8H3D+adEa9zGZwrqpH4TdvqeMrgMqVqsLB4woAryrQ==}
+ dev: true
+
+ /@types/parse-json/4.0.0:
+ resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==}
+ dev: true
+
+ /@types/parse5/5.0.3:
+ resolution: {integrity: sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==}
+ dev: true
+
+ /@types/pretty-hrtime/1.0.1:
+ resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
+ dev: true
+
+ /@types/prop-types/15.7.4:
+ resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==}
+
+ /@types/qs/6.9.7:
+ resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==}
+ dev: true
+
+ /@types/react-dom/17.0.11:
+ resolution: {integrity: sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==}
+ dependencies:
+ '@types/react': 17.0.39
+ dev: true
+
+ /@types/react-redux/7.1.22:
+ resolution: {integrity: sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==}
+ dependencies:
+ '@types/hoist-non-react-statics': 3.3.1
+ '@types/react': 17.0.39
+ hoist-non-react-statics: 3.3.2
+ redux: 4.1.2
+ dev: false
+
+ /@types/react-syntax-highlighter/11.0.5:
+ resolution: {integrity: sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==}
+ dependencies:
+ '@types/react': 17.0.39
+ dev: true
+
+ /@types/react-table/6.8.9:
+ resolution: {integrity: sha512-fVQXjy/EYDbgraScgjDONA291McKqGrw0R0NeK639fx2bS4T19TnXMjg3FjOPlkI3qYTQtFTPADlRYysaQIMpA==}
+ dependencies:
+ '@types/react': 17.0.39
+ dev: false
+
+ /@types/react-transition-group/4.4.4:
+ resolution: {integrity: sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==}
+ dependencies:
+ '@types/react': 17.0.39
+ dev: false
+
+ /@types/react/17.0.39:
+ resolution: {integrity: sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==}
+ dependencies:
+ '@types/prop-types': 15.7.4
+ '@types/scheduler': 0.16.2
+ csstype: 3.0.10
+
+ /@types/scheduler/0.16.2:
+ resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
+
+ /@types/sinonjs__fake-timers/8.1.1:
+ resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==}
+ dev: true
+
+ /@types/sizzle/2.3.3:
+ resolution: {integrity: sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==}
+ dev: true
+
+ /@types/source-list-map/0.1.2:
+ resolution: {integrity: sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==}
+ dev: true
+
+ /@types/symlink-or-copy/1.2.0:
+ resolution: {integrity: sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg==}
+ dev: true
+
+ /@types/tapable/1.0.8:
+ resolution: {integrity: sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==}
+ dev: true
+
+ /@types/uglify-js/3.13.1:
+ resolution: {integrity: sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==}
+ dependencies:
+ source-map: 0.6.1
+ dev: true
+
+ /@types/unist/2.0.6:
+ resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
+ dev: true
+
+ /@types/webpack-env/1.16.3:
+ resolution: {integrity: sha512-9gtOPPkfyNoEqCQgx4qJKkuNm/x0R2hKR7fdl7zvTJyHnIisuE/LfvXOsYWL0o3qq6uiBnKZNNNzi3l0y/X+xw==}
+ dev: true
+
+ /@types/webpack-sources/3.2.0:
+ resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==}
+ dependencies:
+ '@types/node': 14.18.10
+ '@types/source-list-map': 0.1.2
+ source-map: 0.7.3
+ dev: true
+
+ /@types/webpack/4.41.32:
+ resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==}
+ dependencies:
+ '@types/node': 14.18.10
+ '@types/tapable': 1.0.8
+ '@types/uglify-js': 3.13.1
+ '@types/webpack-sources': 3.2.0
+ anymatch: 3.1.2
+ source-map: 0.6.1
+ dev: true
+
+ /@types/yargs-parser/20.2.1:
+ resolution: {integrity: sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==}
+ dev: true
+
+ /@types/yargs/15.0.14:
+ resolution: {integrity: sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==}
+ dependencies:
+ '@types/yargs-parser': 20.2.1
+ dev: true
+
+ /@types/yauzl/2.9.2:
+ resolution: {integrity: sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA==}
+ requiresBuild: true
+ dependencies:
+ '@types/node': 17.0.16
+ dev: true
+ optional: true
+
+ /@typescript-eslint/parser/5.11.0_txwvkng2juu2h6yeaibqmql3uy:
+ resolution: {integrity: sha512-x0DCjetHZYBRovJdr3U0zG9OOdNXUaFLJ82ehr1AlkArljJuwEsgnud+Q7umlGDFLFrs8tU8ybQDFocp/eX8mQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/scope-manager': 5.11.0
+ '@typescript-eslint/types': 5.11.0
+ '@typescript-eslint/typescript-estree': 5.11.0_typescript@4.5.5
+ debug: 4.3.3
+ eslint: 8.8.0
+ typescript: 4.5.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/scope-manager/5.11.0:
+ resolution: {integrity: sha512-z+K4LlahDFVMww20t/0zcA7gq/NgOawaLuxgqGRVKS0PiZlCTIUtX0EJbC0BK1JtR4CelmkPK67zuCgpdlF4EA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ '@typescript-eslint/types': 5.11.0
+ '@typescript-eslint/visitor-keys': 5.11.0
+ dev: true
+
+ /@typescript-eslint/types/5.11.0:
+ resolution: {integrity: sha512-cxgBFGSRCoBEhvSVLkKw39+kMzUKHlJGVwwMbPcTZX3qEhuXhrjwaZXWMxVfxDgyMm+b5Q5b29Llo2yow8Y7xQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /@typescript-eslint/typescript-estree/5.11.0_typescript@4.5.5:
+ resolution: {integrity: sha512-yVH9hKIv3ZN3lw8m/Jy5I4oXO4ZBMqijcXCdA4mY8ull6TPTAoQnKKrcZ0HDXg7Bsl0Unwwx7jcXMuNZc0m4lg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ '@typescript-eslint/types': 5.11.0
+ '@typescript-eslint/visitor-keys': 5.11.0
+ debug: 4.3.3
+ globby: 11.1.0
+ is-glob: 4.0.3
+ semver: 7.3.5
+ tsutils: 3.21.0_typescript@4.5.5
+ typescript: 4.5.5
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@typescript-eslint/visitor-keys/5.11.0:
+ resolution: {integrity: sha512-E8w/vJReMGuloGxJDkpPlGwhxocxOpSVgSvjiLO5IxZPmxZF30weOeJYyPSEACwM+X4NziYS9q+WkN/2DHYQwA==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ '@typescript-eslint/types': 5.11.0
+ eslint-visitor-keys: 3.2.0
+ dev: true
+
+ /@vitejs/plugin-react/1.1.4:
+ resolution: {integrity: sha512-cMUBDonNY8PPeHWjIrYKbRn6bLSunh/Ixo2XLLBd3DM0uYBZft+c+04zkGhhN1lAwvoRKJ2FdtvhGhPgViHc6w==}
+ engines: {node: '>=12.0.0'}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-jsx-development': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-jsx-self': 7.16.7_@babel+core@7.17.0
+ '@babel/plugin-transform-react-jsx-source': 7.16.7_@babel+core@7.17.0
+ '@rollup/pluginutils': 4.1.2
+ react-refresh: 0.11.0
+ resolve: 1.22.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /@webassemblyjs/ast/1.9.0:
+ resolution: {integrity: sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==}
+ dependencies:
+ '@webassemblyjs/helper-module-context': 1.9.0
+ '@webassemblyjs/helper-wasm-bytecode': 1.9.0
+ '@webassemblyjs/wast-parser': 1.9.0
+ dev: true
+
+ /@webassemblyjs/floating-point-hex-parser/1.9.0:
+ resolution: {integrity: sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==}
+ dev: true
+
+ /@webassemblyjs/helper-api-error/1.9.0:
+ resolution: {integrity: sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==}
+ dev: true
+
+ /@webassemblyjs/helper-buffer/1.9.0:
+ resolution: {integrity: sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==}
+ dev: true
+
+ /@webassemblyjs/helper-code-frame/1.9.0:
+ resolution: {integrity: sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==}
+ dependencies:
+ '@webassemblyjs/wast-printer': 1.9.0
+ dev: true
+
+ /@webassemblyjs/helper-fsm/1.9.0:
+ resolution: {integrity: sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==}
+ dev: true
+
+ /@webassemblyjs/helper-module-context/1.9.0:
+ resolution: {integrity: sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ dev: true
+
+ /@webassemblyjs/helper-wasm-bytecode/1.9.0:
+ resolution: {integrity: sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==}
+ dev: true
+
+ /@webassemblyjs/helper-wasm-section/1.9.0:
+ resolution: {integrity: sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-buffer': 1.9.0
+ '@webassemblyjs/helper-wasm-bytecode': 1.9.0
+ '@webassemblyjs/wasm-gen': 1.9.0
+ dev: true
+
+ /@webassemblyjs/ieee754/1.9.0:
+ resolution: {integrity: sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==}
+ dependencies:
+ '@xtuc/ieee754': 1.2.0
+ dev: true
+
+ /@webassemblyjs/leb128/1.9.0:
+ resolution: {integrity: sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==}
+ dependencies:
+ '@xtuc/long': 4.2.2
+ dev: true
+
+ /@webassemblyjs/utf8/1.9.0:
+ resolution: {integrity: sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==}
+ dev: true
+
+ /@webassemblyjs/wasm-edit/1.9.0:
+ resolution: {integrity: sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-buffer': 1.9.0
+ '@webassemblyjs/helper-wasm-bytecode': 1.9.0
+ '@webassemblyjs/helper-wasm-section': 1.9.0
+ '@webassemblyjs/wasm-gen': 1.9.0
+ '@webassemblyjs/wasm-opt': 1.9.0
+ '@webassemblyjs/wasm-parser': 1.9.0
+ '@webassemblyjs/wast-printer': 1.9.0
+ dev: true
+
+ /@webassemblyjs/wasm-gen/1.9.0:
+ resolution: {integrity: sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-wasm-bytecode': 1.9.0
+ '@webassemblyjs/ieee754': 1.9.0
+ '@webassemblyjs/leb128': 1.9.0
+ '@webassemblyjs/utf8': 1.9.0
+ dev: true
+
+ /@webassemblyjs/wasm-opt/1.9.0:
+ resolution: {integrity: sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-buffer': 1.9.0
+ '@webassemblyjs/wasm-gen': 1.9.0
+ '@webassemblyjs/wasm-parser': 1.9.0
+ dev: true
+
+ /@webassemblyjs/wasm-parser/1.9.0:
+ resolution: {integrity: sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-api-error': 1.9.0
+ '@webassemblyjs/helper-wasm-bytecode': 1.9.0
+ '@webassemblyjs/ieee754': 1.9.0
+ '@webassemblyjs/leb128': 1.9.0
+ '@webassemblyjs/utf8': 1.9.0
+ dev: true
+
+ /@webassemblyjs/wast-parser/1.9.0:
+ resolution: {integrity: sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/floating-point-hex-parser': 1.9.0
+ '@webassemblyjs/helper-api-error': 1.9.0
+ '@webassemblyjs/helper-code-frame': 1.9.0
+ '@webassemblyjs/helper-fsm': 1.9.0
+ '@xtuc/long': 4.2.2
+ dev: true
+
+ /@webassemblyjs/wast-printer/1.9.0:
+ resolution: {integrity: sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==}
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/wast-parser': 1.9.0
+ '@xtuc/long': 4.2.2
+ dev: true
+
+ /@xtuc/ieee754/1.2.0:
+ resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
+ dev: true
+
+ /@xtuc/long/4.2.2:
+ resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==}
+ dev: true
+
+ /JSONStream/1.3.5:
+ resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==}
+ hasBin: true
+ dependencies:
+ jsonparse: 1.3.1
+ through: 2.3.8
+ dev: true
+
+ /accepts/1.3.8:
+ resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-types: 2.1.34
+ negotiator: 0.6.3
+ dev: true
+
+ /acorn-jsx/5.3.2_acorn@7.4.1:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 || 7
+ dependencies:
+ acorn: 7.4.1
+ dev: true
+
+ /acorn-jsx/5.3.2_acorn@8.7.0:
+ resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 || 7
+ dependencies:
+ acorn: 8.7.0
+ dev: true
+
+ /acorn-node/1.8.2:
+ resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==}
+ dependencies:
+ acorn: 7.4.1
+ acorn-walk: 7.2.0
+ xtend: 4.0.2
+ dev: true
+
+ /acorn-walk/7.2.0:
+ resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /acorn/6.4.2:
+ resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /acorn/7.4.1:
+ resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /acorn/8.7.0:
+ resolution: {integrity: sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+ dev: true
+
+ /address/1.1.2:
+ resolution: {integrity: sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==}
+ engines: {node: '>= 0.12.0'}
+ dev: true
+
+ /aggregate-error/3.1.0:
+ resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==}
+ engines: {node: '>=8'}
+ dependencies:
+ clean-stack: 2.2.0
+ indent-string: 4.0.0
+ dev: true
+
+ /airbnb-js-shims/2.2.1:
+ resolution: {integrity: sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==}
+ dependencies:
+ array-includes: 3.1.4
+ array.prototype.flat: 1.2.5
+ array.prototype.flatmap: 1.2.5
+ es5-shim: 4.6.4
+ es6-shim: 0.35.6
+ function.prototype.name: 1.1.5
+ globalthis: 1.0.2
+ object.entries: 1.1.5
+ object.fromentries: 2.0.5
+ object.getownpropertydescriptors: 2.1.3
+ object.values: 1.1.5
+ promise.allsettled: 1.0.5
+ promise.prototype.finally: 3.1.3
+ string.prototype.matchall: 4.0.6
+ string.prototype.padend: 3.1.3
+ string.prototype.padstart: 3.1.3
+ symbol.prototype.description: 1.0.5
+ dev: true
+
+ /ajv-errors/1.0.1_ajv@6.12.6:
+ resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==}
+ peerDependencies:
+ ajv: '>=5.0.0'
+ dependencies:
+ ajv: 6.12.6
+ dev: true
+
+ /ajv-keywords/3.5.2_ajv@6.12.6:
+ resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==}
+ peerDependencies:
+ ajv: ^6.9.1
+ dependencies:
+ ajv: 6.12.6
+ dev: true
+
+ /ajv/6.12.6:
+ resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
+ dependencies:
+ fast-deep-equal: 3.1.3
+ fast-json-stable-stringify: 2.1.0
+ json-schema-traverse: 0.4.1
+ uri-js: 4.4.1
+ dev: true
+
+ /ansi-align/3.0.1:
+ resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==}
+ dependencies:
+ string-width: 4.2.3
+ dev: true
+
+ /ansi-colors/3.2.4:
+ resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /ansi-colors/4.1.1:
+ resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /ansi-escapes/4.3.2:
+ resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.21.3
+ dev: true
+
+ /ansi-html-community/0.0.8:
+ resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==}
+ engines: {'0': node >= 0.8.0}
+ hasBin: true
+ dev: true
+
+ /ansi-regex/2.1.1:
+ resolution: {integrity: sha1-w7M6te42DYbg5ijwRorn7yfWVN8=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /ansi-regex/5.0.1:
+ resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /ansi-regex/6.0.1:
+ resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /ansi-styles/3.2.1:
+ resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
+ engines: {node: '>=4'}
+ dependencies:
+ color-convert: 1.9.3
+ dev: true
+
+ /ansi-styles/4.3.0:
+ resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
+ engines: {node: '>=8'}
+ dependencies:
+ color-convert: 2.0.1
+ dev: true
+
+ /ansi-styles/6.1.0:
+ resolution: {integrity: sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /ansi-to-html/0.6.15:
+ resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==}
+ engines: {node: '>=8.0.0'}
+ hasBin: true
+ dependencies:
+ entities: 2.2.0
+ dev: true
+
+ /anymatch/2.0.0:
+ resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==}
+ dependencies:
+ micromatch: 3.1.10
+ normalize-path: 2.1.1
+ dev: true
+
+ /anymatch/3.1.2:
+ resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ normalize-path: 3.0.0
+ picomatch: 2.3.1
+ dev: true
+
+ /app-root-dir/1.0.2:
+ resolution: {integrity: sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=}
+ dev: true
+
+ /append-buffer/1.0.2:
+ resolution: {integrity: sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ buffer-equal: 1.0.0
+ dev: true
+
+ /append-transform/2.0.0:
+ resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==}
+ engines: {node: '>=8'}
+ dependencies:
+ default-require-extensions: 3.0.0
+ dev: true
+
+ /aproba/1.2.0:
+ resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==}
+ dev: true
+
+ /aproba/2.0.0:
+ resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
+ dev: true
+
+ /arch/2.2.0:
+ resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==}
+ dev: true
+
+ /archy/1.0.0:
+ resolution: {integrity: sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=}
+ dev: true
+
+ /are-we-there-yet/2.0.0:
+ resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
+ engines: {node: '>=10'}
+ dependencies:
+ delegates: 1.0.0
+ readable-stream: 3.6.0
+ dev: true
+
+ /argparse/1.0.10:
+ resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
+ dependencies:
+ sprintf-js: 1.0.3
+ dev: true
+
+ /argparse/2.0.1:
+ resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ dev: true
+
+ /arr-diff/4.0.0:
+ resolution: {integrity: sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /arr-flatten/1.1.0:
+ resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /arr-union/3.1.0:
+ resolution: {integrity: sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /array-flatten/1.1.1:
+ resolution: {integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=}
+ dev: true
+
+ /array-includes/3.1.4:
+ resolution: {integrity: sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ get-intrinsic: 1.1.1
+ is-string: 1.0.7
+ dev: true
+
+ /array-union/1.0.2:
+ resolution: {integrity: sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ array-uniq: 1.0.3
+ dev: true
+
+ /array-union/2.1.0:
+ resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /array-uniq/1.0.3:
+ resolution: {integrity: sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /array-unique/0.3.2:
+ resolution: {integrity: sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /array.prototype.flat/1.2.5:
+ resolution: {integrity: sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /array.prototype.flatmap/1.2.5:
+ resolution: {integrity: sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /array.prototype.map/1.0.4:
+ resolution: {integrity: sha512-Qds9QnX7A0qISY7JT5WuJO0NJPE9CMlC6JzHQfhpqAAQQzufVRoeH7EzUY5GcPTx72voG8LV/5eo+b8Qi8hmhA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ es-array-method-boxes-properly: 1.0.0
+ is-string: 1.0.7
+ dev: true
+
+ /arrify/2.0.1:
+ resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /asn1.js/5.4.1:
+ resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==}
+ dependencies:
+ bn.js: 4.12.0
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ safer-buffer: 2.1.2
+ dev: true
+
+ /asn1/0.2.6:
+ resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: true
+
+ /assert-plus/1.0.0:
+ resolution: {integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=}
+ engines: {node: '>=0.8'}
+ dev: true
+
+ /assert/1.5.0:
+ resolution: {integrity: sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==}
+ dependencies:
+ object-assign: 4.1.1
+ util: 0.10.3
+ dev: true
+
+ /assign-symbols/1.0.0:
+ resolution: {integrity: sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /ast-types/0.14.2:
+ resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==}
+ engines: {node: '>=4'}
+ dependencies:
+ tslib: 2.3.1
+ dev: true
+
+ /astral-regex/2.0.0:
+ resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /async-each/1.0.3:
+ resolution: {integrity: sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==}
+ dev: true
+ optional: true
+
+ /async/3.2.3:
+ resolution: {integrity: sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==}
+ dev: true
+
+ /asynckit/0.4.0:
+ resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=}
+ dev: true
+
+ /at-least-node/1.0.0:
+ resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
+ engines: {node: '>= 4.0.0'}
+ dev: true
+
+ /atob/2.1.2:
+ resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==}
+ engines: {node: '>= 4.5.0'}
+ hasBin: true
+ dev: true
+
+ /autoprefixer/9.8.8:
+ resolution: {integrity: sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==}
+ hasBin: true
+ dependencies:
+ browserslist: 4.19.1
+ caniuse-lite: 1.0.30001309
+ normalize-range: 0.1.2
+ num2fraction: 1.2.2
+ picocolors: 0.2.1
+ postcss: 7.0.39
+ postcss-value-parser: 4.2.0
+ dev: true
+
+ /available-typed-arrays/1.0.5:
+ resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /aws-sign2/0.7.0:
+ resolution: {integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=}
+ dev: true
+
+ /aws4/1.11.0:
+ resolution: {integrity: sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==}
+ dev: true
+
+ /axe-core/4.4.1:
+ resolution: {integrity: sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /axios/0.25.0:
+ resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==}
+ dependencies:
+ follow-redirects: 1.14.7
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
+ /babel-loader/8.2.3_u5fzby2crnk75aqgypigfhaoii:
+ resolution: {integrity: sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==}
+ engines: {node: '>= 8.9'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ webpack: '>=2'
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ find-cache-dir: 3.3.2
+ loader-utils: 1.4.0
+ make-dir: 3.1.0
+ schema-utils: 2.7.1
+ webpack: 4.46.0
+ dev: true
+
+ /babel-plugin-add-module-exports/1.0.4:
+ resolution: {integrity: sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==}
+ dev: true
+
+ /babel-plugin-add-react-displayname/0.0.5:
+ resolution: {integrity: sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=}
+ dev: true
+
+ /babel-plugin-apply-mdx-type-prop/1.6.22_@babel+core@7.12.9:
+ resolution: {integrity: sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==}
+ peerDependencies:
+ '@babel/core': ^7.11.6
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.10.4
+ '@mdx-js/util': 1.6.22
+ dev: true
+
+ /babel-plugin-dynamic-import-node/2.3.3:
+ resolution: {integrity: sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==}
+ dependencies:
+ object.assign: 4.1.2
+ dev: true
+
+ /babel-plugin-emotion/10.2.2:
+ resolution: {integrity: sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==}
+ dependencies:
+ '@babel/helper-module-imports': 7.16.7
+ '@emotion/hash': 0.8.0
+ '@emotion/memoize': 0.7.4
+ '@emotion/serialize': 0.11.16
+ babel-plugin-macros: 2.8.0
+ babel-plugin-syntax-jsx: 6.18.0
+ convert-source-map: 1.8.0
+ escape-string-regexp: 1.0.5
+ find-root: 1.1.0
+ source-map: 0.5.7
+ dev: true
+
+ /babel-plugin-extract-import-names/1.6.22:
+ resolution: {integrity: sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==}
+ dependencies:
+ '@babel/helper-plugin-utils': 7.10.4
+ dev: true
+
+ /babel-plugin-istanbul/6.1.1:
+ resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/helper-plugin-utils': 7.16.7
+ '@istanbuljs/load-nyc-config': 1.1.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-instrument: 5.1.0
+ test-exclude: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-macros/2.8.0:
+ resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ cosmiconfig: 6.0.0
+ resolve: 1.22.0
+ dev: true
+
+ /babel-plugin-macros/3.1.0:
+ resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
+ engines: {node: '>=10', npm: '>=6'}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ cosmiconfig: 7.0.1
+ resolve: 1.22.0
+ dev: true
+
+ /babel-plugin-named-asset-import/0.3.8:
+ resolution: {integrity: sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==}
+ peerDependencies:
+ '@babel/core': ^7.1.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dev: true
+
+ /babel-plugin-polyfill-corejs2/0.3.1_@babel+core@7.17.0:
+ resolution: {integrity: sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/compat-data': 7.17.0
+ '@babel/core': 7.17.0
+ '@babel/helper-define-polyfill-provider': 0.3.1_@babel+core@7.17.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-polyfill-corejs3/0.1.7_@babel+core@7.17.0:
+ resolution: {integrity: sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-define-polyfill-provider': 0.1.5_@babel+core@7.17.0
+ core-js-compat: 3.21.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-polyfill-corejs3/0.5.2_@babel+core@7.17.0:
+ resolution: {integrity: sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-define-polyfill-provider': 0.3.1_@babel+core@7.17.0
+ core-js-compat: 3.21.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-polyfill-regenerator/0.3.1_@babel+core@7.17.0:
+ resolution: {integrity: sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/helper-define-polyfill-provider': 0.3.1_@babel+core@7.17.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-react-docgen/4.2.1:
+ resolution: {integrity: sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==}
+ dependencies:
+ ast-types: 0.14.2
+ lodash: 4.17.21
+ react-docgen: 5.4.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /babel-plugin-syntax-jsx/6.18.0:
+ resolution: {integrity: sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=}
+ dev: true
+
+ /babelify/10.0.0_@babel+core@7.17.0:
+ resolution: {integrity: sha512-X40FaxyH7t3X+JFAKvb1H9wooWKLRCi8pg3m8poqtdZaIng+bjzp9RvKQCvRjF9isHiPkXspbbXT/zwXLtwgwg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+ peerDependenciesMeta:
+ '@babel/core':
+ optional: true
+ dependencies:
+ '@babel/core': 7.17.0
+ dev: true
+
+ /bail/1.0.5:
+ resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==}
+ dev: true
+
+ /balanced-match/1.0.2:
+ resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ dev: true
+
+ /base/0.11.2:
+ resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ cache-base: 1.0.1
+ class-utils: 0.3.6
+ component-emitter: 1.3.0
+ define-property: 1.0.0
+ isobject: 3.0.1
+ mixin-deep: 1.3.2
+ pascalcase: 0.1.1
+ dev: true
+
+ /base64-arraybuffer/1.0.2:
+ resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==}
+ engines: {node: '>= 0.6.0'}
+ dev: false
+
+ /base64-js/1.5.1:
+ resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+ dev: true
+
+ /batch-processor/1.0.0:
+ resolution: {integrity: sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=}
+ dev: true
+
+ /bcrypt-pbkdf/1.0.2:
+ resolution: {integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=}
+ dependencies:
+ tweetnacl: 0.14.5
+ dev: true
+
+ /better-opn/2.1.1:
+ resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==}
+ engines: {node: '>8.0.0'}
+ dependencies:
+ open: 7.4.2
+ dev: true
+
+ /big.js/5.2.2:
+ resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==}
+ dev: true
+
+ /binary-extensions/1.13.1:
+ resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+ optional: true
+
+ /binary-extensions/2.2.0:
+ resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /bindings/1.5.0:
+ resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
+ requiresBuild: true
+ dependencies:
+ file-uri-to-path: 1.0.0
+ dev: true
+ optional: true
+
+ /blob-util/2.0.2:
+ resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
+ dev: true
+
+ /bluebird/3.7.2:
+ resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==}
+ dev: true
+
+ /blueimp-canvas-to-blob/3.29.0:
+ resolution: {integrity: sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==}
+ dev: false
+
+ /bn.js/4.12.0:
+ resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==}
+ dev: true
+
+ /bn.js/5.2.0:
+ resolution: {integrity: sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==}
+ dev: true
+
+ /body-parser/1.19.1:
+ resolution: {integrity: sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.1
+ content-type: 1.0.4
+ debug: 2.6.9
+ depd: 1.1.2
+ http-errors: 1.8.1
+ iconv-lite: 0.4.24
+ on-finished: 2.3.0
+ qs: 6.9.6
+ raw-body: 2.4.2
+ type-is: 1.6.18
+ dev: true
+
+ /boolbase/1.0.0:
+ resolution: {integrity: sha1-aN/1++YMUes3cl6p4+0xDcwed24=}
+ dev: true
+
+ /boxen/5.1.2:
+ resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-align: 3.0.1
+ camelcase: 6.3.0
+ chalk: 4.1.2
+ cli-boxes: 2.2.1
+ string-width: 4.2.3
+ type-fest: 0.20.2
+ widest-line: 3.1.0
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /brace-expansion/1.1.11:
+ resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
+ dependencies:
+ balanced-match: 1.0.2
+ concat-map: 0.0.1
+ dev: true
+
+ /braces/2.3.2:
+ resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ arr-flatten: 1.1.0
+ array-unique: 0.3.2
+ extend-shallow: 2.0.1
+ fill-range: 4.0.0
+ isobject: 3.0.1
+ repeat-element: 1.1.4
+ snapdragon: 0.8.2
+ snapdragon-node: 2.1.1
+ split-string: 3.1.0
+ to-regex: 3.0.2
+ dev: true
+
+ /braces/3.0.2:
+ resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
+ engines: {node: '>=8'}
+ dependencies:
+ fill-range: 7.0.1
+ dev: true
+
+ /broccoli-node-api/1.7.0:
+ resolution: {integrity: sha512-QIqLSVJWJUVOhclmkmypJJH9u9s/aWH4+FH6Q6Ju5l+Io4dtwqdPUNmDfw40o6sxhbZHhqGujDJuHTML1wG8Yw==}
+ dev: true
+
+ /broccoli-node-info/2.2.0:
+ resolution: {integrity: sha512-VabSGRpKIzpmC+r+tJueCE5h8k6vON7EIMMWu6d/FyPdtijwLQ7QvzShEw+m3mHoDzUaj/kiZsDYrS8X2adsBg==}
+ engines: {node: 8.* || >= 10.*}
+ dev: true
+
+ /broccoli-output-wrapper/3.2.5:
+ resolution: {integrity: sha512-bQAtwjSrF4Nu0CK0JOy5OZqw9t5U0zzv2555EA/cF8/a8SLDTIetk9UgrtMVw7qKLKdSpOZ2liZNeZZDaKgayw==}
+ engines: {node: 10.* || >= 12.*}
+ dependencies:
+ fs-extra: 8.1.0
+ heimdalljs-logger: 0.1.10
+ symlink-or-copy: 1.3.1
+ dev: true
+
+ /broccoli-plugin/4.0.7:
+ resolution: {integrity: sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg==}
+ engines: {node: 10.* || >= 12.*}
+ dependencies:
+ broccoli-node-api: 1.7.0
+ broccoli-output-wrapper: 3.2.5
+ fs-merger: 3.2.1
+ promise-map-series: 0.3.0
+ quick-temp: 0.1.8
+ rimraf: 3.0.2
+ symlink-or-copy: 1.3.1
+ dev: true
+
+ /brorand/1.1.0:
+ resolution: {integrity: sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=}
+ dev: true
+
+ /browser-pack/6.1.0:
+ resolution: {integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==}
+ hasBin: true
+ dependencies:
+ combine-source-map: 0.8.0
+ defined: 1.0.0
+ JSONStream: 1.3.5
+ safe-buffer: 5.2.1
+ through2: 2.0.5
+ umd: 3.0.3
+ dev: true
+
+ /browser-resolve/2.0.0:
+ resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==}
+ dependencies:
+ resolve: 1.22.0
+ dev: true
+
+ /browserify-aes/1.2.0:
+ resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==}
+ dependencies:
+ buffer-xor: 1.0.3
+ cipher-base: 1.0.4
+ create-hash: 1.2.0
+ evp_bytestokey: 1.0.3
+ inherits: 2.0.4
+ safe-buffer: 5.2.1
+ dev: true
+
+ /browserify-cipher/1.0.1:
+ resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==}
+ dependencies:
+ browserify-aes: 1.2.0
+ browserify-des: 1.0.2
+ evp_bytestokey: 1.0.3
+ dev: true
+
+ /browserify-des/1.0.2:
+ resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==}
+ dependencies:
+ cipher-base: 1.0.4
+ des.js: 1.0.1
+ inherits: 2.0.4
+ safe-buffer: 5.2.1
+ dev: true
+
+ /browserify-rsa/4.1.0:
+ resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==}
+ dependencies:
+ bn.js: 5.2.0
+ randombytes: 2.1.0
+ dev: true
+
+ /browserify-sign/4.2.1:
+ resolution: {integrity: sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==}
+ dependencies:
+ bn.js: 5.2.0
+ browserify-rsa: 4.1.0
+ create-hash: 1.2.0
+ create-hmac: 1.1.7
+ elliptic: 6.5.4
+ inherits: 2.0.4
+ parse-asn1: 5.1.6
+ readable-stream: 3.6.0
+ safe-buffer: 5.2.1
+ dev: true
+
+ /browserify-zlib/0.2.0:
+ resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==}
+ dependencies:
+ pako: 1.0.11
+ dev: true
+
+ /browserify/16.5.2:
+ resolution: {integrity: sha512-TkOR1cQGdmXU9zW4YukWzWVSJwrxmNdADFbqbE3HFgQWe5wqZmOawqZ7J/8MPCwk/W8yY7Y0h+7mOtcZxLP23g==}
+ engines: {node: '>= 0.8'}
+ hasBin: true
+ dependencies:
+ assert: 1.5.0
+ browser-pack: 6.1.0
+ browser-resolve: 2.0.0
+ browserify-zlib: 0.2.0
+ buffer: 5.2.1
+ cached-path-relative: 1.1.0
+ concat-stream: 1.6.2
+ console-browserify: 1.2.0
+ constants-browserify: 1.0.0
+ crypto-browserify: 3.12.0
+ defined: 1.0.0
+ deps-sort: 2.0.1
+ domain-browser: 1.2.0
+ duplexer2: 0.1.4
+ events: 2.1.0
+ glob: 7.2.0
+ has: 1.0.3
+ htmlescape: 1.1.1
+ https-browserify: 1.0.0
+ inherits: 2.0.4
+ insert-module-globals: 7.2.1
+ JSONStream: 1.3.5
+ labeled-stream-splicer: 2.0.2
+ mkdirp-classic: 0.5.3
+ module-deps: 6.2.3
+ os-browserify: 0.3.0
+ parents: 1.0.1
+ path-browserify: 0.0.1
+ process: 0.11.10
+ punycode: 1.4.1
+ querystring-es3: 0.2.1
+ read-only-stream: 2.0.0
+ readable-stream: 2.3.7
+ resolve: 1.22.0
+ shasum: 1.0.2
+ shell-quote: 1.7.3
+ stream-browserify: 2.0.2
+ stream-http: 3.2.0
+ string_decoder: 1.3.0
+ subarg: 1.0.0
+ syntax-error: 1.4.0
+ through2: 2.0.5
+ timers-browserify: 1.4.2
+ tty-browserify: 0.0.1
+ url: 0.11.0
+ util: 0.10.3
+ vm-browserify: 1.1.2
+ xtend: 4.0.2
+ dev: true
+
+ /browserify/17.0.0:
+ resolution: {integrity: sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==}
+ engines: {node: '>= 0.8'}
+ hasBin: true
+ dependencies:
+ assert: 1.5.0
+ browser-pack: 6.1.0
+ browser-resolve: 2.0.0
+ browserify-zlib: 0.2.0
+ buffer: 5.2.1
+ cached-path-relative: 1.1.0
+ concat-stream: 1.6.2
+ console-browserify: 1.2.0
+ constants-browserify: 1.0.0
+ crypto-browserify: 3.12.0
+ defined: 1.0.0
+ deps-sort: 2.0.1
+ domain-browser: 1.2.0
+ duplexer2: 0.1.4
+ events: 3.3.0
+ glob: 7.2.0
+ has: 1.0.3
+ htmlescape: 1.1.1
+ https-browserify: 1.0.0
+ inherits: 2.0.4
+ insert-module-globals: 7.2.1
+ JSONStream: 1.3.5
+ labeled-stream-splicer: 2.0.2
+ mkdirp-classic: 0.5.3
+ module-deps: 6.2.3
+ os-browserify: 0.3.0
+ parents: 1.0.1
+ path-browserify: 1.0.1
+ process: 0.11.10
+ punycode: 1.4.1
+ querystring-es3: 0.2.1
+ read-only-stream: 2.0.0
+ readable-stream: 2.3.7
+ resolve: 1.22.0
+ shasum-object: 1.0.0
+ shell-quote: 1.7.3
+ stream-browserify: 3.0.0
+ stream-http: 3.2.0
+ string_decoder: 1.3.0
+ subarg: 1.0.0
+ syntax-error: 1.4.0
+ through2: 2.0.5
+ timers-browserify: 1.4.2
+ tty-browserify: 0.0.1
+ url: 0.11.0
+ util: 0.12.4
+ vm-browserify: 1.1.2
+ xtend: 4.0.2
+ dev: true
+
+ /browserslist/4.19.1:
+ resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+ dependencies:
+ caniuse-lite: 1.0.30001309
+ electron-to-chromium: 1.4.66
+ escalade: 3.1.1
+ node-releases: 2.0.1
+ picocolors: 1.0.0
+ dev: true
+
+ /bser/2.1.1:
+ resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
+ dependencies:
+ node-int64: 0.4.0
+ dev: true
+
+ /buffer-crc32/0.2.13:
+ resolution: {integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=}
+ dev: true
+
+ /buffer-equal/1.0.0:
+ resolution: {integrity: sha1-WWFrSYME1Var1GaWayLu2j7KX74=}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /buffer-from/1.1.2:
+ resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
+ dev: true
+
+ /buffer-xor/1.0.3:
+ resolution: {integrity: sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=}
+ dev: true
+
+ /buffer/4.9.2:
+ resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ isarray: 1.0.0
+ dev: true
+
+ /buffer/5.2.1:
+ resolution: {integrity: sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: true
+
+ /buffer/5.7.1:
+ resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
+ dependencies:
+ base64-js: 1.5.1
+ ieee754: 1.2.1
+ dev: true
+
+ /builtin-status-codes/3.0.0:
+ resolution: {integrity: sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=}
+ dev: true
+
+ /bytes/3.0.0:
+ resolution: {integrity: sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /bytes/3.1.1:
+ resolution: {integrity: sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /c8/7.11.0:
+ resolution: {integrity: sha512-XqPyj1uvlHMr+Y1IeRndC2X5P7iJzJlEJwBpCdBbq2JocXOgJfr+JVfJkyNMGROke5LfKrhSFXGFXnwnRJAUJw==}
+ engines: {node: '>=10.12.0'}
+ hasBin: true
+ dependencies:
+ '@bcoe/v8-coverage': 0.2.3
+ '@istanbuljs/schema': 0.1.3
+ find-up: 5.0.0
+ foreground-child: 2.0.0
+ istanbul-lib-coverage: 3.2.0
+ istanbul-lib-report: 3.0.0
+ istanbul-reports: 3.1.4
+ rimraf: 3.0.2
+ test-exclude: 6.0.0
+ v8-to-istanbul: 8.1.1
+ yargs: 16.2.0
+ yargs-parser: 20.2.9
+ dev: true
+
+ /cacache/12.0.4:
+ resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==}
+ dependencies:
+ bluebird: 3.7.2
+ chownr: 1.1.4
+ figgy-pudding: 3.5.2
+ glob: 7.2.0
+ graceful-fs: 4.2.9
+ infer-owner: 1.0.4
+ lru-cache: 5.1.1
+ mississippi: 3.0.0
+ mkdirp: 0.5.5
+ move-concurrently: 1.0.1
+ promise-inflight: 1.0.1
+ rimraf: 2.7.1
+ ssri: 6.0.2
+ unique-filename: 1.1.1
+ y18n: 4.0.3
+ dev: true
+
+ /cacache/15.3.0:
+ resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==}
+ engines: {node: '>= 10'}
+ dependencies:
+ '@npmcli/fs': 1.1.0
+ '@npmcli/move-file': 1.1.2
+ chownr: 2.0.0
+ fs-minipass: 2.1.0
+ glob: 7.2.0
+ infer-owner: 1.0.4
+ lru-cache: 6.0.0
+ minipass: 3.1.6
+ minipass-collect: 1.0.2
+ minipass-flush: 1.0.5
+ minipass-pipeline: 1.2.4
+ mkdirp: 1.0.4
+ p-map: 4.0.0
+ promise-inflight: 1.0.1
+ rimraf: 3.0.2
+ ssri: 8.0.1
+ tar: 6.1.11
+ unique-filename: 1.1.1
+ dev: true
+
+ /cache-base/1.0.1:
+ resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ collection-visit: 1.0.0
+ component-emitter: 1.3.0
+ get-value: 2.0.6
+ has-value: 1.0.0
+ isobject: 3.0.1
+ set-value: 2.0.1
+ to-object-path: 0.3.0
+ union-value: 1.0.1
+ unset-value: 1.0.0
+ dev: true
+
+ /cached-path-relative/1.1.0:
+ resolution: {integrity: sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==}
+ dev: true
+
+ /cachedir/2.3.0:
+ resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /caching-transform/4.0.0:
+ resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==}
+ engines: {node: '>=8'}
+ dependencies:
+ hasha: 5.2.2
+ make-dir: 3.1.0
+ package-hash: 4.0.0
+ write-file-atomic: 3.0.3
+ dev: true
+
+ /call-bind/1.0.2:
+ resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
+ dependencies:
+ function-bind: 1.1.1
+ get-intrinsic: 1.1.1
+ dev: true
+
+ /call-me-maybe/1.0.1:
+ resolution: {integrity: sha1-JtII6onje1y95gJQoV8DHBak1ms=}
+ dev: true
+
+ /callsites/3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /camel-case/4.1.2:
+ resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==}
+ dependencies:
+ pascal-case: 3.1.2
+ tslib: 2.3.1
+ dev: true
+
+ /camelcase-css/2.0.1:
+ resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /camelcase/5.3.1:
+ resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /camelcase/6.3.0:
+ resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /caniuse-lite/1.0.30001309:
+ resolution: {integrity: sha512-Pl8vfigmBXXq+/yUz1jUwULeq9xhMJznzdc/xwl4WclDAuebcTHVefpz8lE/bMI+UN7TOkSSe7B7RnZd6+dzjA==}
+ dev: true
+
+ /capture-exit/2.0.0:
+ resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dependencies:
+ rsvp: 4.8.5
+ dev: true
+
+ /case-sensitive-paths-webpack-plugin/2.4.0:
+ resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /caseless/0.12.0:
+ resolution: {integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=}
+ dev: true
+
+ /ccount/1.1.0:
+ resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==}
+ dev: true
+
+ /chalk/2.4.2:
+ resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ ansi-styles: 3.2.1
+ escape-string-regexp: 1.0.5
+ supports-color: 5.5.0
+ dev: true
+
+ /chalk/4.1.2:
+ resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ supports-color: 7.2.0
+ dev: true
+
+ /character-entities-legacy/1.1.4:
+ resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==}
+ dev: true
+
+ /character-entities/1.2.4:
+ resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==}
+ dev: true
+
+ /character-reference-invalid/1.1.4:
+ resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
+ dev: true
+
+ /charcodes/0.2.0:
+ resolution: {integrity: sha512-Y4kiDb+AM4Ecy58YkuZrrSRJBDQdQ2L+NyS1vHHFtNtUjgutcZfx3yp1dAONI/oPaPmyGfCLx5CxL+zauIMyKQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /check-more-types/2.24.0:
+ resolution: {integrity: sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /cheerio-select/1.5.0:
+ resolution: {integrity: sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==}
+ dependencies:
+ css-select: 4.2.1
+ css-what: 5.1.0
+ domelementtype: 2.2.0
+ domhandler: 4.3.0
+ domutils: 2.8.0
+ dev: true
+
+ /cheerio/1.0.0-rc.10:
+ resolution: {integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==}
+ engines: {node: '>= 6'}
+ dependencies:
+ cheerio-select: 1.5.0
+ dom-serializer: 1.3.2
+ domhandler: 4.3.0
+ htmlparser2: 6.1.0
+ parse5: 6.0.1
+ parse5-htmlparser2-tree-adapter: 6.0.1
+ tslib: 2.3.1
+ dev: true
+
+ /chokidar/2.1.8:
+ resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==}
+ deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies
+ dependencies:
+ anymatch: 2.0.0
+ async-each: 1.0.3
+ braces: 2.3.2
+ glob-parent: 3.1.0
+ inherits: 2.0.4
+ is-binary-path: 1.0.1
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ path-is-absolute: 1.0.1
+ readdirp: 2.2.1
+ upath: 1.2.0
+ optionalDependencies:
+ fsevents: 1.2.13
+ dev: true
+ optional: true
+
+ /chokidar/3.5.3:
+ resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
+ engines: {node: '>= 8.10.0'}
+ dependencies:
+ anymatch: 3.1.2
+ braces: 3.0.2
+ glob-parent: 5.1.2
+ is-binary-path: 2.1.0
+ is-glob: 4.0.3
+ normalize-path: 3.0.0
+ readdirp: 3.6.0
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /chownr/1.1.4:
+ resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
+ dev: true
+
+ /chownr/2.0.0:
+ resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /chromatic/6.4.3:
+ resolution: {integrity: sha512-Hxd85QNWwVo2VS9bIGa5bL06wjSt+EUT8ed48jnkOw7cnkkIQfnEVpwjOoZ/91C4rtRPw8w/2EwCHq+eWD4NNg==}
+ hasBin: true
+ dev: true
+
+ /chrome-trace-event/1.0.3:
+ resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==}
+ engines: {node: '>=6.0'}
+ dev: true
+
+ /ci-info/2.0.0:
+ resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
+ dev: true
+
+ /ci-info/3.3.0:
+ resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==}
+ dev: true
+
+ /cipher-base/1.0.4:
+ resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==}
+ dependencies:
+ inherits: 2.0.4
+ safe-buffer: 5.2.1
+ dev: true
+
+ /class-utils/0.3.6:
+ resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ arr-union: 3.1.0
+ define-property: 0.2.5
+ isobject: 3.0.1
+ static-extend: 0.1.2
+ dev: true
+
+ /classnames/2.3.1:
+ resolution: {integrity: sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==}
+ dev: false
+
+ /clean-css/4.2.4:
+ resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==}
+ engines: {node: '>= 4.0'}
+ dependencies:
+ source-map: 0.6.1
+ dev: true
+
+ /clean-stack/2.2.0:
+ resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /cli-boxes/2.2.1:
+ resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /cli-cursor/3.1.0:
+ resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==}
+ engines: {node: '>=8'}
+ dependencies:
+ restore-cursor: 3.1.0
+ dev: true
+
+ /cli-table3/0.6.1:
+ resolution: {integrity: sha512-w0q/enDHhPLq44ovMGdQeeDLvwxwavsJX7oQGYt/LrBlYsyaxyDnp6z3QzFut/6kLLKnlcUVJLrpB7KBfgG/RA==}
+ engines: {node: 10.* || >= 12.*}
+ dependencies:
+ string-width: 4.2.3
+ optionalDependencies:
+ colors: 1.4.0
+ dev: true
+
+ /cli-truncate/2.1.0:
+ resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==}
+ engines: {node: '>=8'}
+ dependencies:
+ slice-ansi: 3.0.0
+ string-width: 4.2.3
+ dev: true
+
+ /cli-truncate/3.1.0:
+ resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ dependencies:
+ slice-ansi: 5.0.0
+ string-width: 5.1.0
+ dev: true
+
+ /cliui/6.0.0:
+ resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 6.2.0
+ dev: true
+
+ /cliui/7.0.4:
+ resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==}
+ dependencies:
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /clone-buffer/1.0.0:
+ resolution: {integrity: sha1-4+JbIHrE5wGvch4staFnksrD3Fg=}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /clone-deep/4.0.1:
+ resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ is-plain-object: 2.0.4
+ kind-of: 6.0.3
+ shallow-clone: 3.0.1
+ dev: true
+
+ /clone-stats/1.0.0:
+ resolution: {integrity: sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=}
+ dev: true
+
+ /clone/2.1.2:
+ resolution: {integrity: sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=}
+ engines: {node: '>=0.8'}
+ dev: true
+
+ /cloneable-readable/1.1.3:
+ resolution: {integrity: sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==}
+ dependencies:
+ inherits: 2.0.4
+ process-nextick-args: 2.0.1
+ readable-stream: 2.3.7
+ dev: true
+
+ /clsx/1.1.1:
+ resolution: {integrity: sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==}
+ engines: {node: '>=6'}
+
+ /coffeeify/3.0.1_coffeescript@1.12.7:
+ resolution: {integrity: sha512-Qjnr7UX6ldK1PHV7wCnv7AuCd4q19KTUtwJnu/6JRJB4rfm12zvcXtKdacUoePOKr1I4ka/ydKiwWpNAdsQb0g==}
+ peerDependencies:
+ coffeescript: '>1.9.2 <3'
+ dependencies:
+ coffeescript: 1.12.7
+ convert-source-map: 1.8.0
+ through2: 2.0.5
+ dev: true
+
+ /coffeescript/1.12.7:
+ resolution: {integrity: sha512-pLXHFxQMPklVoEekowk8b3erNynC+DVJzChxS/LCBBgR6/8AJkHivkm//zbowcfc7BTCAjryuhx6gPqPRfsFoA==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+ dev: true
+
+ /collapse-white-space/1.0.6:
+ resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==}
+ dev: true
+
+ /collection-visit/1.0.0:
+ resolution: {integrity: sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ map-visit: 1.0.0
+ object-visit: 1.0.1
+ dev: true
+
+ /color-convert/1.9.3:
+ resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
+ dependencies:
+ color-name: 1.1.3
+ dev: true
+
+ /color-convert/2.0.1:
+ resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
+ engines: {node: '>=7.0.0'}
+ dependencies:
+ color-name: 1.1.4
+ dev: true
+
+ /color-name/1.1.3:
+ resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=}
+ dev: true
+
+ /color-name/1.1.4:
+ resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ dev: true
+
+ /color-support/1.1.3:
+ resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
+ hasBin: true
+ dev: true
+
+ /colorette/2.0.16:
+ resolution: {integrity: sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==}
+ dev: true
+
+ /colors/1.4.0:
+ resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
+ engines: {node: '>=0.1.90'}
+ dev: true
+
+ /combine-source-map/0.8.0:
+ resolution: {integrity: sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=}
+ dependencies:
+ convert-source-map: 1.1.3
+ inline-source-map: 0.6.2
+ lodash.memoize: 3.0.4
+ source-map: 0.5.7
+ dev: true
+
+ /combined-stream/1.0.8:
+ resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ delayed-stream: 1.0.0
+ dev: true
+
+ /comma-separated-tokens/1.0.8:
+ resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
+ dev: true
+
+ /commander/2.20.3:
+ resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==}
+ dev: true
+
+ /commander/4.1.1:
+ resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /commander/5.1.0:
+ resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /commander/6.2.1:
+ resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /commander/7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+ dev: false
+
+ /commander/8.3.0:
+ resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==}
+ engines: {node: '>= 12'}
+ dev: true
+
+ /common-path-prefix/3.0.0:
+ resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==}
+ dev: true
+
+ /common-tags/1.8.2:
+ resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==}
+ engines: {node: '>=4.0.0'}
+ dev: true
+
+ /commondir/1.0.1:
+ resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=}
+ dev: true
+
+ /component-emitter/1.3.0:
+ resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==}
+ dev: true
+
+ /compressible/2.0.18:
+ resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.51.0
+ dev: true
+
+ /compression/1.7.4:
+ resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ accepts: 1.3.8
+ bytes: 3.0.0
+ compressible: 2.0.18
+ debug: 2.6.9
+ on-headers: 1.0.2
+ safe-buffer: 5.1.2
+ vary: 1.1.2
+ dev: true
+
+ /compressorjs/1.1.1:
+ resolution: {integrity: sha512-SysRuUPfmUNoq+RviE0iMFVUmoX2q/x+7PkEPUmk6NGkd85hDrmvujx0Qtp8UCGA6KMe5kuodsylPQcNaLf60w==}
+ dependencies:
+ blueimp-canvas-to-blob: 3.29.0
+ is-blob: 2.1.0
+ dev: false
+
+ /compute-scroll-into-view/1.0.17:
+ resolution: {integrity: sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==}
+ dev: true
+
+ /concat-map/0.0.1:
+ resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
+ dev: true
+
+ /concat-stream/1.6.2:
+ resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==}
+ engines: {'0': node >= 0.8}
+ dependencies:
+ buffer-from: 1.1.2
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ typedarray: 0.0.6
+ dev: true
+
+ /concat-stream/2.0.0:
+ resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==}
+ engines: {'0': node >= 6.0}
+ dependencies:
+ buffer-from: 1.1.2
+ inherits: 2.0.4
+ readable-stream: 3.6.0
+ typedarray: 0.0.6
+ dev: true
+
+ /console-browserify/1.2.0:
+ resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==}
+ dev: true
+
+ /console-control-strings/1.1.0:
+ resolution: {integrity: sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=}
+ dev: true
+
+ /constants-browserify/1.0.0:
+ resolution: {integrity: sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=}
+ dev: true
+
+ /content-disposition/0.5.4:
+ resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /content-type/1.0.4:
+ resolution: {integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /convert-source-map/1.1.3:
+ resolution: {integrity: sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=}
+ dev: true
+
+ /convert-source-map/1.8.0:
+ resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==}
+ dependencies:
+ safe-buffer: 5.1.2
+ dev: true
+
+ /convert-units/3.0.0-beta.3:
+ resolution: {integrity: sha512-TFsn0/ciBdESdvYWdeMYvPCe2V1l+nSl0DBlaowdcm0WMCJ++3D8rW/Fx9ALBpb1pKsvja6qH7UyjJBzBSh0sg==}
+ dev: false
+
+ /cookie-signature/1.0.6:
+ resolution: {integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=}
+ dev: true
+
+ /cookie/0.4.1:
+ resolution: {integrity: sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /copy-concurrently/1.0.5:
+ resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==}
+ dependencies:
+ aproba: 1.2.0
+ fs-write-stream-atomic: 1.0.10
+ iferr: 0.1.5
+ mkdirp: 0.5.5
+ rimraf: 2.7.1
+ run-queue: 1.0.3
+ dev: true
+
+ /copy-descriptor/0.1.1:
+ resolution: {integrity: sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /copy-to-clipboard/3.3.1:
+ resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==}
+ dependencies:
+ toggle-selection: 1.0.6
+ dev: true
+
+ /core-js-compat/3.21.0:
+ resolution: {integrity: sha512-OSXseNPSK2OPJa6GdtkMz/XxeXx8/CJvfhQWTqd6neuUraujcL4jVsjkLQz1OWnax8xVQJnRPe0V2jqNWORA+A==}
+ dependencies:
+ browserslist: 4.19.1
+ semver: 7.0.0
+ dev: true
+
+ /core-js-pure/3.21.0:
+ resolution: {integrity: sha512-VaJUunCZLnxuDbo1rNOzwbet9E1K9joiXS5+DQMPtgxd24wfsZbJZMMfQLGYMlCUvSxLfsRUUhoOR2x28mFfeg==}
+ requiresBuild: true
+ dev: true
+
+ /core-js/3.21.0:
+ resolution: {integrity: sha512-YUdI3fFu4TF/2WykQ2xzSiTQdldLB4KVuL9WeAy5XONZYt5Cun/fpQvctoKbCgvPhmzADeesTk/j2Rdx77AcKQ==}
+ requiresBuild: true
+ dev: true
+
+ /core-util-is/1.0.2:
+ resolution: {integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=}
+ dev: true
+
+ /core-util-is/1.0.3:
+ resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
+ dev: true
+
+ /cosmiconfig/6.0.0:
+ resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@types/parse-json': 4.0.0
+ import-fresh: 3.3.0
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+ dev: true
+
+ /cosmiconfig/7.0.1:
+ resolution: {integrity: sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@types/parse-json': 4.0.0
+ import-fresh: 3.3.0
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+ dev: true
+
+ /cp-file/7.0.0:
+ resolution: {integrity: sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==}
+ engines: {node: '>=8'}
+ dependencies:
+ graceful-fs: 4.2.9
+ make-dir: 3.1.0
+ nested-error-stacks: 2.1.0
+ p-event: 4.2.0
+ dev: true
+
+ /cpy/8.1.2:
+ resolution: {integrity: sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==}
+ engines: {node: '>=8'}
+ dependencies:
+ arrify: 2.0.1
+ cp-file: 7.0.0
+ globby: 9.2.0
+ has-glob: 1.0.0
+ junk: 3.1.0
+ nested-error-stacks: 2.1.0
+ p-all: 2.1.0
+ p-filter: 2.1.0
+ p-map: 3.0.0
+ dev: true
+
+ /create-ecdh/4.0.4:
+ resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==}
+ dependencies:
+ bn.js: 4.12.0
+ elliptic: 6.5.4
+ dev: true
+
+ /create-hash/1.2.0:
+ resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==}
+ dependencies:
+ cipher-base: 1.0.4
+ inherits: 2.0.4
+ md5.js: 1.3.5
+ ripemd160: 2.0.2
+ sha.js: 2.4.11
+ dev: true
+
+ /create-hmac/1.1.7:
+ resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==}
+ dependencies:
+ cipher-base: 1.0.4
+ create-hash: 1.2.0
+ inherits: 2.0.4
+ ripemd160: 2.0.2
+ safe-buffer: 5.2.1
+ sha.js: 2.4.11
+ dev: true
+
+ /cross-spawn/6.0.5:
+ resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
+ engines: {node: '>=4.8'}
+ dependencies:
+ nice-try: 1.0.5
+ path-key: 2.0.1
+ semver: 5.7.1
+ shebang-command: 1.2.0
+ which: 1.3.1
+ dev: true
+
+ /cross-spawn/7.0.3:
+ resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
+ engines: {node: '>= 8'}
+ dependencies:
+ path-key: 3.1.1
+ shebang-command: 2.0.0
+ which: 2.0.2
+ dev: true
+
+ /crypto-browserify/3.12.0:
+ resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==}
+ dependencies:
+ browserify-cipher: 1.0.1
+ browserify-sign: 4.2.1
+ create-ecdh: 4.0.4
+ create-hash: 1.2.0
+ create-hmac: 1.1.7
+ diffie-hellman: 5.0.3
+ inherits: 2.0.4
+ pbkdf2: 3.1.2
+ public-encrypt: 4.0.3
+ randombytes: 2.1.0
+ randomfill: 1.0.4
+ dev: true
+
+ /css-line-break/2.1.0:
+ resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==}
+ dependencies:
+ utrie: 1.0.2
+ dev: false
+
+ /css-loader/3.6.0_webpack@4.46.0:
+ resolution: {integrity: sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==}
+ engines: {node: '>= 8.9.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ camelcase: 5.3.1
+ cssesc: 3.0.0
+ icss-utils: 4.1.1
+ loader-utils: 1.4.0
+ normalize-path: 3.0.0
+ postcss: 7.0.39
+ postcss-modules-extract-imports: 2.0.0
+ postcss-modules-local-by-default: 3.0.3
+ postcss-modules-scope: 2.2.0
+ postcss-modules-values: 3.0.0
+ postcss-value-parser: 4.2.0
+ schema-utils: 2.7.1
+ semver: 6.3.0
+ webpack: 4.46.0
+ dev: true
+
+ /css-select/4.2.1:
+ resolution: {integrity: sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==}
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 5.1.0
+ domhandler: 4.3.0
+ domutils: 2.8.0
+ nth-check: 2.0.1
+ dev: true
+
+ /css-vendor/2.0.8:
+ resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ is-in-browser: 1.1.3
+ dev: false
+
+ /css-what/5.1.0:
+ resolution: {integrity: sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /cssesc/3.0.0:
+ resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /csstype/2.6.19:
+ resolution: {integrity: sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==}
+
+ /csstype/3.0.10:
+ resolution: {integrity: sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==}
+
+ /cyclist/1.0.1:
+ resolution: {integrity: sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=}
+ dev: true
+
+ /cypress-react-selector/2.3.16:
+ resolution: {integrity: sha512-Ecj7iic5QJZU8mPKV9e9rgRi/TDvjykdfJB3V42ptqw+9G/Ef4iLTneCqyK287N7t7kLbo1mhXXcbj4J39KJlQ==}
+ dependencies:
+ resq: 1.10.2
+ dev: true
+
+ /cypress/9.5.2:
+ resolution: {integrity: sha512-gYiQYvJozMzDOriUV1rCt6CeRM/pRK4nhwGJj3nJQyX2BoUdTCVwp30xDMKc771HiNVhBtgj5o5/iBdVDVXQUg==}
+ engines: {node: '>=12.0.0'}
+ hasBin: true
+ requiresBuild: true
+ dependencies:
+ '@cypress/request': 2.88.10
+ '@cypress/xvfb': 1.2.4
+ '@types/node': 14.18.10
+ '@types/sinonjs__fake-timers': 8.1.1
+ '@types/sizzle': 2.3.3
+ arch: 2.2.0
+ blob-util: 2.0.2
+ bluebird: 3.7.2
+ buffer: 5.7.1
+ cachedir: 2.3.0
+ chalk: 4.1.2
+ check-more-types: 2.24.0
+ cli-cursor: 3.1.0
+ cli-table3: 0.6.1
+ commander: 5.1.0
+ common-tags: 1.8.2
+ dayjs: 1.11.0
+ debug: 4.3.3_supports-color@8.1.1
+ enquirer: 2.3.6
+ eventemitter2: 6.4.5
+ execa: 4.1.0
+ executable: 4.1.1
+ extract-zip: 2.0.1_supports-color@8.1.1
+ figures: 3.2.0
+ fs-extra: 9.1.0
+ getos: 3.2.1
+ is-ci: 3.0.1
+ is-installed-globally: 0.4.0
+ lazy-ass: 1.6.0
+ listr2: 3.14.0_enquirer@2.3.6
+ lodash: 4.17.21
+ log-symbols: 4.1.0
+ minimist: 1.2.5
+ ospath: 1.2.2
+ pretty-bytes: 5.6.0
+ proxy-from-env: 1.0.0
+ request-progress: 3.0.0
+ semver: 7.3.5
+ supports-color: 8.1.1
+ tmp: 0.2.1
+ untildify: 4.0.0
+ yauzl: 2.10.0
+ dev: true
+
+ /d/1.0.1:
+ resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
+ dependencies:
+ es5-ext: 0.10.53
+ type: 1.2.0
+ dev: false
+
+ /d3-array/3.1.1:
+ resolution: {integrity: sha512-33qQ+ZoZlli19IFiQx4QEpf2CBEayMRzhlisJHSCsSUbDXv6ZishqS1x7uFVClKG4Wr7rZVHvaAttoLow6GqdQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ internmap: 2.0.3
+ dev: false
+
+ /d3-axis/3.0.0:
+ resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-brush/3.0.0:
+ resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1_d3-selection@3.0.0
+ dev: false
+
+ /d3-chord/3.0.1:
+ resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-path: 3.0.1
+ dev: false
+
+ /d3-color/3.0.1:
+ resolution: {integrity: sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-contour/3.0.1:
+ resolution: {integrity: sha512-0Oc4D0KyhwhM7ZL0RMnfGycLN7hxHB8CMmwZ3+H26PWAG0ozNuYG5hXSDNgmP1SgJkQMrlG6cP20HoaSbvcJTQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.1.1
+ dev: false
+
+ /d3-delaunay/6.0.2:
+ resolution: {integrity: sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ delaunator: 5.0.0
+ dev: false
+
+ /d3-dispatch/3.0.1:
+ resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-drag/3.0.0:
+ resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-selection: 3.0.0
+ dev: false
+
+ /d3-dsv/3.0.1:
+ resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==}
+ engines: {node: '>=12'}
+ hasBin: true
+ dependencies:
+ commander: 7.2.0
+ iconv-lite: 0.6.3
+ rw: 1.3.3
+ dev: false
+
+ /d3-ease/3.0.1:
+ resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-fetch/3.0.1:
+ resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dsv: 3.0.1
+ dev: false
+
+ /d3-force/3.0.0:
+ resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-timer: 3.0.1
+ dev: false
+
+ /d3-format/3.1.0:
+ resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-geo/3.0.1:
+ resolution: {integrity: sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.1.1
+ dev: false
+
+ /d3-hierarchy/3.1.1:
+ resolution: {integrity: sha512-LtAIu54UctRmhGKllleflmHalttH3zkfSi4NlKrTAoFKjC+AFBJohsCAdgCBYQwH0F8hIOGY89X1pPqAchlMkA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-interpolate/3.0.1:
+ resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-color: 3.0.1
+ dev: false
+
+ /d3-path/3.0.1:
+ resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-polygon/3.0.1:
+ resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-quadtree/3.0.1:
+ resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-random/3.0.1:
+ resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-scale-chromatic/3.0.0:
+ resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-color: 3.0.1
+ d3-interpolate: 3.0.1
+ dev: false
+
+ /d3-scale/4.0.2:
+ resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.1.1
+ d3-format: 3.1.0
+ d3-interpolate: 3.0.1
+ d3-time: 3.0.0
+ d3-time-format: 4.1.0
+ dev: false
+
+ /d3-selection/3.0.0:
+ resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-shape/3.1.0:
+ resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-path: 3.0.1
+ dev: false
+
+ /d3-time-format/4.1.0:
+ resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-time: 3.0.0
+ dev: false
+
+ /d3-time/3.0.0:
+ resolution: {integrity: sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.1.1
+ dev: false
+
+ /d3-timer/3.0.1:
+ resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /d3-transition/3.0.1_d3-selection@3.0.0:
+ resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ d3-selection: 2 - 3
+ dependencies:
+ d3-color: 3.0.1
+ d3-dispatch: 3.0.1
+ d3-ease: 3.0.1
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-timer: 3.0.1
+ dev: false
+
+ /d3-zoom/3.0.0:
+ resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-interpolate: 3.0.1
+ d3-selection: 3.0.0
+ d3-transition: 3.0.1_d3-selection@3.0.0
+ dev: false
+
+ /d3/7.3.0:
+ resolution: {integrity: sha512-MDRLJCMK232OJQRqGljQ/gCxtB8k3/sLKFjftMjzPB3nKVUODpdW9Rb3vcq7U8Ka5YKoZkAmp++Ur6I+6iNWIw==}
+ engines: {node: '>=12'}
+ dependencies:
+ d3-array: 3.1.1
+ d3-axis: 3.0.0
+ d3-brush: 3.0.0
+ d3-chord: 3.0.1
+ d3-color: 3.0.1
+ d3-contour: 3.0.1
+ d3-delaunay: 6.0.2
+ d3-dispatch: 3.0.1
+ d3-drag: 3.0.0
+ d3-dsv: 3.0.1
+ d3-ease: 3.0.1
+ d3-fetch: 3.0.1
+ d3-force: 3.0.0
+ d3-format: 3.1.0
+ d3-geo: 3.0.1
+ d3-hierarchy: 3.1.1
+ d3-interpolate: 3.0.1
+ d3-path: 3.0.1
+ d3-polygon: 3.0.1
+ d3-quadtree: 3.0.1
+ d3-random: 3.0.1
+ d3-scale: 4.0.2
+ d3-scale-chromatic: 3.0.0
+ d3-selection: 3.0.0
+ d3-shape: 3.1.0
+ d3-time: 3.0.0
+ d3-time-format: 4.1.0
+ d3-timer: 3.0.1
+ d3-transition: 3.0.1_d3-selection@3.0.0
+ d3-zoom: 3.0.0
+ dev: false
+
+ /dash-ast/1.0.0:
+ resolution: {integrity: sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==}
+ dev: true
+
+ /dashdash/1.14.1:
+ resolution: {integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=}
+ engines: {node: '>=0.10'}
+ dependencies:
+ assert-plus: 1.0.0
+ dev: true
+
+ /dayjs/1.10.7:
+ resolution: {integrity: sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==}
+ dev: true
+
+ /dayjs/1.11.0:
+ resolution: {integrity: sha512-JLC809s6Y948/FuCZPm5IX8rRhQwOiyMb2TfVVQEixG7P8Lm/gt5S7yoQZmC8x1UehI9Pb7sksEt4xx14m+7Ug==}
+ dev: true
+
+ /de-indent/1.0.2:
+ resolution: {integrity: sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=}
+ dev: true
+
+ /debug/2.6.9:
+ resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
+ dependencies:
+ ms: 2.0.0
+ dev: true
+
+ /debug/3.2.7:
+ resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
+ dependencies:
+ ms: 2.1.3
+ dev: true
+
+ /debug/4.3.3:
+ resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ dev: true
+
+ /debug/4.3.3_supports-color@8.1.1:
+ resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ supports-color: 8.1.1
+ dev: true
+
+ /debug/4.3.3_supports-color@9.2.1:
+ resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ dependencies:
+ ms: 2.1.2
+ supports-color: 9.2.1
+ dev: true
+
+ /decamelize/1.2.0:
+ resolution: {integrity: sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /decode-uri-component/0.2.0:
+ resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
+ engines: {node: '>=0.10'}
+ dev: true
+
+ /dedent/0.7.0:
+ resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=}
+ dev: true
+
+ /deep-is/0.1.4:
+ resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
+ dev: true
+
+ /deep-object-diff/1.1.7:
+ resolution: {integrity: sha512-QkgBca0mL08P6HiOjoqvmm6xOAl2W6CT2+34Ljhg0OeFan8cwlcdq8jrLKsBBuUFAZLsN5b6y491KdKEoSo9lg==}
+ dev: true
+
+ /deepmerge/4.2.2:
+ resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /default-require-extensions/3.0.0:
+ resolution: {integrity: sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==}
+ engines: {node: '>=8'}
+ dependencies:
+ strip-bom: 4.0.0
+ dev: true
+
+ /define-properties/1.1.3:
+ resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ object-keys: 1.1.1
+ dev: true
+
+ /define-property/0.2.5:
+ resolution: {integrity: sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-descriptor: 0.1.6
+ dev: true
+
+ /define-property/1.0.0:
+ resolution: {integrity: sha1-dp66rz9KY6rTr56NMEybvnm/sOY=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-descriptor: 1.0.2
+ dev: true
+
+ /define-property/2.0.2:
+ resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-descriptor: 1.0.2
+ isobject: 3.0.1
+ dev: true
+
+ /defined/1.0.0:
+ resolution: {integrity: sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=}
+ dev: true
+
+ /delaunator/5.0.0:
+ resolution: {integrity: sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==}
+ dependencies:
+ robust-predicates: 3.0.1
+ dev: false
+
+ /delayed-stream/1.0.0:
+ resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /delegates/1.0.0:
+ resolution: {integrity: sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=}
+ dev: true
+
+ /depd/1.1.2:
+ resolution: {integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /deps-sort/2.0.1:
+ resolution: {integrity: sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==}
+ hasBin: true
+ dependencies:
+ JSONStream: 1.3.5
+ shasum-object: 1.0.0
+ subarg: 1.0.0
+ through2: 2.0.5
+ dev: true
+
+ /des.js/1.0.1:
+ resolution: {integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==}
+ dependencies:
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ dev: true
+
+ /destroy/1.0.4:
+ resolution: {integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=}
+ dev: true
+
+ /detab/2.0.4:
+ resolution: {integrity: sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==}
+ dependencies:
+ repeat-string: 1.6.1
+ dev: true
+
+ /detect-port/1.3.0:
+ resolution: {integrity: sha512-E+B1gzkl2gqxt1IhUzwjrxBKRqx1UzC3WLONHinn8S3T6lwV/agVCyitiFOsGJ/eYuEUBvD71MZHy3Pv1G9doQ==}
+ engines: {node: '>= 4.2.1'}
+ hasBin: true
+ dependencies:
+ address: 1.1.2
+ debug: 2.6.9
+ dev: true
+
+ /detective/5.2.0:
+ resolution: {integrity: sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+ dependencies:
+ acorn-node: 1.8.2
+ defined: 1.0.0
+ minimist: 1.2.5
+ dev: true
+
+ /diffie-hellman/5.0.3:
+ resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==}
+ dependencies:
+ bn.js: 4.12.0
+ miller-rabin: 4.0.1
+ randombytes: 2.1.0
+ dev: true
+
+ /dir-glob/2.2.2:
+ resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==}
+ engines: {node: '>=4'}
+ dependencies:
+ path-type: 3.0.0
+ dev: true
+
+ /dir-glob/3.0.1:
+ resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-type: 4.0.0
+ dev: true
+
+ /doctrine/2.1.0:
+ resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /doctrine/3.0.0:
+ resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ esutils: 2.0.3
+ dev: true
+
+ /dom-converter/0.2.0:
+ resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==}
+ dependencies:
+ utila: 0.4.0
+ dev: true
+
+ /dom-helpers/5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ csstype: 3.0.10
+ dev: false
+
+ /dom-serializer/1.3.2:
+ resolution: {integrity: sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==}
+ dependencies:
+ domelementtype: 2.2.0
+ domhandler: 4.3.0
+ entities: 2.2.0
+ dev: true
+
+ /dom-walk/0.1.2:
+ resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==}
+ dev: true
+
+ /domain-browser/1.2.0:
+ resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==}
+ engines: {node: '>=0.4', npm: '>=1.2'}
+ dev: true
+
+ /domelementtype/2.2.0:
+ resolution: {integrity: sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==}
+ dev: true
+
+ /domhandler/4.3.0:
+ resolution: {integrity: sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==}
+ engines: {node: '>= 4'}
+ dependencies:
+ domelementtype: 2.2.0
+ dev: true
+
+ /domutils/2.8.0:
+ resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==}
+ dependencies:
+ dom-serializer: 1.3.2
+ domelementtype: 2.2.0
+ domhandler: 4.3.0
+ dev: true
+
+ /dot-case/3.0.4:
+ resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==}
+ dependencies:
+ no-case: 3.0.4
+ tslib: 2.3.1
+ dev: true
+
+ /dotenv-expand/5.1.0:
+ resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
+ dev: true
+
+ /dotenv/8.6.0:
+ resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /downshift/6.1.7_react@17.0.2:
+ resolution: {integrity: sha512-cVprZg/9Lvj/uhYRxELzlu1aezRcgPWBjTvspiGTVEU64gF5pRdSRKFVLcxqsZC637cLAGMbL40JavEfWnqgNg==}
+ peerDependencies:
+ react: '>=16.12.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ compute-scroll-into-view: 1.0.17
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-is: 17.0.2
+ tslib: 2.3.1
+ dev: true
+
+ /duplexer2/0.1.4:
+ resolution: {integrity: sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=}
+ dependencies:
+ readable-stream: 2.3.7
+ dev: true
+
+ /duplexify/3.7.1:
+ resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==}
+ dependencies:
+ end-of-stream: 1.4.4
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ stream-shift: 1.0.1
+ dev: true
+
+ /eastasianwidth/0.2.0:
+ resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
+ dev: true
+
+ /ecc-jsbn/0.1.2:
+ resolution: {integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=}
+ dependencies:
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+ dev: true
+
+ /ee-first/1.1.1:
+ resolution: {integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=}
+ dev: true
+
+ /electron-to-chromium/1.4.66:
+ resolution: {integrity: sha512-f1RXFMsvwufWLwYUxTiP7HmjprKXrqEWHiQkjAYa9DJeVIlZk5v8gBGcaV+FhtXLly6C1OTVzQY+2UQrACiLlg==}
+ dev: true
+
+ /element-resize-detector/1.2.4:
+ resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==}
+ dependencies:
+ batch-processor: 1.0.0
+ dev: true
+
+ /elliptic/6.5.4:
+ resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==}
+ dependencies:
+ bn.js: 4.12.0
+ brorand: 1.1.0
+ hash.js: 1.1.7
+ hmac-drbg: 1.0.1
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ minimalistic-crypto-utils: 1.0.1
+ dev: true
+
+ /emoji-regex/8.0.0:
+ resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
+ dev: true
+
+ /emoji-regex/9.2.2:
+ resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
+ dev: true
+
+ /emojis-list/3.0.0:
+ resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /emotion-theming/10.3.0_gfrer23gq2rp2t523t6qbxrx6m:
+ resolution: {integrity: sha512-mXiD2Oj7N9b6+h/dC6oLf9hwxbtKHQjoIqtodEyL8CpkN4F3V4IK/BT4D0C7zSs4BBFOu4UlPJbvvBLa88SGEA==}
+ peerDependencies:
+ '@emotion/core': ^10.0.27
+ react: '>=16.3.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/core': 10.3.1_react@17.0.2
+ '@emotion/weak-memoize': 0.2.5
+ hoist-non-react-statics: 3.3.2
+ react: 17.0.2
+ dev: true
+
+ /encodeurl/1.0.2:
+ resolution: {integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /end-of-stream/1.4.4:
+ resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
+ dependencies:
+ once: 1.4.0
+ dev: true
+
+ /endent/2.1.0:
+ resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==}
+ dependencies:
+ dedent: 0.7.0
+ fast-json-parse: 1.0.3
+ objectorarray: 1.0.5
+ dev: true
+
+ /enhanced-resolve/4.5.0:
+ resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==}
+ engines: {node: '>=6.9.0'}
+ dependencies:
+ graceful-fs: 4.2.9
+ memory-fs: 0.5.0
+ tapable: 1.1.3
+ dev: true
+
+ /enquirer/2.3.6:
+ resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ ansi-colors: 4.1.1
+ dev: true
+
+ /ensure-posix-path/1.1.1:
+ resolution: {integrity: sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw==}
+ dev: true
+
+ /entities/2.2.0:
+ resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==}
+ dev: true
+
+ /entities/3.0.1:
+ resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
+ engines: {node: '>=0.12'}
+ dev: true
+
+ /eol/0.9.1:
+ resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==}
+ dev: true
+
+ /errno/0.1.8:
+ resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==}
+ hasBin: true
+ dependencies:
+ prr: 1.0.1
+ dev: true
+
+ /error-ex/1.3.2:
+ resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
+ dependencies:
+ is-arrayish: 0.2.1
+ dev: true
+
+ /error-stack-parser/2.0.6:
+ resolution: {integrity: sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ==}
+ dependencies:
+ stackframe: 1.2.0
+ dev: true
+
+ /es-abstract/1.19.1:
+ resolution: {integrity: sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ es-to-primitive: 1.2.1
+ function-bind: 1.1.1
+ get-intrinsic: 1.1.1
+ get-symbol-description: 1.0.0
+ has: 1.0.3
+ has-symbols: 1.0.2
+ internal-slot: 1.0.3
+ is-callable: 1.2.4
+ is-negative-zero: 2.0.2
+ is-regex: 1.1.4
+ is-shared-array-buffer: 1.0.1
+ is-string: 1.0.7
+ is-weakref: 1.0.2
+ object-inspect: 1.12.0
+ object-keys: 1.1.1
+ object.assign: 4.1.2
+ string.prototype.trimend: 1.0.4
+ string.prototype.trimstart: 1.0.4
+ unbox-primitive: 1.0.1
+ dev: true
+
+ /es-array-method-boxes-properly/1.0.0:
+ resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==}
+ dev: true
+
+ /es-get-iterator/1.1.2:
+ resolution: {integrity: sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.1.1
+ has-symbols: 1.0.2
+ is-arguments: 1.1.1
+ is-map: 2.0.2
+ is-set: 2.0.2
+ is-string: 1.0.7
+ isarray: 2.0.5
+ dev: true
+
+ /es-module-lexer/0.9.3:
+ resolution: {integrity: sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==}
+ dev: true
+
+ /es-to-primitive/1.2.1:
+ resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ is-callable: 1.2.4
+ is-date-object: 1.0.5
+ is-symbol: 1.0.4
+ dev: true
+
+ /es5-ext/0.10.53:
+ resolution: {integrity: sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==}
+ dependencies:
+ es6-iterator: 2.0.3
+ es6-symbol: 3.1.3
+ next-tick: 1.0.0
+ dev: false
+
+ /es5-shim/4.6.4:
+ resolution: {integrity: sha512-Z0f7OUYZ8JfqT12d3Tgh2ErxIH5Shaz97GE8qyDG9quxb2Hmh2vvFHlOFjx6lzyD0CRgvJfnNYcisjdbRp7MPw==}
+ engines: {node: '>=0.4.0'}
+ dev: true
+
+ /es6-error/4.1.1:
+ resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==}
+ dev: true
+
+ /es6-iterator/2.0.3:
+ resolution: {integrity: sha1-p96IkUGgWpSwhUQDstCg+/qY87c=}
+ dependencies:
+ d: 1.0.1
+ es5-ext: 0.10.53
+ es6-symbol: 3.1.3
+ dev: false
+
+ /es6-shim/0.35.6:
+ resolution: {integrity: sha512-EmTr31wppcaIAgblChZiuN/l9Y7DPyw8Xtbg7fIVngn6zMW+IEBJDJngeKC3x6wr0V/vcA2wqeFnaw1bFJbDdA==}
+ dev: true
+
+ /es6-symbol/3.1.3:
+ resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==}
+ dependencies:
+ d: 1.0.1
+ ext: 1.6.0
+ dev: false
+
+ /esbuild-android-arm64/0.13.15:
+ resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-android-arm64/0.13.8:
+ resolution: {integrity: sha512-AilbChndywpk7CdKkNSZ9klxl+9MboLctXd9LwLo3b0dawmOF/i/t2U5d8LM6SbT1Xw36F8yngSUPrd8yPs2RA==}
+ cpu: [arm64]
+ os: [android]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-64/0.13.15:
+ resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-64/0.13.8:
+ resolution: {integrity: sha512-b6sdiT84zV5LVaoF+UoMVGJzR/iE2vNUfUDfFQGrm4LBwM/PWXweKpuu6RD9mcyCq18cLxkP6w/LD/w9DtX3ng==}
+ cpu: [x64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-arm64/0.13.15:
+ resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-darwin-arm64/0.13.8:
+ resolution: {integrity: sha512-R8YuPiiJayuJJRUBG4H0VwkEKo6AvhJs2m7Tl0JaIer3u1FHHXwGhMxjJDmK+kXwTFPriSysPvcobXC/UrrZCQ==}
+ cpu: [arm64]
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-64/0.13.15:
+ resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-64/0.13.8:
+ resolution: {integrity: sha512-zBn6urrn8FnKC+YSgDxdof9jhPCeU8kR/qaamlV4gI8R3KUaUK162WYM7UyFVAlj9N0MyD3AtB+hltzu4cysTw==}
+ cpu: [x64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-arm64/0.13.15:
+ resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-freebsd-arm64/0.13.8:
+ resolution: {integrity: sha512-pWW2slN7lGlkx0MOEBoUGwRX5UgSCLq3dy2c8RIOpiHtA87xAUpDBvZK10MykbT+aMfXc0NI2lu1X+6kI34xng==}
+ cpu: [arm64]
+ os: [freebsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-32/0.13.15:
+ resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-32/0.13.8:
+ resolution: {integrity: sha512-T0I0ueeKVO/Is0CAeSEOG9s2jeNNb8jrrMwG9QBIm3UU18MRB60ERgkS2uV3fZ1vP2F8i3Z2e3Zju4lg9dhVmw==}
+ cpu: [ia32]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-64/0.13.15:
+ resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-64/0.13.8:
+ resolution: {integrity: sha512-Bm8SYmFtvfDCIu9sjKppFXzRXn2BVpuCinU1ChTuMtdKI/7aPpXIrkqBNOgPTOQO9AylJJc1Zw6EvtKORhn64w==}
+ cpu: [x64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm/0.13.15:
+ resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm/0.13.8:
+ resolution: {integrity: sha512-4/HfcC40LJ4GPyboHA+db0jpFarTB628D1ifU+/5bunIgY+t6mHkJWyxWxAAE8wl/ZIuRYB9RJFdYpu1AXGPdg==}
+ cpu: [arm]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm64/0.13.15:
+ resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-arm64/0.13.8:
+ resolution: {integrity: sha512-X4pWZ+SL+FJ09chWFgRNO3F+YtvAQRcWh0uxKqZSWKiWodAB20flsW/OWFYLXBKiVCTeoGMvENZS/GeVac7+tQ==}
+ cpu: [arm64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-mips64le/0.13.15:
+ resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-mips64le/0.13.8:
+ resolution: {integrity: sha512-o7e0D+sqHKT31v+mwFircJFjwSKVd2nbkHEn4l9xQ1hLR+Bv8rnt3HqlblY3+sBdlrOTGSwz0ReROlKUMJyldA==}
+ cpu: [mips64el]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-ppc64le/0.13.15:
+ resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-linux-ppc64le/0.13.8:
+ resolution: {integrity: sha512-eZSQ0ERsWkukJp2px/UWJHVNuy0lMoz/HZcRWAbB6reoaBw7S9vMzYNUnflfL3XA6WDs+dZn3ekHE4Y2uWLGig==}
+ cpu: [ppc64]
+ os: [linux]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-netbsd-64/0.13.15:
+ resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-netbsd-64/0.13.8:
+ resolution: {integrity: sha512-gZX4kP7gVvOrvX0ZwgHmbuHczQUwqYppxqtoyC7VNd80t5nBHOFXVhWo2Ad/Lms0E8b+wwgI/WjZFTCpUHOg9Q==}
+ cpu: [x64]
+ os: [netbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-openbsd-64/0.13.15:
+ resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-openbsd-64/0.13.8:
+ resolution: {integrity: sha512-afzza308X4WmcebexbTzAgfEWt9MUkdTvwIa8xOu4CM2qGbl2LanqEl8/LUs8jh6Gqw6WsicEK52GPrS9wvkcw==}
+ cpu: [x64]
+ os: [openbsd]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-sunos-64/0.13.15:
+ resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-sunos-64/0.13.8:
+ resolution: {integrity: sha512-mWPZibmBbuMKD+LDN23LGcOZ2EawMYBONMXXHmbuxeT0XxCNwadbCVwUQ/2p5Dp5Kvf6mhrlIffcnWOiCBpiVw==}
+ cpu: [x64]
+ os: [sunos]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-32/0.13.15:
+ resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-32/0.13.8:
+ resolution: {integrity: sha512-QsZ1HnWIcnIEApETZWw8HlOhDSWqdZX2SylU7IzGxOYyVcX7QI06ety/aDcn437mwyO7Ph4RrbhB+2ntM8kX8A==}
+ cpu: [ia32]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-64/0.13.15:
+ resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-64/0.13.8:
+ resolution: {integrity: sha512-76Fb57B9eE/JmJi1QmUW0tRLQZfGo0it+JeYoCDTSlbTn7LV44ecOHIMJSSgZADUtRMWT9z0Kz186bnaB3amSg==}
+ cpu: [x64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-arm64/0.13.15:
+ resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild-windows-arm64/0.13.8:
+ resolution: {integrity: sha512-HW6Mtq5eTudllxY2YgT62MrVcn7oq2o8TAoAvDUhyiEmRmDY8tPwAhb1vxw5/cdkbukM3KdMYtksnUhF/ekWeg==}
+ cpu: [arm64]
+ os: [win32]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /esbuild/0.13.15:
+ resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ esbuild-android-arm64: 0.13.15
+ esbuild-darwin-64: 0.13.15
+ esbuild-darwin-arm64: 0.13.15
+ esbuild-freebsd-64: 0.13.15
+ esbuild-freebsd-arm64: 0.13.15
+ esbuild-linux-32: 0.13.15
+ esbuild-linux-64: 0.13.15
+ esbuild-linux-arm: 0.13.15
+ esbuild-linux-arm64: 0.13.15
+ esbuild-linux-mips64le: 0.13.15
+ esbuild-linux-ppc64le: 0.13.15
+ esbuild-netbsd-64: 0.13.15
+ esbuild-openbsd-64: 0.13.15
+ esbuild-sunos-64: 0.13.15
+ esbuild-windows-32: 0.13.15
+ esbuild-windows-64: 0.13.15
+ esbuild-windows-arm64: 0.13.15
+ dev: true
+
+ /esbuild/0.13.8:
+ resolution: {integrity: sha512-A4af7G7YZLfG5OnARJRMtlpEsCkq/zHZQXewgPA864l9D6VjjbH1SuFYK/OSV6BtHwDGkdwyRrX0qQFLnMfUcw==}
+ hasBin: true
+ requiresBuild: true
+ optionalDependencies:
+ esbuild-android-arm64: 0.13.8
+ esbuild-darwin-64: 0.13.8
+ esbuild-darwin-arm64: 0.13.8
+ esbuild-freebsd-64: 0.13.8
+ esbuild-freebsd-arm64: 0.13.8
+ esbuild-linux-32: 0.13.8
+ esbuild-linux-64: 0.13.8
+ esbuild-linux-arm: 0.13.8
+ esbuild-linux-arm64: 0.13.8
+ esbuild-linux-mips64le: 0.13.8
+ esbuild-linux-ppc64le: 0.13.8
+ esbuild-netbsd-64: 0.13.8
+ esbuild-openbsd-64: 0.13.8
+ esbuild-sunos-64: 0.13.8
+ esbuild-windows-32: 0.13.8
+ esbuild-windows-64: 0.13.8
+ esbuild-windows-arm64: 0.13.8
+ dev: true
+
+ /escalade/3.1.1:
+ resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /escape-html/1.0.3:
+ resolution: {integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=}
+ dev: true
+
+ /escape-string-regexp/1.0.5:
+ resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
+ engines: {node: '>=0.8.0'}
+ dev: true
+
+ /escape-string-regexp/4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /escodegen/2.0.0:
+ resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==}
+ engines: {node: '>=6.0'}
+ hasBin: true
+ dependencies:
+ esprima: 4.0.1
+ estraverse: 5.3.0
+ esutils: 2.0.3
+ optionator: 0.8.3
+ optionalDependencies:
+ source-map: 0.6.1
+ dev: true
+
+ /eslint-config-prettier/8.3.0_eslint@8.8.0:
+ resolution: {integrity: sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==}
+ hasBin: true
+ peerDependencies:
+ eslint: '>=7.0.0'
+ dependencies:
+ eslint: 8.8.0
+ dev: true
+
+ /eslint-plugin-prettier/4.0.0_punao7uarsvpb6gm4i6ih2skcq:
+ resolution: {integrity: sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==}
+ engines: {node: '>=6.0.0'}
+ peerDependencies:
+ eslint: '>=7.28.0'
+ eslint-config-prettier: '*'
+ prettier: '>=2.0.0'
+ peerDependenciesMeta:
+ eslint-config-prettier:
+ optional: true
+ prettier:
+ optional: true
+ dependencies:
+ eslint: 8.8.0
+ eslint-config-prettier: 8.3.0_eslint@8.8.0
+ prettier-linter-helpers: 1.0.0
+ dev: true
+
+ /eslint-plugin-react/7.28.0_eslint@8.8.0:
+ resolution: {integrity: sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
+ dependencies:
+ array-includes: 3.1.4
+ array.prototype.flatmap: 1.2.5
+ doctrine: 2.1.0
+ eslint: 8.8.0
+ estraverse: 5.3.0
+ jsx-ast-utils: 3.2.1
+ minimatch: 3.0.5
+ object.entries: 1.1.5
+ object.fromentries: 2.0.5
+ object.hasown: 1.1.0
+ object.values: 1.1.5
+ prop-types: 15.8.1
+ resolve: 2.0.0-next.3
+ semver: 6.3.0
+ string.prototype.matchall: 4.0.6
+ dev: true
+
+ /eslint-scope/4.0.3:
+ resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 4.3.0
+ dev: true
+
+ /eslint-scope/7.1.0:
+ resolution: {integrity: sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ esrecurse: 4.3.0
+ estraverse: 5.3.0
+ dev: true
+
+ /eslint-utils/3.0.0_eslint@8.8.0:
+ resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==}
+ engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0}
+ peerDependencies:
+ eslint: '>=5'
+ dependencies:
+ eslint: 8.8.0
+ eslint-visitor-keys: 2.1.0
+ dev: true
+
+ /eslint-visitor-keys/2.1.0:
+ resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /eslint-visitor-keys/3.2.0:
+ resolution: {integrity: sha512-IOzT0X126zn7ALX0dwFiUQEdsfzrm4+ISsQS8nukaJXwEyYKRSnEIIDULYg1mCtGp7UUXgfGl7BIolXREQK+XQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dev: true
+
+ /eslint/8.8.0:
+ resolution: {integrity: sha512-H3KXAzQGBH1plhYS3okDix2ZthuYJlQQEGE5k0IKuEqUSiyu4AmxxlJ2MtTYeJ3xB4jDhcYCwGOg2TXYdnDXlQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ '@eslint/eslintrc': 1.0.5
+ '@humanwhocodes/config-array': 0.9.3
+ ajv: 6.12.6
+ chalk: 4.1.2
+ cross-spawn: 7.0.3
+ debug: 4.3.3
+ doctrine: 3.0.0
+ escape-string-regexp: 4.0.0
+ eslint-scope: 7.1.0
+ eslint-utils: 3.0.0_eslint@8.8.0
+ eslint-visitor-keys: 3.2.0
+ espree: 9.3.0
+ esquery: 1.4.0
+ esutils: 2.0.3
+ fast-deep-equal: 3.1.3
+ file-entry-cache: 6.0.1
+ functional-red-black-tree: 1.0.1
+ glob-parent: 6.0.2
+ globals: 13.12.1
+ ignore: 5.2.0
+ import-fresh: 3.3.0
+ imurmurhash: 0.1.4
+ is-glob: 4.0.3
+ js-yaml: 4.1.0
+ json-stable-stringify-without-jsonify: 1.0.1
+ levn: 0.4.1
+ lodash.merge: 4.6.2
+ minimatch: 3.0.5
+ natural-compare: 1.4.0
+ optionator: 0.9.1
+ regexpp: 3.2.0
+ strip-ansi: 6.0.1
+ strip-json-comments: 3.1.1
+ text-table: 0.2.0
+ v8-compile-cache: 2.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /espree/9.3.0:
+ resolution: {integrity: sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==}
+ engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
+ dependencies:
+ acorn: 8.7.0
+ acorn-jsx: 5.3.2_acorn@8.7.0
+ eslint-visitor-keys: 3.2.0
+ dev: true
+
+ /esprima/4.0.1:
+ resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /esquery/1.4.0:
+ resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /esrecurse/4.3.0:
+ resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ estraverse: 5.3.0
+ dev: true
+
+ /estraverse/4.3.0:
+ resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /estraverse/5.3.0:
+ resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
+ engines: {node: '>=4.0'}
+ dev: true
+
+ /estree-to-babel/3.2.1:
+ resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==}
+ engines: {node: '>=8.3.0'}
+ dependencies:
+ '@babel/traverse': 7.17.0
+ '@babel/types': 7.17.0
+ c8: 7.11.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /estree-walker/2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+ dev: true
+
+ /esutils/2.0.3:
+ resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /etag/1.8.1:
+ resolution: {integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /eventemitter2/6.4.5:
+ resolution: {integrity: sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==}
+ dev: true
+
+ /eventemitter3/4.0.7:
+ resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
+ dev: false
+
+ /events/2.1.0:
+ resolution: {integrity: sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg==}
+ engines: {node: '>=0.4.x'}
+ dev: true
+
+ /events/3.3.0:
+ resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
+ engines: {node: '>=0.8.x'}
+ dev: true
+
+ /evp_bytestokey/1.0.3:
+ resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==}
+ dependencies:
+ md5.js: 1.3.5
+ safe-buffer: 5.2.1
+ dev: true
+
+ /exec-sh/0.3.6:
+ resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==}
+ dev: true
+
+ /execa/1.0.0:
+ resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==}
+ engines: {node: '>=6'}
+ dependencies:
+ cross-spawn: 6.0.5
+ get-stream: 4.1.0
+ is-stream: 1.1.0
+ npm-run-path: 2.0.2
+ p-finally: 1.0.0
+ signal-exit: 3.0.7
+ strip-eof: 1.0.0
+ dev: true
+
+ /execa/4.1.0:
+ resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==}
+ engines: {node: '>=10'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 5.2.0
+ human-signals: 1.1.1
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+ dev: true
+
+ /execa/5.1.1:
+ resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
+ engines: {node: '>=10'}
+ dependencies:
+ cross-spawn: 7.0.3
+ get-stream: 6.0.1
+ human-signals: 2.1.0
+ is-stream: 2.0.1
+ merge-stream: 2.0.0
+ npm-run-path: 4.0.1
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ strip-final-newline: 2.0.0
+ dev: true
+
+ /executable/4.1.1:
+ resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==}
+ engines: {node: '>=4'}
+ dependencies:
+ pify: 2.3.0
+ dev: true
+
+ /expand-brackets/2.1.4:
+ resolution: {integrity: sha1-t3c14xXOMPa27/D4OwQVGiJEliI=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ debug: 2.6.9
+ define-property: 0.2.5
+ extend-shallow: 2.0.1
+ posix-character-classes: 0.1.1
+ regex-not: 1.0.2
+ snapdragon: 0.8.2
+ to-regex: 3.0.2
+ dev: true
+
+ /express/4.17.2:
+ resolution: {integrity: sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==}
+ engines: {node: '>= 0.10.0'}
+ dependencies:
+ accepts: 1.3.8
+ array-flatten: 1.1.1
+ body-parser: 1.19.1
+ content-disposition: 0.5.4
+ content-type: 1.0.4
+ cookie: 0.4.1
+ cookie-signature: 1.0.6
+ debug: 2.6.9
+ depd: 1.1.2
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ finalhandler: 1.1.2
+ fresh: 0.5.2
+ merge-descriptors: 1.0.1
+ methods: 1.1.2
+ on-finished: 2.3.0
+ parseurl: 1.3.3
+ path-to-regexp: 0.1.7
+ proxy-addr: 2.0.7
+ qs: 6.9.6
+ range-parser: 1.2.1
+ safe-buffer: 5.2.1
+ send: 0.17.2
+ serve-static: 1.14.2
+ setprototypeof: 1.2.0
+ statuses: 1.5.0
+ type-is: 1.6.18
+ utils-merge: 1.0.1
+ vary: 1.1.2
+ dev: true
+
+ /ext/1.6.0:
+ resolution: {integrity: sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg==}
+ dependencies:
+ type: 2.6.0
+ dev: false
+
+ /extend-shallow/2.0.1:
+ resolution: {integrity: sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extendable: 0.1.1
+ dev: true
+
+ /extend-shallow/3.0.2:
+ resolution: {integrity: sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ assign-symbols: 1.0.0
+ is-extendable: 1.0.1
+ dev: true
+
+ /extend/3.0.2:
+ resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
+ dev: true
+
+ /extglob/2.0.4:
+ resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ array-unique: 0.3.2
+ define-property: 1.0.0
+ expand-brackets: 2.1.4
+ extend-shallow: 2.0.1
+ fragment-cache: 0.2.1
+ regex-not: 1.0.2
+ snapdragon: 0.8.2
+ to-regex: 3.0.2
+ dev: true
+
+ /extract-zip/2.0.1_supports-color@8.1.1:
+ resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==}
+ engines: {node: '>= 10.17.0'}
+ hasBin: true
+ dependencies:
+ debug: 4.3.3_supports-color@8.1.1
+ get-stream: 5.2.0
+ yauzl: 2.10.0
+ optionalDependencies:
+ '@types/yauzl': 2.9.2
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /extsprintf/1.3.0:
+ resolution: {integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=}
+ engines: {'0': node >=0.6.0}
+ dev: true
+
+ /fast-deep-equal/2.0.1:
+ resolution: {integrity: sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=}
+ dev: true
+
+ /fast-deep-equal/3.1.3:
+ resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
+
+ /fast-diff/1.2.0:
+ resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
+ dev: true
+
+ /fast-glob/2.2.7:
+ resolution: {integrity: sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ '@mrmlnc/readdir-enhanced': 2.2.1
+ '@nodelib/fs.stat': 1.1.3
+ glob-parent: 3.1.0
+ is-glob: 4.0.3
+ merge2: 1.4.1
+ micromatch: 3.1.10
+ dev: true
+
+ /fast-glob/3.2.11:
+ resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==}
+ engines: {node: '>=8.6.0'}
+ dependencies:
+ '@nodelib/fs.stat': 2.0.5
+ '@nodelib/fs.walk': 1.2.8
+ glob-parent: 5.1.2
+ merge2: 1.4.1
+ micromatch: 4.0.4
+ dev: true
+
+ /fast-json-parse/1.0.3:
+ resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==}
+ dev: true
+
+ /fast-json-stable-stringify/2.1.0:
+ resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
+ dev: true
+
+ /fast-levenshtein/2.0.6:
+ resolution: {integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=}
+ dev: true
+
+ /fast-safe-stringify/2.1.1:
+ resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==}
+ dev: true
+
+ /fastq/1.13.0:
+ resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==}
+ dependencies:
+ reusify: 1.0.4
+ dev: true
+
+ /fault/1.0.4:
+ resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==}
+ dependencies:
+ format: 0.2.2
+ dev: true
+
+ /fb-watchman/2.0.1:
+ resolution: {integrity: sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==}
+ dependencies:
+ bser: 2.1.1
+ dev: true
+
+ /fd-slicer/1.1.0:
+ resolution: {integrity: sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=}
+ dependencies:
+ pend: 1.2.0
+ dev: true
+
+ /figgy-pudding/3.5.2:
+ resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==}
+ dev: true
+
+ /figures/3.2.0:
+ resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==}
+ engines: {node: '>=8'}
+ dependencies:
+ escape-string-regexp: 1.0.5
+ dev: true
+
+ /file-entry-cache/6.0.1:
+ resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flat-cache: 3.0.4
+ dev: true
+
+ /file-loader/6.2.0_webpack@4.46.0:
+ resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ loader-utils: 2.0.2
+ schema-utils: 3.1.1
+ webpack: 4.46.0
+ dev: true
+
+ /file-saver/2.0.5:
+ resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+ dev: false
+
+ /file-system-cache/1.0.5:
+ resolution: {integrity: sha1-hCWbNqK7uNPW6xAh0xMv/mTP/08=}
+ dependencies:
+ bluebird: 3.7.2
+ fs-extra: 0.30.0
+ ramda: 0.21.0
+ dev: true
+
+ /file-uri-to-path/1.0.0:
+ resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /fill-range/4.0.0:
+ resolution: {integrity: sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ extend-shallow: 2.0.1
+ is-number: 3.0.0
+ repeat-string: 1.6.1
+ to-regex-range: 2.1.1
+ dev: true
+
+ /fill-range/7.0.1:
+ resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ to-regex-range: 5.0.1
+ dev: true
+
+ /finalhandler/1.1.2:
+ resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ debug: 2.6.9
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ on-finished: 2.3.0
+ parseurl: 1.3.3
+ statuses: 1.5.0
+ unpipe: 1.0.0
+ dev: true
+
+ /find-cache-dir/2.1.0:
+ resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ commondir: 1.0.1
+ make-dir: 2.1.0
+ pkg-dir: 3.0.0
+ dev: true
+
+ /find-cache-dir/3.3.2:
+ resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==}
+ engines: {node: '>=8'}
+ dependencies:
+ commondir: 1.0.1
+ make-dir: 3.1.0
+ pkg-dir: 4.2.0
+ dev: true
+
+ /find-root/1.1.0:
+ resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
+ dev: true
+
+ /find-up/3.0.0:
+ resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==}
+ engines: {node: '>=6'}
+ dependencies:
+ locate-path: 3.0.0
+ dev: true
+
+ /find-up/4.1.0:
+ resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==}
+ engines: {node: '>=8'}
+ dependencies:
+ locate-path: 5.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /find-up/5.0.0:
+ resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
+ engines: {node: '>=10'}
+ dependencies:
+ locate-path: 6.0.0
+ path-exists: 4.0.0
+ dev: true
+
+ /flat-cache/3.0.4:
+ resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==}
+ engines: {node: ^10.12.0 || >=12.0.0}
+ dependencies:
+ flatted: 3.2.5
+ rimraf: 3.0.2
+ dev: true
+
+ /flatted/3.2.5:
+ resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==}
+ dev: true
+
+ /flush-write-stream/1.1.1:
+ resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /follow-redirects/1.14.7:
+ resolution: {integrity: sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==}
+ engines: {node: '>=4.0'}
+ peerDependencies:
+ debug: '*'
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ dev: false
+
+ /for-in/1.0.2:
+ resolution: {integrity: sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /foreach/2.0.5:
+ resolution: {integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k=}
+ dev: true
+
+ /foreground-child/2.0.0:
+ resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ cross-spawn: 7.0.3
+ signal-exit: 3.0.7
+ dev: true
+
+ /forever-agent/0.6.1:
+ resolution: {integrity: sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=}
+ dev: true
+
+ /fork-ts-checker-webpack-plugin/4.1.6:
+ resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==}
+ engines: {node: '>=6.11.5', yarn: '>=1.0.0'}
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ chalk: 2.4.2
+ micromatch: 3.1.10
+ minimatch: 3.0.5
+ semver: 5.7.1
+ tapable: 1.1.3
+ worker-rpc: 0.1.1
+ dev: true
+
+ /fork-ts-checker-webpack-plugin/6.5.0_q5wy7dh6g63ozjytk4pnktq6de:
+ resolution: {integrity: sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw==}
+ engines: {node: '>=10', yarn: '>=1.0.0'}
+ peerDependencies:
+ eslint: '>= 6'
+ typescript: '>= 2.7'
+ vue-template-compiler: '*'
+ webpack: '>= 4'
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ vue-template-compiler:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ '@types/json-schema': 7.0.9
+ chalk: 4.1.2
+ chokidar: 3.5.3
+ cosmiconfig: 6.0.0
+ deepmerge: 4.2.2
+ eslint: 8.8.0
+ fs-extra: 9.1.0
+ glob: 7.2.0
+ memfs: 3.4.1
+ minimatch: 3.0.5
+ schema-utils: 2.7.0
+ semver: 7.3.5
+ tapable: 1.1.3
+ typescript: 4.5.5
+ webpack: 4.46.0
+ dev: true
+
+ /form-data/2.3.3:
+ resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==}
+ engines: {node: '>= 0.12'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.34
+ dev: true
+
+ /form-data/3.0.1:
+ resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
+ engines: {node: '>= 6'}
+ dependencies:
+ asynckit: 0.4.0
+ combined-stream: 1.0.8
+ mime-types: 2.1.34
+ dev: true
+
+ /format/0.2.2:
+ resolution: {integrity: sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=}
+ engines: {node: '>=0.4.x'}
+ dev: true
+
+ /forwarded/0.2.0:
+ resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /fragment-cache/0.2.1:
+ resolution: {integrity: sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ map-cache: 0.2.2
+ dev: true
+
+ /framer-motion/6.2.4_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-1UfnSG4c4CefKft6QMYGx8AWt3TtaFoR/Ax4dkuDDD5BDDeIuUm7gesmJrF8GzxeX/i6fMm8+MEdPngUyPVdLA==}
+ peerDependencies:
+ react: '>=16.8 || ^17.0.0 || 17'
+ react-dom: '>=16.8 || ^17.0.0 || 17'
+ dependencies:
+ framesync: 6.0.1
+ hey-listen: 1.0.8
+ popmotion: 11.0.3
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ style-value-types: 5.0.0
+ tslib: 2.3.1
+ optionalDependencies:
+ '@emotion/is-prop-valid': 0.8.8
+ dev: false
+
+ /framesync/6.0.1:
+ resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==}
+ dependencies:
+ tslib: 2.3.1
+ dev: false
+
+ /fresh/0.5.2:
+ resolution: {integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /from2/2.3.0:
+ resolution: {integrity: sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /fromentries/1.3.2:
+ resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==}
+ dev: true
+
+ /fs-extra/0.30.0:
+ resolution: {integrity: sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=}
+ dependencies:
+ graceful-fs: 4.2.9
+ jsonfile: 2.4.0
+ klaw: 1.3.1
+ path-is-absolute: 1.0.1
+ rimraf: 2.7.1
+ dev: true
+
+ /fs-extra/10.0.0:
+ resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ graceful-fs: 4.2.9
+ jsonfile: 6.1.0
+ universalify: 2.0.0
+ dev: true
+
+ /fs-extra/8.1.0:
+ resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
+ engines: {node: '>=6 <7 || >=8'}
+ dependencies:
+ graceful-fs: 4.2.9
+ jsonfile: 4.0.0
+ universalify: 0.1.2
+ dev: true
+
+ /fs-extra/9.1.0:
+ resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ at-least-node: 1.0.0
+ graceful-fs: 4.2.9
+ jsonfile: 6.1.0
+ universalify: 2.0.0
+ dev: true
+
+ /fs-merger/3.2.1:
+ resolution: {integrity: sha512-AN6sX12liy0JE7C2evclwoo0aCG3PFulLjrTLsJpWh/2mM+DinhpSGqYLbHBBbIW1PLRNcFhJG8Axtz8mQW3ug==}
+ dependencies:
+ broccoli-node-api: 1.7.0
+ broccoli-node-info: 2.2.0
+ fs-extra: 8.1.0
+ fs-tree-diff: 2.0.1
+ walk-sync: 2.2.0
+ dev: true
+
+ /fs-minipass/2.1.0:
+ resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ minipass: 3.1.6
+ dev: true
+
+ /fs-mkdirp-stream/1.0.0:
+ resolution: {integrity: sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ graceful-fs: 4.2.9
+ through2: 2.0.5
+ dev: true
+
+ /fs-monkey/1.0.3:
+ resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==}
+ dev: true
+
+ /fs-tree-diff/2.0.1:
+ resolution: {integrity: sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dependencies:
+ '@types/symlink-or-copy': 1.2.0
+ heimdalljs-logger: 0.1.10
+ object-assign: 4.1.1
+ path-posix: 1.0.0
+ symlink-or-copy: 1.3.1
+ dev: true
+
+ /fs-write-stream-atomic/1.0.10:
+ resolution: {integrity: sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=}
+ dependencies:
+ graceful-fs: 4.2.9
+ iferr: 0.1.5
+ imurmurhash: 0.1.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /fs.realpath/1.0.0:
+ resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=}
+ dev: true
+
+ /fsevents/1.2.13:
+ resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==}
+ engines: {node: '>= 4.0'}
+ os: [darwin]
+ deprecated: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.
+ requiresBuild: true
+ dependencies:
+ bindings: 1.5.0
+ nan: 2.15.0
+ dev: true
+ optional: true
+
+ /fsevents/2.3.2:
+ resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
+ engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
+ os: [darwin]
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /function-bind/1.1.1:
+ resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
+ dev: true
+
+ /function.prototype.name/1.1.5:
+ resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ functions-have-names: 1.2.2
+ dev: true
+
+ /functional-red-black-tree/1.0.1:
+ resolution: {integrity: sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=}
+ dev: true
+
+ /functions-have-names/1.2.2:
+ resolution: {integrity: sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==}
+ dev: true
+
+ /fuse.js/3.6.1:
+ resolution: {integrity: sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /gauge/3.0.2:
+ resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ aproba: 2.0.0
+ color-support: 1.1.3
+ console-control-strings: 1.1.0
+ has-unicode: 2.0.1
+ object-assign: 4.1.1
+ signal-exit: 3.0.7
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ wide-align: 1.1.5
+ dev: true
+
+ /gensync/1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+ dev: true
+
+ /get-assigned-identifiers/1.2.0:
+ resolution: {integrity: sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==}
+ dev: true
+
+ /get-caller-file/2.0.5:
+ resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dev: true
+
+ /get-intrinsic/1.1.1:
+ resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
+ dependencies:
+ function-bind: 1.1.1
+ has: 1.0.3
+ has-symbols: 1.0.2
+ dev: true
+
+ /get-package-type/0.1.0:
+ resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
+ engines: {node: '>=8.0.0'}
+ dev: true
+
+ /get-stream/4.1.0:
+ resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
+ engines: {node: '>=6'}
+ dependencies:
+ pump: 3.0.0
+ dev: true
+
+ /get-stream/5.2.0:
+ resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==}
+ engines: {node: '>=8'}
+ dependencies:
+ pump: 3.0.0
+ dev: true
+
+ /get-stream/6.0.1:
+ resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /get-symbol-description/1.0.0:
+ resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.1.1
+ dev: true
+
+ /get-value/2.0.6:
+ resolution: {integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /getos/3.2.1:
+ resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==}
+ dependencies:
+ async: 3.2.3
+ dev: true
+
+ /getpass/0.1.7:
+ resolution: {integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=}
+ dependencies:
+ assert-plus: 1.0.0
+ dev: true
+
+ /github-slugger/1.4.0:
+ resolution: {integrity: sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==}
+ dev: true
+
+ /glob-parent/3.1.0:
+ resolution: {integrity: sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=}
+ dependencies:
+ is-glob: 3.1.0
+ path-dirname: 1.0.2
+ dev: true
+
+ /glob-parent/5.1.2:
+ resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
+ engines: {node: '>= 6'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-parent/6.0.2:
+ resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ is-glob: 4.0.3
+ dev: true
+
+ /glob-promise/3.4.0_glob@7.2.0:
+ resolution: {integrity: sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==}
+ engines: {node: '>=4'}
+ peerDependencies:
+ glob: '*'
+ dependencies:
+ '@types/glob': 7.2.0
+ glob: 7.2.0
+ dev: true
+
+ /glob-promise/4.2.2_glob@7.2.0:
+ resolution: {integrity: sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ glob: ^7.1.6
+ dependencies:
+ '@types/glob': 7.2.0
+ glob: 7.2.0
+ dev: true
+
+ /glob-stream/6.1.0:
+ resolution: {integrity: sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ extend: 3.0.2
+ glob: 7.2.0
+ glob-parent: 3.1.0
+ is-negated-glob: 1.0.0
+ ordered-read-streams: 1.0.1
+ pumpify: 1.5.1
+ readable-stream: 2.3.7
+ remove-trailing-separator: 1.1.0
+ to-absolute-glob: 2.0.2
+ unique-stream: 2.3.1
+ dev: true
+
+ /glob-to-regexp/0.3.0:
+ resolution: {integrity: sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=}
+ dev: true
+
+ /glob-to-regexp/0.4.1:
+ resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
+ dev: true
+
+ /glob/7.2.0:
+ resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==}
+ dependencies:
+ fs.realpath: 1.0.0
+ inflight: 1.0.6
+ inherits: 2.0.4
+ minimatch: 3.0.5
+ once: 1.4.0
+ path-is-absolute: 1.0.1
+ dev: true
+
+ /global-dirs/3.0.0:
+ resolution: {integrity: sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ ini: 2.0.0
+ dev: true
+
+ /global/4.4.0:
+ resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
+ dependencies:
+ min-document: 2.19.0
+ process: 0.11.10
+ dev: true
+
+ /globals/11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /globals/13.12.1:
+ resolution: {integrity: sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==}
+ engines: {node: '>=8'}
+ dependencies:
+ type-fest: 0.20.2
+ dev: true
+
+ /globalthis/1.0.2:
+ resolution: {integrity: sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ define-properties: 1.1.3
+ dev: true
+
+ /globby/11.0.4:
+ resolution: {integrity: sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.2.11
+ ignore: 5.2.0
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /globby/11.1.0:
+ resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
+ engines: {node: '>=10'}
+ dependencies:
+ array-union: 2.1.0
+ dir-glob: 3.0.1
+ fast-glob: 3.2.11
+ ignore: 5.2.0
+ merge2: 1.4.1
+ slash: 3.0.0
+ dev: true
+
+ /globby/9.2.0:
+ resolution: {integrity: sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==}
+ engines: {node: '>=6'}
+ dependencies:
+ '@types/glob': 7.2.0
+ array-union: 1.0.2
+ dir-glob: 2.2.2
+ fast-glob: 2.2.7
+ glob: 7.2.0
+ ignore: 4.0.6
+ pify: 4.0.1
+ slash: 2.0.0
+ dev: true
+
+ /google-map-react/2.1.10_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-cqW2EcygYqF26inp5liM/pAcCwOGXB9LW32oGwf931Iuq8tnasCpyEtq87G+RyQCKCo2P8/QyV+MGHuc7r9AEg==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: ^16.0.0 || ^17.0.0 || 17
+ react-dom: ^16.0.0 || ^17.0.0 || 17
+ dependencies:
+ '@googlemaps/js-api-loader': 1.13.4
+ '@mapbox/point-geometry': 0.1.0
+ eventemitter3: 4.0.7
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /graceful-fs/4.2.9:
+ resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==}
+ dev: true
+
+ /gulp-sort/2.0.0:
+ resolution: {integrity: sha1-xnYqLx8N4KP8WVohWZ0/rI26Gso=}
+ dependencies:
+ through2: 2.0.5
+ dev: true
+
+ /handlebars/4.7.7:
+ resolution: {integrity: sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==}
+ engines: {node: '>=0.4.7'}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.5
+ neo-async: 2.6.2
+ source-map: 0.6.1
+ wordwrap: 1.0.0
+ optionalDependencies:
+ uglify-js: 3.15.1
+ dev: true
+
+ /has-bigints/1.0.1:
+ resolution: {integrity: sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==}
+ dev: true
+
+ /has-flag/3.0.0:
+ resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /has-flag/4.0.0:
+ resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /has-glob/1.0.0:
+ resolution: {integrity: sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-glob: 3.1.0
+ dev: true
+
+ /has-symbols/1.0.2:
+ resolution: {integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /has-tostringtag/1.0.0:
+ resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.2
+ dev: true
+
+ /has-unicode/2.0.1:
+ resolution: {integrity: sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=}
+ dev: true
+
+ /has-value/0.3.1:
+ resolution: {integrity: sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ get-value: 2.0.6
+ has-values: 0.1.4
+ isobject: 2.1.0
+ dev: true
+
+ /has-value/1.0.0:
+ resolution: {integrity: sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ get-value: 2.0.6
+ has-values: 1.0.0
+ isobject: 3.0.1
+ dev: true
+
+ /has-values/0.1.4:
+ resolution: {integrity: sha1-bWHeldkd/Km5oCCJrThL/49it3E=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /has-values/1.0.0:
+ resolution: {integrity: sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-number: 3.0.0
+ kind-of: 4.0.0
+ dev: true
+
+ /has/1.0.3:
+ resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
+ engines: {node: '>= 0.4.0'}
+ dependencies:
+ function-bind: 1.1.1
+ dev: true
+
+ /hash-base/3.1.0:
+ resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==}
+ engines: {node: '>=4'}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 3.6.0
+ safe-buffer: 5.2.1
+ dev: true
+
+ /hash.js/1.1.7:
+ resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==}
+ dependencies:
+ inherits: 2.0.4
+ minimalistic-assert: 1.0.1
+ dev: true
+
+ /hasha/5.2.2:
+ resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ is-stream: 2.0.1
+ type-fest: 0.8.1
+ dev: true
+
+ /hast-to-hyperscript/9.0.1:
+ resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==}
+ dependencies:
+ '@types/unist': 2.0.6
+ comma-separated-tokens: 1.0.8
+ property-information: 5.6.0
+ space-separated-tokens: 1.1.5
+ style-to-object: 0.3.0
+ unist-util-is: 4.1.0
+ web-namespaces: 1.1.4
+ dev: true
+
+ /hast-util-from-parse5/6.0.1:
+ resolution: {integrity: sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==}
+ dependencies:
+ '@types/parse5': 5.0.3
+ hastscript: 6.0.0
+ property-information: 5.6.0
+ vfile: 4.2.1
+ vfile-location: 3.2.0
+ web-namespaces: 1.1.4
+ dev: true
+
+ /hast-util-parse-selector/2.2.5:
+ resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==}
+ dev: true
+
+ /hast-util-raw/6.0.1:
+ resolution: {integrity: sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==}
+ dependencies:
+ '@types/hast': 2.3.4
+ hast-util-from-parse5: 6.0.1
+ hast-util-to-parse5: 6.0.0
+ html-void-elements: 1.0.5
+ parse5: 6.0.1
+ unist-util-position: 3.1.0
+ vfile: 4.2.1
+ web-namespaces: 1.1.4
+ xtend: 4.0.2
+ zwitch: 1.0.5
+ dev: true
+
+ /hast-util-to-parse5/6.0.0:
+ resolution: {integrity: sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==}
+ dependencies:
+ hast-to-hyperscript: 9.0.1
+ property-information: 5.6.0
+ web-namespaces: 1.1.4
+ xtend: 4.0.2
+ zwitch: 1.0.5
+ dev: true
+
+ /hastscript/6.0.0:
+ resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==}
+ dependencies:
+ '@types/hast': 2.3.4
+ comma-separated-tokens: 1.0.8
+ hast-util-parse-selector: 2.2.5
+ property-information: 5.6.0
+ space-separated-tokens: 1.1.5
+ dev: true
+
+ /he/1.2.0:
+ resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
+ hasBin: true
+ dev: true
+
+ /heimdalljs-logger/0.1.10:
+ resolution: {integrity: sha512-pO++cJbhIufVI/fmB/u2Yty3KJD0TqNPecehFae0/eps0hkZ3b4Zc/PezUMOpYuHFQbA7FxHZxa305EhmjLj4g==}
+ dependencies:
+ debug: 2.6.9
+ heimdalljs: 0.2.6
+ dev: true
+
+ /heimdalljs/0.2.6:
+ resolution: {integrity: sha512-o9bd30+5vLBvBtzCPwwGqpry2+n0Hi6H1+qwt6y+0kwRHGGF8TFIhJPmnuM0xO97zaKrDZMwO/V56fAnn8m/tA==}
+ dependencies:
+ rsvp: 3.2.1
+ dev: true
+
+ /hey-listen/1.0.8:
+ resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
+ dev: false
+
+ /highlight.js/10.7.3:
+ resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==}
+ dev: true
+
+ /history/4.10.1:
+ resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ loose-envify: 1.4.0
+ resolve-pathname: 3.0.0
+ tiny-invariant: 1.2.0
+ tiny-warning: 1.0.3
+ value-equal: 1.0.1
+ dev: false
+
+ /history/5.0.0:
+ resolution: {integrity: sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: true
+
+ /history/5.2.0:
+ resolution: {integrity: sha512-uPSF6lAJb3nSePJ43hN3eKj1dTWpN9gMod0ZssbFTIsen+WehTmEadgL+kg78xLJFdRfrrC//SavDzmRVdE+Ig==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+
+ /hmac-drbg/1.0.1:
+ resolution: {integrity: sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=}
+ dependencies:
+ hash.js: 1.1.7
+ minimalistic-assert: 1.0.1
+ minimalistic-crypto-utils: 1.0.1
+ dev: true
+
+ /hoist-non-react-statics/2.5.5:
+ resolution: {integrity: sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==}
+ dev: false
+
+ /hoist-non-react-statics/3.3.2:
+ resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+ dependencies:
+ react-is: 16.13.1
+
+ /hosted-git-info/2.8.9:
+ resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
+ dev: true
+
+ /html-entities/2.3.2:
+ resolution: {integrity: sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==}
+ dev: true
+
+ /html-escaper/2.0.2:
+ resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==}
+
+ /html-minifier-terser/5.1.1:
+ resolution: {integrity: sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dependencies:
+ camel-case: 4.1.2
+ clean-css: 4.2.4
+ commander: 4.1.1
+ he: 1.2.0
+ param-case: 3.0.4
+ relateurl: 0.2.7
+ terser: 4.8.0
+ dev: true
+
+ /html-parse-stringify/3.0.1:
+ resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==}
+ dependencies:
+ void-elements: 3.1.0
+ dev: false
+
+ /html-tags/3.1.0:
+ resolution: {integrity: sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /html-void-elements/1.0.5:
+ resolution: {integrity: sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==}
+ dev: true
+
+ /html-webpack-plugin/4.5.2_webpack@4.46.0:
+ resolution: {integrity: sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==}
+ engines: {node: '>=6.9'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ '@types/html-minifier-terser': 5.1.2
+ '@types/tapable': 1.0.8
+ '@types/webpack': 4.41.32
+ html-minifier-terser: 5.1.1
+ loader-utils: 1.4.0
+ lodash: 4.17.21
+ pretty-error: 2.1.2
+ tapable: 1.1.3
+ util.promisify: 1.0.0
+ webpack: 4.46.0
+ dev: true
+
+ /html2canvas/1.4.1:
+ resolution: {integrity: sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==}
+ engines: {node: '>=8.0.0'}
+ dependencies:
+ css-line-break: 2.1.0
+ text-segmentation: 1.0.3
+ dev: false
+
+ /htmlescape/1.1.1:
+ resolution: {integrity: sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=}
+ engines: {node: '>=0.10'}
+ dev: true
+
+ /htmlparser2/6.1.0:
+ resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==}
+ dependencies:
+ domelementtype: 2.2.0
+ domhandler: 4.3.0
+ domutils: 2.8.0
+ entities: 2.2.0
+ dev: true
+
+ /http-errors/1.8.1:
+ resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ depd: 1.1.2
+ inherits: 2.0.4
+ setprototypeof: 1.2.0
+ statuses: 1.5.0
+ toidentifier: 1.0.1
+ dev: true
+
+ /http-signature/1.3.6:
+ resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ assert-plus: 1.0.0
+ jsprim: 2.0.2
+ sshpk: 1.17.0
+ dev: true
+
+ /https-browserify/1.0.0:
+ resolution: {integrity: sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=}
+ dev: true
+
+ /human-signals/1.1.1:
+ resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==}
+ engines: {node: '>=8.12.0'}
+ dev: true
+
+ /human-signals/2.1.0:
+ resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
+ engines: {node: '>=10.17.0'}
+ dev: true
+
+ /hyphenate-style-name/1.0.4:
+ resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==}
+ dev: false
+
+ /i18next-browser-languagedetector/6.1.3:
+ resolution: {integrity: sha512-T+oGXHXtrur14CGnZZ7qQ07X38XJQEI00b/4ILrtO6xPbwTlQ1wtMZC2H+tBULixHuVUXv8LKbxfjyITJkezUg==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: false
+
+ /i18next-parser/5.4.0:
+ resolution: {integrity: sha512-AkMOy3NW09tnB+4CAVzHVWxhoab8q1L6E3aIugWeTZqbUVYTjb6dtW1AhiiUd4nLMOj29LaaVCkyqOhrTezp7Q==}
+ engines: {node: '>=12', npm: '>=6', yarn: '>=1'}
+ hasBin: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ broccoli-plugin: 4.0.7
+ cheerio: 1.0.0-rc.10
+ colors: 1.4.0
+ commander: 8.3.0
+ concat-stream: 2.0.0
+ eol: 0.9.1
+ fs-extra: 10.0.0
+ gulp-sort: 2.0.0
+ i18next: 21.6.11
+ js-yaml: 4.1.0
+ rsvp: 4.8.5
+ sort-keys: 4.2.0
+ through2: 4.0.2
+ typescript: 4.5.5
+ vinyl: 2.2.1
+ vinyl-fs: 3.0.3
+ vue-template-compiler: 2.6.14
+ dev: true
+
+ /i18next-xhr-backend/3.2.2:
+ resolution: {integrity: sha512-OtRf2Vo3IqAxsttQbpjYnmMML12IMB5e0fc5B7qKJFLScitYaXa1OhMX0n0X/3vrfFlpHL9Ro/H+ps4Ej2j7QQ==}
+ deprecated: replaced by i18next-http-backend
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: false
+
+ /i18next/21.6.11:
+ resolution: {integrity: sha512-tJ2+o0lVO+fhi8bPkCpBAeY1SgkqmQm5NzgPWCQssBrywJw98/o+Kombhty5nxQOpHtvMmsxcOopczUiH6bJxQ==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+
+ /icepick/1.3.0:
+ resolution: {integrity: sha1-5JQoQu2Pnud419149+NmJ/Sf2u8=}
+ dev: false
+
+ /iconv-lite/0.4.24:
+ resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: true
+
+ /iconv-lite/0.6.3:
+ resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ safer-buffer: 2.1.2
+ dev: false
+
+ /icss-utils/4.1.1:
+ resolution: {integrity: sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ postcss: 7.0.39
+ dev: true
+
+ /ieee754/1.2.1:
+ resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+ dev: true
+
+ /iferr/0.1.5:
+ resolution: {integrity: sha1-xg7taebY/bazEEofy8ocGS3FtQE=}
+ dev: true
+
+ /ignore/4.0.6:
+ resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /ignore/5.2.0:
+ resolution: {integrity: sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==}
+ engines: {node: '>= 4'}
+ dev: true
+
+ /immer/9.0.12:
+ resolution: {integrity: sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA==}
+ dev: false
+
+ /immutable/4.0.0:
+ resolution: {integrity: sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==}
+ dev: true
+
+ /import-fresh/3.3.0:
+ resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
+ engines: {node: '>=6'}
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+ dev: true
+
+ /imurmurhash/0.1.4:
+ resolution: {integrity: sha1-khi5srkoojixPcT7a21XbyMUU+o=}
+ engines: {node: '>=0.8.19'}
+ dev: true
+
+ /indent-string/4.0.0:
+ resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /infer-owner/1.0.4:
+ resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==}
+ dev: true
+
+ /inflight/1.0.6:
+ resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=}
+ dependencies:
+ once: 1.4.0
+ wrappy: 1.0.2
+ dev: true
+
+ /inherits/2.0.1:
+ resolution: {integrity: sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=}
+ dev: true
+
+ /inherits/2.0.3:
+ resolution: {integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=}
+ dev: true
+
+ /inherits/2.0.4:
+ resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
+ dev: true
+
+ /ini/2.0.0:
+ resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /inline-source-map/0.6.2:
+ resolution: {integrity: sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=}
+ dependencies:
+ source-map: 0.5.7
+ dev: true
+
+ /inline-style-parser/0.1.1:
+ resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==}
+ dev: true
+
+ /insert-module-globals/7.2.1:
+ resolution: {integrity: sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==}
+ hasBin: true
+ dependencies:
+ acorn-node: 1.8.2
+ combine-source-map: 0.8.0
+ concat-stream: 1.6.2
+ is-buffer: 1.1.6
+ JSONStream: 1.3.5
+ path-is-absolute: 1.0.1
+ process: 0.11.10
+ through2: 2.0.5
+ undeclared-identifiers: 1.1.3
+ xtend: 4.0.2
+ dev: true
+
+ /internal-slot/1.0.3:
+ resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ get-intrinsic: 1.1.1
+ has: 1.0.3
+ side-channel: 1.0.4
+ dev: true
+
+ /internmap/2.0.3:
+ resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==}
+ engines: {node: '>=12'}
+ dev: false
+
+ /interpret/2.2.0:
+ resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /invariant/2.2.4:
+ resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==}
+ dependencies:
+ loose-envify: 1.4.0
+
+ /ip/1.1.5:
+ resolution: {integrity: sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=}
+ dev: true
+
+ /ipaddr.js/1.9.1:
+ resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /is-absolute-url/3.0.3:
+ resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-absolute/1.0.0:
+ resolution: {integrity: sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-relative: 1.0.0
+ is-windows: 1.0.2
+ dev: true
+
+ /is-accessor-descriptor/0.1.6:
+ resolution: {integrity: sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 3.2.2
+ dev: true
+
+ /is-accessor-descriptor/1.0.0:
+ resolution: {integrity: sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 6.0.3
+ dev: true
+
+ /is-alphabetical/1.0.4:
+ resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==}
+ dev: true
+
+ /is-alphanumerical/1.0.4:
+ resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==}
+ dependencies:
+ is-alphabetical: 1.0.4
+ is-decimal: 1.0.4
+ dev: true
+
+ /is-arguments/1.1.1:
+ resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-arrayish/0.2.1:
+ resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=}
+ dev: true
+
+ /is-bigint/1.0.4:
+ resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
+ dependencies:
+ has-bigints: 1.0.1
+ dev: true
+
+ /is-binary-path/1.0.1:
+ resolution: {integrity: sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ binary-extensions: 1.13.1
+ dev: true
+ optional: true
+
+ /is-binary-path/2.1.0:
+ resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
+ engines: {node: '>=8'}
+ dependencies:
+ binary-extensions: 2.2.0
+ dev: true
+
+ /is-blob/2.1.0:
+ resolution: {integrity: sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==}
+ engines: {node: '>=6'}
+ dev: false
+
+ /is-boolean-object/1.1.2:
+ resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-buffer/1.1.6:
+ resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+ dev: true
+
+ /is-buffer/2.0.5:
+ resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /is-callable/1.2.4:
+ resolution: {integrity: sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-ci/2.0.0:
+ resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==}
+ hasBin: true
+ dependencies:
+ ci-info: 2.0.0
+ dev: true
+
+ /is-ci/3.0.1:
+ resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==}
+ hasBin: true
+ dependencies:
+ ci-info: 3.3.0
+ dev: true
+
+ /is-core-module/2.8.1:
+ resolution: {integrity: sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==}
+ dependencies:
+ has: 1.0.3
+ dev: true
+
+ /is-data-descriptor/0.1.4:
+ resolution: {integrity: sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 3.2.2
+ dev: true
+
+ /is-data-descriptor/1.0.0:
+ resolution: {integrity: sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 6.0.3
+ dev: true
+
+ /is-date-object/1.0.5:
+ resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-decimal/1.0.4:
+ resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==}
+ dev: true
+
+ /is-descriptor/0.1.6:
+ resolution: {integrity: sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-accessor-descriptor: 0.1.6
+ is-data-descriptor: 0.1.4
+ kind-of: 5.1.0
+ dev: true
+
+ /is-descriptor/1.0.2:
+ resolution: {integrity: sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-accessor-descriptor: 1.0.0
+ is-data-descriptor: 1.0.0
+ kind-of: 6.0.3
+ dev: true
+
+ /is-docker/2.2.1:
+ resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==}
+ engines: {node: '>=8'}
+ hasBin: true
+ dev: true
+
+ /is-dom/1.1.0:
+ resolution: {integrity: sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==}
+ dependencies:
+ is-object: 1.0.2
+ is-window: 1.0.2
+ dev: true
+
+ /is-extendable/0.1.1:
+ resolution: {integrity: sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-extendable/1.0.1:
+ resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-plain-object: 2.0.4
+ dev: true
+
+ /is-extglob/2.1.1:
+ resolution: {integrity: sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-fullwidth-code-point/3.0.0:
+ resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-fullwidth-code-point/4.0.0:
+ resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /is-function/1.0.2:
+ resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==}
+ dev: true
+
+ /is-generator-function/1.0.10:
+ resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-glob/3.1.0:
+ resolution: {integrity: sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-glob/4.0.3:
+ resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-extglob: 2.1.1
+ dev: true
+
+ /is-hexadecimal/1.0.4:
+ resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==}
+ dev: true
+
+ /is-in-browser/1.1.3:
+ resolution: {integrity: sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=}
+ dev: false
+
+ /is-installed-globally/0.4.0:
+ resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ global-dirs: 3.0.0
+ is-path-inside: 3.0.3
+ dev: true
+
+ /is-map/2.0.2:
+ resolution: {integrity: sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==}
+ dev: true
+
+ /is-negated-glob/1.0.0:
+ resolution: {integrity: sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-negative-zero/2.0.2:
+ resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /is-number-object/1.0.6:
+ resolution: {integrity: sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-number/3.0.0:
+ resolution: {integrity: sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 3.2.2
+ dev: true
+
+ /is-number/7.0.0:
+ resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
+ engines: {node: '>=0.12.0'}
+ dev: true
+
+ /is-object/1.0.2:
+ resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==}
+ dev: true
+
+ /is-path-inside/3.0.3:
+ resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-obj/2.1.0:
+ resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-plain-object/2.0.4:
+ resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ isobject: 3.0.1
+ dev: true
+
+ /is-plain-object/5.0.0:
+ resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-regex/1.1.4:
+ resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-relative/1.0.0:
+ resolution: {integrity: sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-unc-path: 1.0.0
+ dev: true
+
+ /is-set/2.0.2:
+ resolution: {integrity: sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==}
+ dev: true
+
+ /is-shared-array-buffer/1.0.1:
+ resolution: {integrity: sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==}
+ dev: true
+
+ /is-stream/1.1.0:
+ resolution: {integrity: sha1-EtSj3U5o4Lec6428hBc66A2RykQ=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-stream/2.0.1:
+ resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /is-string/1.0.7:
+ resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-symbol/1.0.4:
+ resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ has-symbols: 1.0.2
+ dev: true
+
+ /is-typed-array/1.1.8:
+ resolution: {integrity: sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.2
+ es-abstract: 1.19.1
+ foreach: 2.0.5
+ has-tostringtag: 1.0.0
+ dev: true
+
+ /is-typedarray/1.0.0:
+ resolution: {integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=}
+ dev: true
+
+ /is-unc-path/1.0.0:
+ resolution: {integrity: sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ unc-path-regex: 0.1.2
+ dev: true
+
+ /is-unicode-supported/0.1.0:
+ resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /is-utf8/0.2.1:
+ resolution: {integrity: sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=}
+ dev: true
+
+ /is-valid-glob/1.0.0:
+ resolution: {integrity: sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-weakref/1.0.2:
+ resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==}
+ dependencies:
+ call-bind: 1.0.2
+ dev: true
+
+ /is-whitespace-character/1.0.4:
+ resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==}
+ dev: true
+
+ /is-window/1.0.2:
+ resolution: {integrity: sha1-LIlspT25feRdPDMTOmXYyfVjSA0=}
+ dev: true
+
+ /is-windows/1.0.2:
+ resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /is-word-character/1.0.4:
+ resolution: {integrity: sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==}
+ dev: true
+
+ /is-wsl/1.1.0:
+ resolution: {integrity: sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /is-wsl/2.2.0:
+ resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==}
+ engines: {node: '>=8'}
+ dependencies:
+ is-docker: 2.2.1
+ dev: true
+
+ /isarray/0.0.1:
+ resolution: {integrity: sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=}
+ dev: false
+
+ /isarray/1.0.0:
+ resolution: {integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=}
+ dev: true
+
+ /isarray/2.0.5:
+ resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==}
+ dev: true
+
+ /isexe/2.0.0:
+ resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=}
+ dev: true
+
+ /isobject/2.1.0:
+ resolution: {integrity: sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ isarray: 1.0.0
+ dev: true
+
+ /isobject/3.0.1:
+ resolution: {integrity: sha1-TkMekrEalzFjaqH5yNHMvP2reN8=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /isobject/4.0.0:
+ resolution: {integrity: sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /isstream/0.1.2:
+ resolution: {integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=}
+ dev: true
+
+ /istanbul-lib-coverage/3.0.0:
+ resolution: {integrity: sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /istanbul-lib-coverage/3.2.0:
+ resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /istanbul-lib-hook/3.0.0:
+ resolution: {integrity: sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ append-transform: 2.0.0
+ dev: true
+
+ /istanbul-lib-instrument/4.0.3:
+ resolution: {integrity: sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /istanbul-lib-instrument/5.1.0:
+ resolution: {integrity: sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/parser': 7.17.0
+ '@istanbuljs/schema': 0.1.3
+ istanbul-lib-coverage: 3.2.0
+ semver: 6.3.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /istanbul-lib-processinfo/2.0.2:
+ resolution: {integrity: sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==}
+ engines: {node: '>=8'}
+ dependencies:
+ archy: 1.0.0
+ cross-spawn: 7.0.3
+ istanbul-lib-coverage: 3.2.0
+ make-dir: 3.1.0
+ p-map: 3.0.0
+ rimraf: 3.0.2
+ uuid: 3.4.0
+ dev: true
+
+ /istanbul-lib-report/3.0.0:
+ resolution: {integrity: sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==}
+ engines: {node: '>=8'}
+ dependencies:
+ istanbul-lib-coverage: 3.2.0
+ make-dir: 3.1.0
+ supports-color: 7.2.0
+ dev: true
+
+ /istanbul-lib-source-maps/4.0.1:
+ resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
+ engines: {node: '>=10'}
+ dependencies:
+ debug: 4.3.3
+ istanbul-lib-coverage: 3.2.0
+ source-map: 0.6.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /istanbul-reports/3.1.4:
+ resolution: {integrity: sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw==}
+ engines: {node: '>=8'}
+ dependencies:
+ html-escaper: 2.0.2
+ istanbul-lib-report: 3.0.0
+ dev: true
+
+ /iterate-iterator/1.0.2:
+ resolution: {integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==}
+ dev: true
+
+ /iterate-value/1.0.2:
+ resolution: {integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==}
+ dependencies:
+ es-get-iterator: 1.1.2
+ iterate-iterator: 1.0.2
+ dev: true
+
+ /jest-haste-map/26.6.2:
+ resolution: {integrity: sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==}
+ engines: {node: '>= 10.14.2'}
+ dependencies:
+ '@jest/types': 26.6.2
+ '@types/graceful-fs': 4.1.5
+ '@types/node': 17.0.16
+ anymatch: 3.1.2
+ fb-watchman: 2.0.1
+ graceful-fs: 4.2.9
+ jest-regex-util: 26.0.0
+ jest-serializer: 26.6.2
+ jest-util: 26.6.2
+ jest-worker: 26.6.2
+ micromatch: 4.0.4
+ sane: 4.1.0
+ walker: 1.0.8
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /jest-regex-util/26.0.0:
+ resolution: {integrity: sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==}
+ engines: {node: '>= 10.14.2'}
+ dev: true
+
+ /jest-serializer/26.6.2:
+ resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==}
+ engines: {node: '>= 10.14.2'}
+ dependencies:
+ '@types/node': 17.0.16
+ graceful-fs: 4.2.9
+ dev: true
+
+ /jest-util/26.6.2:
+ resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==}
+ engines: {node: '>= 10.14.2'}
+ dependencies:
+ '@jest/types': 26.6.2
+ '@types/node': 17.0.16
+ chalk: 4.1.2
+ graceful-fs: 4.2.9
+ is-ci: 2.0.0
+ micromatch: 4.0.4
+ dev: true
+
+ /jest-worker/26.6.2:
+ resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
+ engines: {node: '>= 10.13.0'}
+ dependencies:
+ '@types/node': 17.0.16
+ merge-stream: 2.0.0
+ supports-color: 7.2.0
+ dev: true
+
+ /js-string-escape/1.0.1:
+ resolution: {integrity: sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /js-tokens/4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
+ /js-yaml/3.14.1:
+ resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
+ hasBin: true
+ dependencies:
+ argparse: 1.0.10
+ esprima: 4.0.1
+ dev: true
+
+ /js-yaml/4.1.0:
+ resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
+ hasBin: true
+ dependencies:
+ argparse: 2.0.1
+ dev: true
+
+ /js-year-calendar/1.0.2:
+ resolution: {integrity: sha512-ayHH/vE7xuXgGCprhQ23REbp3Rb2fy1rXO8jA26Wmuw4vYJ/TTIgFxFuNAlNPL8WR4tNXfnG41nlH3p+hjFesg==}
+ dev: false
+
+ /jsbn/0.1.1:
+ resolution: {integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM=}
+ dev: true
+
+ /jsesc/0.5.0:
+ resolution: {integrity: sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=}
+ hasBin: true
+ dev: true
+
+ /jsesc/2.5.2:
+ resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /json-parse-better-errors/1.0.2:
+ resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
+ dev: true
+
+ /json-parse-even-better-errors/2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+ dev: true
+
+ /json-schema-traverse/0.4.1:
+ resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
+ dev: true
+
+ /json-schema/0.4.0:
+ resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==}
+ dev: true
+
+ /json-stable-stringify-without-jsonify/1.0.1:
+ resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=}
+ dev: true
+
+ /json-stable-stringify/0.0.1:
+ resolution: {integrity: sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=}
+ dependencies:
+ jsonify: 0.0.0
+ dev: true
+
+ /json-stringify-safe/5.0.1:
+ resolution: {integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=}
+ dev: true
+
+ /json5/1.0.1:
+ resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.5
+ dev: true
+
+ /json5/2.2.0:
+ resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==}
+ engines: {node: '>=6'}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.5
+ dev: true
+
+ /jsonfile/2.4.0:
+ resolution: {integrity: sha1-NzaitCi4e72gzIO1P6PWM6NcKug=}
+ optionalDependencies:
+ graceful-fs: 4.2.9
+ dev: true
+
+ /jsonfile/4.0.0:
+ resolution: {integrity: sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=}
+ optionalDependencies:
+ graceful-fs: 4.2.9
+ dev: true
+
+ /jsonfile/6.1.0:
+ resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==}
+ dependencies:
+ universalify: 2.0.0
+ optionalDependencies:
+ graceful-fs: 4.2.9
+ dev: true
+
+ /jsonify/0.0.0:
+ resolution: {integrity: sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=}
+ dev: true
+
+ /jsonparse/1.3.1:
+ resolution: {integrity: sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=}
+ engines: {'0': node >= 0.2.0}
+ dev: true
+
+ /jsprim/2.0.2:
+ resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==}
+ engines: {'0': node >=0.6.0}
+ dependencies:
+ assert-plus: 1.0.0
+ extsprintf: 1.3.0
+ json-schema: 0.4.0
+ verror: 1.10.0
+ dev: true
+
+ /jss-plugin-camel-case/10.9.0:
+ resolution: {integrity: sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ hyphenate-style-name: 1.0.4
+ jss: 10.9.0
+ dev: false
+
+ /jss-plugin-default-unit/10.9.0:
+ resolution: {integrity: sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ jss: 10.9.0
+ dev: false
+
+ /jss-plugin-global/10.9.0:
+ resolution: {integrity: sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ jss: 10.9.0
+ dev: false
+
+ /jss-plugin-nested/10.9.0:
+ resolution: {integrity: sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ jss: 10.9.0
+ tiny-warning: 1.0.3
+ dev: false
+
+ /jss-plugin-props-sort/10.9.0:
+ resolution: {integrity: sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ jss: 10.9.0
+ dev: false
+
+ /jss-plugin-rule-value-function/10.9.0:
+ resolution: {integrity: sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ jss: 10.9.0
+ tiny-warning: 1.0.3
+ dev: false
+
+ /jss-plugin-vendor-prefixer/10.9.0:
+ resolution: {integrity: sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ css-vendor: 2.0.8
+ jss: 10.9.0
+ dev: false
+
+ /jss/10.9.0:
+ resolution: {integrity: sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ csstype: 3.0.10
+ is-in-browser: 1.1.3
+ tiny-warning: 1.0.3
+ dev: false
+
+ /jsx-ast-utils/3.2.1:
+ resolution: {integrity: sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==}
+ engines: {node: '>=4.0'}
+ dependencies:
+ array-includes: 3.1.4
+ object.assign: 4.1.2
+ dev: true
+
+ /junk/3.1.0:
+ resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /kind-of/3.2.2:
+ resolution: {integrity: sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-buffer: 1.1.6
+ dev: true
+
+ /kind-of/4.0.0:
+ resolution: {integrity: sha1-IIE989cSkosgc3hpGkUGb65y3Vc=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-buffer: 1.1.6
+ dev: true
+
+ /kind-of/5.1.0:
+ resolution: {integrity: sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /kind-of/6.0.3:
+ resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /klaw/1.3.1:
+ resolution: {integrity: sha1-QIhDO0azsbolnXh4XY6W9zugJDk=}
+ optionalDependencies:
+ graceful-fs: 4.2.9
+ dev: true
+
+ /kleur/3.0.3:
+ resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /klona/2.0.5:
+ resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /labeled-stream-splicer/2.0.2:
+ resolution: {integrity: sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==}
+ dependencies:
+ inherits: 2.0.4
+ stream-splicer: 2.0.1
+ dev: true
+
+ /lazy-ass/1.6.0:
+ resolution: {integrity: sha1-eZllXoZGwX8In90YfRUNMyTVRRM=}
+ engines: {node: '> 0.8'}
+ dev: true
+
+ /lazy-universal-dotenv/3.0.1:
+ resolution: {integrity: sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==}
+ engines: {node: '>=6.0.0', npm: '>=6.0.0', yarn: '>=1.0.0'}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ app-root-dir: 1.0.2
+ core-js: 3.21.0
+ dotenv: 8.6.0
+ dotenv-expand: 5.1.0
+ dev: true
+
+ /lazystream/1.0.1:
+ resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
+ engines: {node: '>= 0.6.3'}
+ dependencies:
+ readable-stream: 2.3.7
+ dev: true
+
+ /lead/1.0.0:
+ resolution: {integrity: sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ flush-write-stream: 1.1.1
+ dev: true
+
+ /levn/0.3.0:
+ resolution: {integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.1.2
+ type-check: 0.3.2
+ dev: true
+
+ /levn/0.4.1:
+ resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ dev: true
+
+ /lilconfig/2.0.4:
+ resolution: {integrity: sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /lines-and-columns/1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ dev: true
+
+ /lint-staged/12.3.3:
+ resolution: {integrity: sha512-OqcLsqcPOqzvsfkxjeBpZylgJ3SRG1RYqc9LxC6tkt6tNsq1bNVkAixBwX09f6CobcHswzqVOCBpFR1Fck0+ag==}
+ engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
+ hasBin: true
+ dependencies:
+ cli-truncate: 3.1.0
+ colorette: 2.0.16
+ commander: 8.3.0
+ debug: 4.3.3_supports-color@9.2.1
+ execa: 5.1.1
+ lilconfig: 2.0.4
+ listr2: 4.0.2
+ micromatch: 4.0.4
+ normalize-path: 3.0.0
+ object-inspect: 1.12.0
+ string-argv: 0.3.1
+ supports-color: 9.2.1
+ yaml: 1.10.2
+ transitivePeerDependencies:
+ - enquirer
+ dev: true
+
+ /listr2/3.14.0_enquirer@2.3.6:
+ resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ enquirer: '>= 2.3.0 < 3'
+ peerDependenciesMeta:
+ enquirer:
+ optional: true
+ dependencies:
+ cli-truncate: 2.1.0
+ colorette: 2.0.16
+ enquirer: 2.3.6
+ log-update: 4.0.0
+ p-map: 4.0.0
+ rfdc: 1.3.0
+ rxjs: 7.5.2
+ through: 2.3.8
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /listr2/4.0.2:
+ resolution: {integrity: sha512-YcgwfCWpvPbj9FLUGqvdFvd3hrFWKpOeuXznRgfWEJ7RNr8b/IKKIKZABHx3aU+4CWN/iSAFFSReziQG6vTeIA==}
+ engines: {node: '>=12'}
+ peerDependencies:
+ enquirer: '>= 2.3.0 < 3'
+ peerDependenciesMeta:
+ enquirer:
+ optional: true
+ dependencies:
+ cli-truncate: 2.1.0
+ colorette: 2.0.16
+ log-update: 4.0.0
+ p-map: 4.0.0
+ rfdc: 1.3.0
+ rxjs: 7.5.2
+ through: 2.3.8
+ wrap-ansi: 7.0.0
+ dev: true
+
+ /loader-runner/2.4.0:
+ resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==}
+ engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}
+ dev: true
+
+ /loader-utils/1.4.0:
+ resolution: {integrity: sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ big.js: 5.2.2
+ emojis-list: 3.0.0
+ json5: 1.0.1
+ dev: true
+
+ /loader-utils/2.0.0:
+ resolution: {integrity: sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==}
+ engines: {node: '>=8.9.0'}
+ dependencies:
+ big.js: 5.2.2
+ emojis-list: 3.0.0
+ json5: 2.2.0
+ dev: true
+
+ /loader-utils/2.0.2:
+ resolution: {integrity: sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==}
+ engines: {node: '>=8.9.0'}
+ dependencies:
+ big.js: 5.2.2
+ emojis-list: 3.0.0
+ json5: 2.2.0
+ dev: true
+
+ /locate-path/3.0.0:
+ resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-locate: 3.0.0
+ path-exists: 3.0.0
+ dev: true
+
+ /locate-path/5.0.0:
+ resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-locate: 4.1.0
+ dev: true
+
+ /locate-path/6.0.0:
+ resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-locate: 5.0.0
+ dev: true
+
+ /lodash.clonedeep/4.5.0:
+ resolution: {integrity: sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=}
+ dev: true
+
+ /lodash.debounce/4.0.8:
+ resolution: {integrity: sha1-gteb/zCmfEAF/9XiUVMArZyk168=}
+ dev: true
+
+ /lodash.flattendeep/4.4.0:
+ resolution: {integrity: sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=}
+ dev: true
+
+ /lodash.get/4.4.2:
+ resolution: {integrity: sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=}
+ dev: false
+
+ /lodash.memoize/3.0.4:
+ resolution: {integrity: sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=}
+ dev: true
+
+ /lodash.merge/4.6.2:
+ resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
+ dev: true
+
+ /lodash.once/4.1.1:
+ resolution: {integrity: sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=}
+ dev: true
+
+ /lodash.topath/4.5.2:
+ resolution: {integrity: sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=}
+ dev: false
+
+ /lodash.uniq/4.5.0:
+ resolution: {integrity: sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=}
+ dev: true
+
+ /lodash/4.17.21:
+ resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
+ dev: true
+
+ /log-symbols/4.1.0:
+ resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==}
+ engines: {node: '>=10'}
+ dependencies:
+ chalk: 4.1.2
+ is-unicode-supported: 0.1.0
+ dev: true
+
+ /log-update/4.0.0:
+ resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-escapes: 4.3.2
+ cli-cursor: 3.1.0
+ slice-ansi: 4.0.0
+ wrap-ansi: 6.2.0
+ dev: true
+
+ /loose-envify/1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+ dependencies:
+ js-tokens: 4.0.0
+
+ /lower-case/2.0.2:
+ resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==}
+ dependencies:
+ tslib: 2.3.1
+ dev: true
+
+ /lowlight/1.20.0:
+ resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==}
+ dependencies:
+ fault: 1.0.4
+ highlight.js: 10.7.3
+ dev: true
+
+ /lru-cache/5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+ dependencies:
+ yallist: 3.1.1
+ dev: true
+
+ /lru-cache/6.0.0:
+ resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
+ engines: {node: '>=10'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /make-dir/2.1.0:
+ resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==}
+ engines: {node: '>=6'}
+ dependencies:
+ pify: 4.0.1
+ semver: 5.7.1
+ dev: true
+
+ /make-dir/3.1.0:
+ resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
+ engines: {node: '>=8'}
+ dependencies:
+ semver: 6.3.0
+ dev: true
+
+ /makeerror/1.0.12:
+ resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
+ dependencies:
+ tmpl: 1.0.5
+ dev: true
+
+ /map-cache/0.2.2:
+ resolution: {integrity: sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /map-or-similar/1.5.0:
+ resolution: {integrity: sha1-beJlMXSt+12e3DPGnT6Sobdvrwg=}
+ dev: true
+
+ /map-visit/1.0.0:
+ resolution: {integrity: sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ object-visit: 1.0.1
+ dev: true
+
+ /markdown-escapes/1.0.4:
+ resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==}
+ dev: true
+
+ /markdown-to-jsx/7.1.6_react@17.0.2:
+ resolution: {integrity: sha512-1wrIGZYwIG2gR3yfRmbr4FlQmhaAKoKTpRo4wur4fp9p0njU1Hi7vR8fj0AUKKIcPduiJmPprzmCB5B/GvlC7g==}
+ engines: {node: '>= 10'}
+ peerDependencies:
+ react: '>= 0.14.0 || 17'
+ dependencies:
+ react: 17.0.2
+ dev: true
+
+ /matcher-collection/2.0.1:
+ resolution: {integrity: sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ dependencies:
+ '@types/minimatch': 3.0.5
+ minimatch: 3.0.5
+ dev: true
+
+ /md5.js/1.3.5:
+ resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==}
+ dependencies:
+ hash-base: 3.1.0
+ inherits: 2.0.4
+ safe-buffer: 5.2.1
+ dev: true
+
+ /mdast-squeeze-paragraphs/4.0.0:
+ resolution: {integrity: sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==}
+ dependencies:
+ unist-util-remove: 2.1.0
+ dev: true
+
+ /mdast-util-definitions/4.0.0:
+ resolution: {integrity: sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==}
+ dependencies:
+ unist-util-visit: 2.0.3
+ dev: true
+
+ /mdast-util-to-hast/10.0.1:
+ resolution: {integrity: sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==}
+ dependencies:
+ '@types/mdast': 3.0.10
+ '@types/unist': 2.0.6
+ mdast-util-definitions: 4.0.0
+ mdurl: 1.0.1
+ unist-builder: 2.0.3
+ unist-util-generated: 1.1.6
+ unist-util-position: 3.1.0
+ unist-util-visit: 2.0.3
+ dev: true
+
+ /mdast-util-to-string/1.1.0:
+ resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==}
+ dev: true
+
+ /mdurl/1.0.1:
+ resolution: {integrity: sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=}
+ dev: true
+
+ /media-typer/0.3.0:
+ resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /memfs/3.4.1:
+ resolution: {integrity: sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==}
+ engines: {node: '>= 4.0.0'}
+ dependencies:
+ fs-monkey: 1.0.3
+ dev: true
+
+ /memoize-one/5.2.1:
+ resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
+ dev: false
+
+ /memoizerific/1.11.3:
+ resolution: {integrity: sha1-fIekZGREwy11Q4VwkF8tvRsagFo=}
+ dependencies:
+ map-or-similar: 1.5.0
+ dev: true
+
+ /memory-fs/0.4.1:
+ resolution: {integrity: sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=}
+ dependencies:
+ errno: 0.1.8
+ readable-stream: 2.3.7
+ dev: true
+
+ /memory-fs/0.5.0:
+ resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==}
+ engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}
+ dependencies:
+ errno: 0.1.8
+ readable-stream: 2.3.7
+ dev: true
+
+ /merge-descriptors/1.0.1:
+ resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=}
+ dev: true
+
+ /merge-stream/2.0.0:
+ resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
+ dev: true
+
+ /merge2/1.4.1:
+ resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /methods/1.1.2:
+ resolution: {integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /microevent.ts/0.1.1:
+ resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==}
+ dev: true
+
+ /micromatch/3.1.10:
+ resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ arr-diff: 4.0.0
+ array-unique: 0.3.2
+ braces: 2.3.2
+ define-property: 2.0.2
+ extend-shallow: 3.0.2
+ extglob: 2.0.4
+ fragment-cache: 0.2.1
+ kind-of: 6.0.3
+ nanomatch: 1.2.13
+ object.pick: 1.3.0
+ regex-not: 1.0.2
+ snapdragon: 0.8.2
+ to-regex: 3.0.2
+ dev: true
+
+ /micromatch/4.0.4:
+ resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==}
+ engines: {node: '>=8.6'}
+ dependencies:
+ braces: 3.0.2
+ picomatch: 2.3.1
+ dev: true
+
+ /miller-rabin/4.0.1:
+ resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==}
+ hasBin: true
+ dependencies:
+ bn.js: 4.12.0
+ brorand: 1.1.0
+ dev: true
+
+ /mime-db/1.51.0:
+ resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /mime-types/2.1.34:
+ resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ mime-db: 1.51.0
+ dev: true
+
+ /mime/1.6.0:
+ resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==}
+ engines: {node: '>=4'}
+ hasBin: true
+ dev: true
+
+ /mime/2.6.0:
+ resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==}
+ engines: {node: '>=4.0.0'}
+ hasBin: true
+ dev: true
+
+ /mimic-fn/2.1.0:
+ resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /min-document/2.19.0:
+ resolution: {integrity: sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=}
+ dependencies:
+ dom-walk: 0.1.2
+ dev: true
+
+ /min-indent/1.0.1:
+ resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /minimalistic-assert/1.0.1:
+ resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
+ dev: true
+
+ /minimalistic-crypto-utils/1.0.1:
+ resolution: {integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=}
+ dev: true
+
+ /minimatch/3.0.5:
+ resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==}
+ dependencies:
+ brace-expansion: 1.1.11
+ dev: true
+
+ /minimist/1.2.5:
+ resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==}
+ dev: true
+
+ /minipass-collect/1.0.2:
+ resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==}
+ engines: {node: '>= 8'}
+ dependencies:
+ minipass: 3.1.6
+ dev: true
+
+ /minipass-flush/1.0.5:
+ resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==}
+ engines: {node: '>= 8'}
+ dependencies:
+ minipass: 3.1.6
+ dev: true
+
+ /minipass-pipeline/1.2.4:
+ resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==}
+ engines: {node: '>=8'}
+ dependencies:
+ minipass: 3.1.6
+ dev: true
+
+ /minipass/3.1.6:
+ resolution: {integrity: sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ yallist: 4.0.0
+ dev: true
+
+ /minizlib/2.1.2:
+ resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
+ engines: {node: '>= 8'}
+ dependencies:
+ minipass: 3.1.6
+ yallist: 4.0.0
+ dev: true
+
+ /mississippi/3.0.0:
+ resolution: {integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==}
+ engines: {node: '>=4.0.0'}
+ dependencies:
+ concat-stream: 1.6.2
+ duplexify: 3.7.1
+ end-of-stream: 1.4.4
+ flush-write-stream: 1.1.1
+ from2: 2.3.0
+ parallel-transform: 1.2.0
+ pump: 3.0.0
+ pumpify: 1.5.1
+ stream-each: 1.2.3
+ through2: 2.0.5
+ dev: true
+
+ /mixin-deep/1.3.2:
+ resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ for-in: 1.0.2
+ is-extendable: 1.0.1
+ dev: true
+
+ /mkdirp-classic/0.5.3:
+ resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
+ dev: true
+
+ /mkdirp/0.5.5:
+ resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==}
+ hasBin: true
+ dependencies:
+ minimist: 1.2.5
+ dev: true
+
+ /mkdirp/1.0.4:
+ resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dev: true
+
+ /mktemp/0.4.0:
+ resolution: {integrity: sha1-bQUVYRyKjITkhKogABKbmOmB/ws=}
+ engines: {node: '>0.9'}
+ dev: true
+
+ /module-deps/6.2.3:
+ resolution: {integrity: sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==}
+ engines: {node: '>= 0.8.0'}
+ hasBin: true
+ dependencies:
+ browser-resolve: 2.0.0
+ cached-path-relative: 1.1.0
+ concat-stream: 1.6.2
+ defined: 1.0.0
+ detective: 5.2.0
+ duplexer2: 0.1.4
+ inherits: 2.0.4
+ JSONStream: 1.3.5
+ parents: 1.0.1
+ readable-stream: 2.3.7
+ resolve: 1.22.0
+ stream-combiner2: 1.1.1
+ subarg: 1.0.0
+ through2: 2.0.5
+ xtend: 4.0.2
+ dev: true
+
+ /moment-range/4.0.2_moment@2.29.1:
+ resolution: {integrity: sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==}
+ peerDependencies:
+ moment: '>= 2'
+ dependencies:
+ es6-symbol: 3.1.3
+ moment: 2.29.1
+ dev: false
+
+ /moment/2.29.1:
+ resolution: {integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==}
+ dev: false
+
+ /move-concurrently/1.0.1:
+ resolution: {integrity: sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=}
+ dependencies:
+ aproba: 1.2.0
+ copy-concurrently: 1.0.5
+ fs-write-stream-atomic: 1.0.10
+ mkdirp: 0.5.5
+ rimraf: 2.7.1
+ run-queue: 1.0.3
+ dev: true
+
+ /ms/2.0.0:
+ resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
+ dev: true
+
+ /ms/2.1.1:
+ resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==}
+ dev: true
+
+ /ms/2.1.2:
+ resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
+ dev: true
+
+ /ms/2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+ dev: true
+
+ /nan/2.15.0:
+ resolution: {integrity: sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==}
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /nanoid/3.2.0:
+ resolution: {integrity: sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==}
+ engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
+ hasBin: true
+ dev: true
+
+ /nanomatch/1.2.13:
+ resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ arr-diff: 4.0.0
+ array-unique: 0.3.2
+ define-property: 2.0.2
+ extend-shallow: 3.0.2
+ fragment-cache: 0.2.1
+ is-windows: 1.0.2
+ kind-of: 6.0.3
+ object.pick: 1.3.0
+ regex-not: 1.0.2
+ snapdragon: 0.8.2
+ to-regex: 3.0.2
+ dev: true
+
+ /natural-compare/1.4.0:
+ resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=}
+ dev: true
+
+ /negotiator/0.6.3:
+ resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /neo-async/2.6.2:
+ resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
+ dev: true
+
+ /nested-error-stacks/2.1.0:
+ resolution: {integrity: sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug==}
+ dev: true
+
+ /next-tick/1.0.0:
+ resolution: {integrity: sha1-yobR/ogoFpsBICCOPchCS524NCw=}
+ dev: false
+
+ /nice-try/1.0.5:
+ resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
+ dev: true
+
+ /no-case/3.0.4:
+ resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==}
+ dependencies:
+ lower-case: 2.0.2
+ tslib: 2.3.1
+ dev: true
+
+ /node-dir/0.1.17:
+ resolution: {integrity: sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=}
+ engines: {node: '>= 0.10.5'}
+ dependencies:
+ minimatch: 3.0.5
+ dev: true
+
+ /node-fetch/2.6.7:
+ resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==}
+ engines: {node: 4.x || >=6.0.0}
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ dependencies:
+ whatwg-url: 5.0.0
+ dev: true
+
+ /node-int64/0.4.0:
+ resolution: {integrity: sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=}
+ dev: true
+
+ /node-libs-browser/2.2.1:
+ resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==}
+ dependencies:
+ assert: 1.5.0
+ browserify-zlib: 0.2.0
+ buffer: 4.9.2
+ console-browserify: 1.2.0
+ constants-browserify: 1.0.0
+ crypto-browserify: 3.12.0
+ domain-browser: 1.2.0
+ events: 3.3.0
+ https-browserify: 1.0.0
+ os-browserify: 0.3.0
+ path-browserify: 0.0.1
+ process: 0.11.10
+ punycode: 1.4.1
+ querystring-es3: 0.2.1
+ readable-stream: 2.3.7
+ stream-browserify: 2.0.2
+ stream-http: 2.8.3
+ string_decoder: 1.3.0
+ timers-browserify: 2.0.12
+ tty-browserify: 0.0.0
+ url: 0.11.0
+ util: 0.11.1
+ vm-browserify: 1.1.2
+ dev: true
+
+ /node-preload/0.2.1:
+ resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ process-on-spawn: 1.0.0
+ dev: true
+
+ /node-releases/2.0.1:
+ resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==}
+ dev: true
+
+ /normalize-package-data/2.5.0:
+ resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
+ dependencies:
+ hosted-git-info: 2.8.9
+ resolve: 1.22.0
+ semver: 5.7.1
+ validate-npm-package-license: 3.0.4
+ dev: true
+
+ /normalize-path/2.1.1:
+ resolution: {integrity: sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ remove-trailing-separator: 1.1.0
+ dev: true
+
+ /normalize-path/3.0.0:
+ resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /normalize-range/0.1.2:
+ resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /notistack/1.0.10_7twteiegzuck7mfw73wj5btjea:
+ resolution: {integrity: sha512-z0y4jJaVtOoH3kc3GtNUlhNTY+5LE04QDeLVujX3VPhhzg67zw055mZjrBF+nzpv3V9aiPNph1EgRU4+t8kQTQ==}
+ peerDependencies:
+ '@material-ui/core': ^4.0.0
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@material-ui/core': 4.12.3_xd63vgjm47lzoal5ybyqmsdesy
+ clsx: 1.1.1
+ hoist-non-react-statics: 3.3.2
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /now-and-later/2.0.1:
+ resolution: {integrity: sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ once: 1.4.0
+ dev: true
+
+ /npm-run-path/2.0.2:
+ resolution: {integrity: sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=}
+ engines: {node: '>=4'}
+ dependencies:
+ path-key: 2.0.1
+ dev: true
+
+ /npm-run-path/4.0.1:
+ resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
+ engines: {node: '>=8'}
+ dependencies:
+ path-key: 3.1.1
+ dev: true
+
+ /npmlog/5.0.1:
+ resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
+ dependencies:
+ are-we-there-yet: 2.0.0
+ console-control-strings: 1.1.0
+ gauge: 3.0.2
+ set-blocking: 2.0.0
+ dev: true
+
+ /nth-check/2.0.1:
+ resolution: {integrity: sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==}
+ dependencies:
+ boolbase: 1.0.0
+ dev: true
+
+ /num2fraction/1.2.2:
+ resolution: {integrity: sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=}
+ dev: true
+
+ /nyc/15.1.0:
+ resolution: {integrity: sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==}
+ engines: {node: '>=8.9'}
+ hasBin: true
+ dependencies:
+ '@istanbuljs/load-nyc-config': 1.1.0
+ '@istanbuljs/schema': 0.1.3
+ caching-transform: 4.0.0
+ convert-source-map: 1.8.0
+ decamelize: 1.2.0
+ find-cache-dir: 3.3.2
+ find-up: 4.1.0
+ foreground-child: 2.0.0
+ get-package-type: 0.1.0
+ glob: 7.2.0
+ istanbul-lib-coverage: 3.2.0
+ istanbul-lib-hook: 3.0.0
+ istanbul-lib-instrument: 4.0.3
+ istanbul-lib-processinfo: 2.0.2
+ istanbul-lib-report: 3.0.0
+ istanbul-lib-source-maps: 4.0.1
+ istanbul-reports: 3.1.4
+ make-dir: 3.1.0
+ node-preload: 0.2.1
+ p-map: 3.0.0
+ process-on-spawn: 1.0.0
+ resolve-from: 5.0.0
+ rimraf: 3.0.2
+ signal-exit: 3.0.7
+ spawn-wrap: 2.0.0
+ test-exclude: 6.0.0
+ yargs: 15.4.1
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /object-assign/4.1.1:
+ resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
+ engines: {node: '>=0.10.0'}
+
+ /object-copy/0.1.0:
+ resolution: {integrity: sha1-fn2Fi3gb18mRpBupde04EnVOmYw=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ copy-descriptor: 0.1.1
+ define-property: 0.2.5
+ kind-of: 3.2.2
+ dev: true
+
+ /object-inspect/1.12.0:
+ resolution: {integrity: sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==}
+ dev: true
+
+ /object-keys/1.1.1:
+ resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /object-visit/1.0.1:
+ resolution: {integrity: sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ isobject: 3.0.1
+ dev: true
+
+ /object.assign/4.1.2:
+ resolution: {integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ has-symbols: 1.0.2
+ object-keys: 1.1.1
+ dev: true
+
+ /object.entries/1.1.5:
+ resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /object.fromentries/2.0.5:
+ resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /object.getownpropertydescriptors/2.1.3:
+ resolution: {integrity: sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /object.hasown/1.1.0:
+ resolution: {integrity: sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==}
+ dependencies:
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /object.pick/1.3.0:
+ resolution: {integrity: sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ isobject: 3.0.1
+ dev: true
+
+ /object.values/1.1.5:
+ resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /objectorarray/1.0.5:
+ resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==}
+ dev: true
+
+ /on-finished/2.3.0:
+ resolution: {integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ ee-first: 1.1.1
+ dev: true
+
+ /on-headers/1.0.2:
+ resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /once/1.4.0:
+ resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
+ dependencies:
+ wrappy: 1.0.2
+ dev: true
+
+ /onetime/5.1.2:
+ resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
+ engines: {node: '>=6'}
+ dependencies:
+ mimic-fn: 2.1.0
+ dev: true
+
+ /open/7.4.2:
+ resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==}
+ engines: {node: '>=8'}
+ dependencies:
+ is-docker: 2.2.1
+ is-wsl: 2.2.0
+ dev: true
+
+ /optionator/0.8.3:
+ resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.3.0
+ prelude-ls: 1.1.2
+ type-check: 0.3.2
+ word-wrap: 1.2.3
+ dev: true
+
+ /optionator/0.9.1:
+ resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ deep-is: 0.1.4
+ fast-levenshtein: 2.0.6
+ levn: 0.4.1
+ prelude-ls: 1.2.1
+ type-check: 0.4.0
+ word-wrap: 1.2.3
+ dev: true
+
+ /ordered-read-streams/1.0.1:
+ resolution: {integrity: sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=}
+ dependencies:
+ readable-stream: 2.3.7
+ dev: true
+
+ /os-browserify/0.3.0:
+ resolution: {integrity: sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=}
+ dev: true
+
+ /ospath/1.2.2:
+ resolution: {integrity: sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=}
+ dev: true
+
+ /outpipe/1.1.1:
+ resolution: {integrity: sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=}
+ dependencies:
+ shell-quote: 1.7.3
+ dev: true
+
+ /overlayscrollbars/1.13.1:
+ resolution: {integrity: sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==}
+ dev: true
+
+ /p-all/2.1.0:
+ resolution: {integrity: sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-map: 2.1.0
+ dev: true
+
+ /p-event/4.2.0:
+ resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-timeout: 3.2.0
+ dev: true
+
+ /p-filter/2.1.0:
+ resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-map: 2.1.0
+ dev: true
+
+ /p-finally/1.0.0:
+ resolution: {integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /p-limit/2.3.0:
+ resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-try: 2.2.0
+ dev: true
+
+ /p-limit/3.1.0:
+ resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ yocto-queue: 0.1.0
+ dev: true
+
+ /p-locate/3.0.0:
+ resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ p-limit: 2.3.0
+ dev: true
+
+ /p-locate/4.1.0:
+ resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-limit: 2.3.0
+ dev: true
+
+ /p-locate/5.0.0:
+ resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==}
+ engines: {node: '>=10'}
+ dependencies:
+ p-limit: 3.1.0
+ dev: true
+
+ /p-map/2.1.0:
+ resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /p-map/3.0.0:
+ resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ aggregate-error: 3.1.0
+ dev: true
+
+ /p-map/4.0.0:
+ resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ aggregate-error: 3.1.0
+ dev: true
+
+ /p-timeout/3.2.0:
+ resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
+ engines: {node: '>=8'}
+ dependencies:
+ p-finally: 1.0.0
+ dev: true
+
+ /p-try/2.2.0:
+ resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /package-hash/4.0.0:
+ resolution: {integrity: sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ graceful-fs: 4.2.9
+ hasha: 5.2.2
+ lodash.flattendeep: 4.4.0
+ release-zalgo: 1.0.0
+ dev: true
+
+ /pako/1.0.11:
+ resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==}
+ dev: true
+
+ /parallel-transform/1.2.0:
+ resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==}
+ dependencies:
+ cyclist: 1.0.1
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /param-case/3.0.4:
+ resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==}
+ dependencies:
+ dot-case: 3.0.4
+ tslib: 2.3.1
+ dev: true
+
+ /parent-module/1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+ dependencies:
+ callsites: 3.1.0
+ dev: true
+
+ /parents/1.0.1:
+ resolution: {integrity: sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=}
+ dependencies:
+ path-platform: 0.11.15
+ dev: true
+
+ /parse-asn1/5.1.6:
+ resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==}
+ dependencies:
+ asn1.js: 5.4.1
+ browserify-aes: 1.2.0
+ evp_bytestokey: 1.0.3
+ pbkdf2: 3.1.2
+ safe-buffer: 5.2.1
+ dev: true
+
+ /parse-entities/2.0.0:
+ resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==}
+ dependencies:
+ character-entities: 1.2.4
+ character-entities-legacy: 1.1.4
+ character-reference-invalid: 1.1.4
+ is-alphanumerical: 1.0.4
+ is-decimal: 1.0.4
+ is-hexadecimal: 1.0.4
+ dev: true
+
+ /parse-json/5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@babel/code-frame': 7.16.7
+ error-ex: 1.3.2
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+ dev: true
+
+ /parse5-htmlparser2-tree-adapter/6.0.1:
+ resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==}
+ dependencies:
+ parse5: 6.0.1
+ dev: true
+
+ /parse5/6.0.1:
+ resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
+ dev: true
+
+ /parseurl/1.3.3:
+ resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /pascal-case/3.1.2:
+ resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==}
+ dependencies:
+ no-case: 3.0.4
+ tslib: 2.3.1
+ dev: true
+
+ /pascalcase/0.1.1:
+ resolution: {integrity: sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-browserify/0.0.1:
+ resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==}
+ dev: true
+
+ /path-browserify/1.0.1:
+ resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==}
+ dev: true
+
+ /path-dirname/1.0.2:
+ resolution: {integrity: sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=}
+ dev: true
+
+ /path-exists/3.0.0:
+ resolution: {integrity: sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /path-exists/4.0.0:
+ resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-is-absolute/1.0.1:
+ resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /path-key/2.0.1:
+ resolution: {integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /path-key/3.1.1:
+ resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /path-parse/1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+ dev: true
+
+ /path-platform/0.11.15:
+ resolution: {integrity: sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /path-posix/1.0.0:
+ resolution: {integrity: sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8=}
+ dev: true
+
+ /path-to-regexp/0.1.7:
+ resolution: {integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=}
+ dev: true
+
+ /path-to-regexp/1.8.0:
+ resolution: {integrity: sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==}
+ dependencies:
+ isarray: 0.0.1
+ dev: false
+
+ /path-type/3.0.0:
+ resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
+ engines: {node: '>=4'}
+ dependencies:
+ pify: 3.0.0
+ dev: true
+
+ /path-type/4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /pbkdf2/3.1.2:
+ resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==}
+ engines: {node: '>=0.12'}
+ dependencies:
+ create-hash: 1.2.0
+ create-hmac: 1.1.7
+ ripemd160: 2.0.2
+ safe-buffer: 5.2.1
+ sha.js: 2.4.11
+ dev: true
+
+ /pend/1.2.0:
+ resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=}
+ dev: true
+
+ /performance-now/2.1.0:
+ resolution: {integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=}
+ dev: true
+
+ /picocolors/0.2.1:
+ resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==}
+ dev: true
+
+ /picocolors/1.0.0:
+ resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
+ dev: true
+
+ /picomatch/2.3.1:
+ resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
+ engines: {node: '>=8.6'}
+ dev: true
+
+ /pify/2.3.0:
+ resolution: {integrity: sha1-7RQaasBDqEnqWISY59yosVMw6Qw=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /pify/3.0.0:
+ resolution: {integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /pify/4.0.1:
+ resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /pirates/4.0.5:
+ resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /pkg-dir/3.0.0:
+ resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==}
+ engines: {node: '>=6'}
+ dependencies:
+ find-up: 3.0.0
+ dev: true
+
+ /pkg-dir/4.2.0:
+ resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ find-up: 4.1.0
+ dev: true
+
+ /pkg-dir/5.0.0:
+ resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==}
+ engines: {node: '>=10'}
+ dependencies:
+ find-up: 5.0.0
+ dev: true
+
+ /pnp-webpack-plugin/1.6.4_typescript@4.5.5:
+ resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==}
+ engines: {node: '>=6'}
+ dependencies:
+ ts-pnp: 1.2.0_typescript@4.5.5
+ transitivePeerDependencies:
+ - typescript
+ dev: true
+
+ /polished/4.1.4:
+ resolution: {integrity: sha512-Nq5Mbza+Auo7N3sQb1QMFaQiDO+4UexWuSGR7Cjb4Sw11SZIJcrrFtiZ+L0jT9MBsUsxDboHVASbCLbE1rnECg==}
+ engines: {node: '>=10'}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: true
+
+ /popmotion/11.0.3:
+ resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==}
+ dependencies:
+ framesync: 6.0.1
+ hey-listen: 1.0.8
+ style-value-types: 5.0.0
+ tslib: 2.3.1
+ dev: false
+
+ /popper.js/1.16.1-lts:
+ resolution: {integrity: sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==}
+ dev: false
+
+ /posix-character-classes/0.1.1:
+ resolution: {integrity: sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /postcss-flexbugs-fixes/4.2.1:
+ resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==}
+ dependencies:
+ postcss: 7.0.39
+ dev: true
+
+ /postcss-loader/4.3.0_gzaxsinx64nntyd3vmdqwl7coe:
+ resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ postcss: ^7.0.0 || ^8.0.1
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ cosmiconfig: 7.0.1
+ klona: 2.0.5
+ loader-utils: 2.0.2
+ postcss: 7.0.39
+ schema-utils: 3.1.1
+ semver: 7.3.5
+ webpack: 4.46.0
+ dev: true
+
+ /postcss-modules-extract-imports/2.0.0:
+ resolution: {integrity: sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==}
+ engines: {node: '>= 6'}
+ dependencies:
+ postcss: 7.0.39
+ dev: true
+
+ /postcss-modules-local-by-default/3.0.3:
+ resolution: {integrity: sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==}
+ engines: {node: '>= 6'}
+ dependencies:
+ icss-utils: 4.1.1
+ postcss: 7.0.39
+ postcss-selector-parser: 6.0.9
+ postcss-value-parser: 4.2.0
+ dev: true
+
+ /postcss-modules-scope/2.2.0:
+ resolution: {integrity: sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==}
+ engines: {node: '>= 6'}
+ dependencies:
+ postcss: 7.0.39
+ postcss-selector-parser: 6.0.9
+ dev: true
+
+ /postcss-modules-values/3.0.0:
+ resolution: {integrity: sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==}
+ dependencies:
+ icss-utils: 4.1.1
+ postcss: 7.0.39
+ dev: true
+
+ /postcss-selector-parser/6.0.9:
+ resolution: {integrity: sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==}
+ engines: {node: '>=4'}
+ dependencies:
+ cssesc: 3.0.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /postcss-value-parser/4.2.0:
+ resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
+ dev: true
+
+ /postcss/7.0.39:
+ resolution: {integrity: sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ picocolors: 0.2.1
+ source-map: 0.6.1
+ dev: true
+
+ /postcss/8.4.6:
+ resolution: {integrity: sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==}
+ engines: {node: ^10 || ^12 || >=14}
+ dependencies:
+ nanoid: 3.2.0
+ picocolors: 1.0.0
+ source-map-js: 1.0.2
+ dev: true
+
+ /prelude-ls/1.1.2:
+ resolution: {integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prelude-ls/1.2.1:
+ resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
+ engines: {node: '>= 0.8.0'}
+ dev: true
+
+ /prettier-linter-helpers/1.0.0:
+ resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
+ engines: {node: '>=6.0.0'}
+ dependencies:
+ fast-diff: 1.2.0
+ dev: true
+
+ /prettier/2.3.0:
+ resolution: {integrity: sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==}
+ engines: {node: '>=10.13.0'}
+ hasBin: true
+ dev: true
+
+ /pretty-bytes/5.6.0:
+ resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /pretty-error/2.1.2:
+ resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==}
+ dependencies:
+ lodash: 4.17.21
+ renderkid: 2.0.7
+ dev: true
+
+ /pretty-hrtime/1.0.3:
+ resolution: {integrity: sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /prismjs/1.25.0:
+ resolution: {integrity: sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==}
+ dev: true
+
+ /prismjs/1.26.0:
+ resolution: {integrity: sha512-HUoH9C5Z3jKkl3UunCyiD5jwk0+Hz0fIgQ2nbwU2Oo/ceuTAQAg+pPVnfdt2TJWRVLcxKh9iuoYDUSc8clb5UQ==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /process-nextick-args/2.0.1:
+ resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
+ dev: true
+
+ /process-on-spawn/1.0.0:
+ resolution: {integrity: sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==}
+ engines: {node: '>=8'}
+ dependencies:
+ fromentries: 1.3.2
+ dev: true
+
+ /process/0.11.10:
+ resolution: {integrity: sha1-czIwDoQBYb2j5podHZGn1LwW8YI=}
+ engines: {node: '>= 0.6.0'}
+ dev: true
+
+ /promise-inflight/1.0.1:
+ resolution: {integrity: sha1-mEcocL8igTL8vdhoEputEsPAKeM=}
+ dev: true
+
+ /promise-map-series/0.3.0:
+ resolution: {integrity: sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA==}
+ engines: {node: 10.* || >= 12.*}
+ dev: true
+
+ /promise.allsettled/1.0.5:
+ resolution: {integrity: sha512-tVDqeZPoBC0SlzJHzWGZ2NKAguVq2oiYj7gbggbiTvH2itHohijTp7njOUA0aQ/nl+0lr/r6egmhoYu63UZ/pQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ array.prototype.map: 1.0.4
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ get-intrinsic: 1.1.1
+ iterate-value: 1.0.2
+ dev: true
+
+ /promise.prototype.finally/3.1.3:
+ resolution: {integrity: sha512-EXRF3fC9/0gz4qkt/f5EP5iW4kj9oFpBICNpCNOb/52+8nlHIX07FPLbi/q4qYBQ1xZqivMzTpNQSnArVASolQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /prompts/2.4.2:
+ resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==}
+ engines: {node: '>= 6'}
+ dependencies:
+ kleur: 3.0.3
+ sisteransi: 1.0.5
+ dev: true
+
+ /prop-types/15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
+ /property-information/5.6.0:
+ resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==}
+ dependencies:
+ xtend: 4.0.2
+ dev: true
+
+ /proxy-addr/2.0.7:
+ resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ forwarded: 0.2.0
+ ipaddr.js: 1.9.1
+ dev: true
+
+ /proxy-from-env/1.0.0:
+ resolution: {integrity: sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=}
+ dev: true
+
+ /prr/1.0.1:
+ resolution: {integrity: sha1-0/wRS6BplaRexok/SEzrHXj19HY=}
+ dev: true
+
+ /psl/1.8.0:
+ resolution: {integrity: sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==}
+ dev: true
+
+ /public-encrypt/4.0.3:
+ resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==}
+ dependencies:
+ bn.js: 4.12.0
+ browserify-rsa: 4.1.0
+ create-hash: 1.2.0
+ parse-asn1: 5.1.6
+ randombytes: 2.1.0
+ safe-buffer: 5.2.1
+ dev: true
+
+ /pump/2.0.1:
+ resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==}
+ dependencies:
+ end-of-stream: 1.4.4
+ once: 1.4.0
+ dev: true
+
+ /pump/3.0.0:
+ resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
+ dependencies:
+ end-of-stream: 1.4.4
+ once: 1.4.0
+ dev: true
+
+ /pumpify/1.5.1:
+ resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==}
+ dependencies:
+ duplexify: 3.7.1
+ inherits: 2.0.4
+ pump: 2.0.1
+ dev: true
+
+ /punycode/1.3.2:
+ resolution: {integrity: sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=}
+ dev: true
+
+ /punycode/1.4.1:
+ resolution: {integrity: sha1-wNWmOycYgArY4esPpSachN1BhF4=}
+ dev: true
+
+ /punycode/2.1.1:
+ resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /qs/6.10.3:
+ resolution: {integrity: sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==}
+ engines: {node: '>=0.6'}
+ dependencies:
+ side-channel: 1.0.4
+ dev: true
+
+ /qs/6.5.3:
+ resolution: {integrity: sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==}
+ engines: {node: '>=0.6'}
+ dev: true
+
+ /qs/6.9.6:
+ resolution: {integrity: sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==}
+ engines: {node: '>=0.6'}
+ dev: true
+
+ /querystring-es3/0.2.1:
+ resolution: {integrity: sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=}
+ engines: {node: '>=0.4.x'}
+ dev: true
+
+ /querystring/0.2.0:
+ resolution: {integrity: sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=}
+ engines: {node: '>=0.4.x'}
+ deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
+ dev: true
+
+ /querystring/0.2.1:
+ resolution: {integrity: sha512-wkvS7mL/JMugcup3/rMitHmd9ecIGd2lhFhK9N3UUQ450h66d1r3Y9nvXzQAW1Lq+wyx61k/1pfKS5KuKiyEbg==}
+ engines: {node: '>=0.4.x'}
+ deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead.
+ dev: true
+
+ /queue-microtask/1.2.3:
+ resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
+ dev: true
+
+ /quick-temp/0.1.8:
+ resolution: {integrity: sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg=}
+ dependencies:
+ mktemp: 0.4.0
+ rimraf: 2.7.1
+ underscore.string: 3.3.6
+ dev: true
+
+ /ramda/0.21.0:
+ resolution: {integrity: sha1-oAGr7bP/YQd9T/HVd9RN536NCjU=}
+ dev: true
+
+ /randombytes/2.1.0:
+ resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /randomfill/1.0.4:
+ resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==}
+ dependencies:
+ randombytes: 2.1.0
+ safe-buffer: 5.2.1
+ dev: true
+
+ /range-parser/1.2.1:
+ resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /raw-body/2.4.2:
+ resolution: {integrity: sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==}
+ engines: {node: '>= 0.8'}
+ dependencies:
+ bytes: 3.1.1
+ http-errors: 1.8.1
+ iconv-lite: 0.4.24
+ unpipe: 1.0.0
+ dev: true
+
+ /raw-loader/4.0.2_webpack@4.46.0:
+ resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ loader-utils: 2.0.2
+ schema-utils: 3.1.1
+ webpack: 4.46.0
+ dev: true
+
+ /rc-year-calendar/1.0.2_at7mkepldmzoo6silmqc5bca74:
+ resolution: {integrity: sha512-TdEHZ4hs3WEuEAAmX/HEWlK7EZwhACkpuJKdkxL360igekuQDguyXTC9RuDFdk6lv4CAT7L4d4D6PTP7zUMBlQ==}
+ peerDependencies:
+ prop-types: ^15.7.2
+ react: ^16.8.4 || 17
+ dependencies:
+ js-year-calendar: 1.0.2
+ prop-types: 15.8.1
+ react: 17.0.2
+ dev: false
+
+ /react-colorful/5.5.1_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg==}
+ peerDependencies:
+ react: '>=16.8.0 || 17'
+ react-dom: '>=16.8.0 || 17'
+ dependencies:
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: true
+
+ /react-docgen-typescript/2.2.2_typescript@4.5.5:
+ resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==}
+ peerDependencies:
+ typescript: '>= 4.3.x'
+ dependencies:
+ typescript: 4.5.5
+ dev: true
+
+ /react-docgen/5.4.0:
+ resolution: {integrity: sha512-JBjVQ9cahmNlfjMGxWUxJg919xBBKAoy3hgDgKERbR+BcF4ANpDuzWAScC7j27hZfd8sJNmMPOLWo9+vB/XJEQ==}
+ engines: {node: '>=8.10.0'}
+ hasBin: true
+ dependencies:
+ '@babel/core': 7.17.0
+ '@babel/generator': 7.17.0
+ '@babel/runtime': 7.17.0
+ ast-types: 0.14.2
+ commander: 2.20.3
+ doctrine: 3.0.0
+ estree-to-babel: 3.2.1
+ neo-async: 2.6.2
+ node-dir: 0.1.17
+ strip-indent: 3.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /react-dom/17.0.2_react@17.0.2:
+ resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==}
+ peerDependencies:
+ react: 17.0.2 || 17
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react: 17.0.2
+ scheduler: 0.20.2
+ dev: false
+
+ /react-draggable/4.4.4_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==}
+ peerDependencies:
+ react: '>= 16.3.0 || 17'
+ react-dom: '>= 16.3.0 || 17'
+ dependencies:
+ clsx: 1.1.1
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: true
+
+ /react-element-to-jsx-string/14.3.4_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==}
+ peerDependencies:
+ react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || 17
+ react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 || 17
+ dependencies:
+ '@base2/pretty-print-object': 1.0.1
+ is-plain-object: 5.0.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-is: 17.0.2
+ dev: true
+
+ /react-fast-compare/3.2.0:
+ resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==}
+ dev: true
+
+ /react-google-login/5.2.2_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-JUngfvaSMcOuV0lFff7+SzJ2qviuNMQdqlsDJkUM145xkGPVIfqWXq9Ui+2Dr6jdJWH5KYdynz9+4CzKjI5u6g==}
+ peerDependencies:
+ react: ^16 || ^17 || 17
+ react-dom: ^16 || ^17 || 17
+ dependencies:
+ '@types/react': 17.0.39
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /react-helmet-async/1.2.2_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-XgSQezeCbLfCxdZhDA3T/g27XZKnOYyOkruopTLSJj8RvFZwdXnM4djnfYaiBSDzOidDgTo1jcEozoRu/+P9UQ==}
+ peerDependencies:
+ react: ^16.6.0 || ^17.0.0 || 17
+ react-dom: ^16.6.0 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ invariant: 2.2.4
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-fast-compare: 3.2.0
+ shallowequal: 1.1.0
+ dev: true
+
+ /react-hook-form/7.26.1_react@17.0.2:
+ resolution: {integrity: sha512-/Qw/7IsCCVfYSGryJAMcouEpIDgWZJPeHR15J0IFSgo1BgofcfnY+AeUDcYD1E3yzzXYpR7NHyJehhkBKvjdMg==}
+ engines: {node: '>=12.22.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17 || 17
+ dependencies:
+ react: 17.0.2
+ dev: false
+
+ /react-i18next/11.15.4_h63ejkrqcivap6la2z72khlnye:
+ resolution: {integrity: sha512-jKJNAcVcbPGK+yrTcXhLblgPY16n6NbpZZL3Mk8nswj1v3ayIiUBVDU09SgqnT+DluyQBS97hwSvPU5yVFG0yg==}
+ peerDependencies:
+ i18next: '>= 19.0.0'
+ react: '>= 16.8.0 || 17'
+ react-dom: '*'
+ react-native: '*'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ html-escaper: 2.0.2
+ html-parse-stringify: 3.0.1
+ i18next: 21.6.11
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /react-icons/4.3.1_react@17.0.2:
+ resolution: {integrity: sha512-cB10MXLTs3gVuXimblAdI71jrJx8njrJZmNMEMC+sQu5B/BIOmlsAjskdqpn81y8UBVEGuHODd7/ci5DvoSzTQ==}
+ peerDependencies:
+ react: '*'
+ dependencies:
+ react: 17.0.2
+ dev: false
+
+ /react-inspector/5.1.1_react@17.0.2:
+ resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==}
+ peerDependencies:
+ react: ^16.8.4 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ is-dom: 1.1.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ dev: true
+
+ /react-is/16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ /react-is/17.0.2:
+ resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
+
+ /react-load-script/0.0.6_at7mkepldmzoo6silmqc5bca74:
+ resolution: {integrity: sha512-aRGxDGP9VoLxcsaYvKWIW+LRrMOzz2eEcubTS4NvQPPugjk2VvMhow0wWTkSl7RxookomD1MwcP4l5UStg5ShQ==}
+ deprecated: abandoned and unmaintained
+ peerDependencies:
+ prop-types: '>=15'
+ react: '>=0.14.9 || 17'
+ dependencies:
+ prop-types: 15.8.1
+ react: 17.0.2
+ dev: false
+
+ /react-native-segmented-control-tab/3.4.1:
+ resolution: {integrity: sha512-BNPdlE9Unr0Xabewn8W+FhBMLjssXy9Ey7S7AY0hXlrKrEKFdC9z0yT+eEWd5dLam4T6T4IuGL8b7ZF4uGyWNw==}
+ dev: false
+
+ /react-popper-tooltip/3.1.1_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==}
+ peerDependencies:
+ react: ^16.6.0 || ^17.0.0 || 17
+ react-dom: ^16.6.0 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@popperjs/core': 2.11.2
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-popper: 2.2.5_jvejhdhmibhthrzxlktliu4udq
+ dev: true
+
+ /react-popper/2.2.5_jvejhdhmibhthrzxlktliu4udq:
+ resolution: {integrity: sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==}
+ peerDependencies:
+ '@popperjs/core': ^2.0.0
+ react: ^16.8.0 || ^17 || 17
+ dependencies:
+ '@popperjs/core': 2.11.2
+ react: 17.0.2
+ react-fast-compare: 3.2.0
+ warning: 4.0.3
+ dev: true
+
+ /react-redux-form/1.16.14_63tzpzdcuxiupedwoo4b6s3rxy:
+ resolution: {integrity: sha512-exd8FoWwJRQynjnYqCLmcbwcqgRPyU+qiKmTA7/T8qlNgyqgmbAgkYNe9NG9FYb5oLgHAtx5vDhVEpje888lIA==}
+ peerDependencies:
+ react: ^15.3.0 || ^16.0.0 || 17
+ react-dom: ^0.14.7 || ^15.0.0 || ^16.0.0 || 17
+ react-redux: ^4.0.0 || ^5.0.3 || ^7.0.0
+ redux: ^3.0.0 || ^4.0.0
+ dependencies:
+ icepick: 1.3.0
+ invariant: 2.2.4
+ lodash.get: 4.4.2
+ lodash.topath: 4.5.2
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-native-segmented-control-tab: 3.4.1
+ react-redux: 7.2.6_sfoxds7t5ydpegc3knd667wn6m
+ redux: 4.1.2
+ shallow-compare: 1.2.2
+ dev: false
+
+ /react-redux/7.2.6_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==}
+ peerDependencies:
+ react: ^16.8.3 || ^17 || 17
+ react-dom: '*'
+ react-native: '*'
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ react-native:
+ optional: true
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@types/react-redux': 7.1.22
+ hoist-non-react-statics: 3.3.2
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-is: 17.0.2
+ dev: false
+
+ /react-refresh/0.11.0:
+ resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /react-router-dom/4.3.1_react@17.0.2:
+ resolution: {integrity: sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==}
+ peerDependencies:
+ react: '>=15 || 17'
+ dependencies:
+ history: 4.10.1
+ invariant: 2.2.4
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-router: 4.3.1_react@17.0.2
+ warning: 4.0.3
+ dev: false
+
+ /react-router-dom/6.2.1_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-I6Zax+/TH/cZMDpj3/4Fl2eaNdcvoxxHoH1tYOREsQ22OKDYofGebrNm6CTPUcvLvZm63NL/vzCYdjf9CUhqmA==}
+ peerDependencies:
+ react: '>=16.8 || 17'
+ react-dom: '>=16.8 || 17'
+ dependencies:
+ history: 5.2.0
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-router: 6.2.1_react@17.0.2
+ dev: true
+
+ /react-router/4.3.1_react@17.0.2:
+ resolution: {integrity: sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==}
+ peerDependencies:
+ react: '>=15 || 17'
+ dependencies:
+ history: 4.10.1
+ hoist-non-react-statics: 2.5.5
+ invariant: 2.2.4
+ loose-envify: 1.4.0
+ path-to-regexp: 1.8.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ warning: 4.0.3
+ dev: false
+
+ /react-router/6.2.1_react@17.0.2:
+ resolution: {integrity: sha512-2fG0udBtxou9lXtK97eJeET2ki5//UWfQSl1rlJ7quwe6jrktK9FCCc8dQb5QY6jAv3jua8bBQRhhDOM/kVRsg==}
+ peerDependencies:
+ react: '>=16.8 || 17'
+ dependencies:
+ history: 5.2.0
+ react: 17.0.2
+ dev: true
+
+ /react-select/5.2.2_xd63vgjm47lzoal5ybyqmsdesy:
+ resolution: {integrity: sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ react-dom: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ '@emotion/cache': 11.7.1
+ '@emotion/react': 11.7.1_udcsdvdzjr5ns727jqoeu7kyda
+ '@types/react-transition-group': 4.4.4
+ memoize-one: 5.2.1
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-transition-group: 4.4.2_sfoxds7t5ydpegc3knd667wn6m
+ transitivePeerDependencies:
+ - '@babel/core'
+ - '@types/react'
+ dev: false
+
+ /react-sizeme/3.0.2:
+ resolution: {integrity: sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==}
+ dependencies:
+ element-resize-detector: 1.2.4
+ invariant: 2.2.4
+ shallowequal: 1.1.0
+ throttle-debounce: 3.0.1
+ dev: true
+
+ /react-syntax-highlighter/13.5.3_react@17.0.2:
+ resolution: {integrity: sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==}
+ peerDependencies:
+ react: '>= 0.14.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ highlight.js: 10.7.3
+ lowlight: 1.20.0
+ prismjs: 1.26.0
+ react: 17.0.2
+ refractor: 3.5.0
+ dev: true
+
+ /react-table/6.11.5_oxfzelaz5ynxsop2v2nu2h2m64:
+ resolution: {integrity: sha512-LM+AS9v//7Y7lAlgTWW/cW6Sn5VOb3EsSkKQfQTzOW8FngB1FUskLLNEVkAYsTX9LjOWR3QlGjykJqCE6eXT/g==}
+ peerDependencies:
+ prop-types: ^15.7.0
+ react: ^16.x.x || 17
+ react-dom: ^16.x.x || 17
+ dependencies:
+ '@types/react-table': 6.8.9
+ classnames: 2.3.1
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ react-is: 16.13.1
+ dev: false
+
+ /react-textarea-autosize/8.3.3_udcsdvdzjr5ns727jqoeu7kyda:
+ resolution: {integrity: sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ '@babel/runtime': 7.17.0
+ react: 17.0.2
+ use-composed-ref: 1.2.1_react@17.0.2
+ use-latest: 1.2.0_udcsdvdzjr5ns727jqoeu7kyda
+ transitivePeerDependencies:
+ - '@types/react'
+ dev: true
+
+ /react-transition-group/4.4.2_sfoxds7t5ydpegc3knd667wn6m:
+ resolution: {integrity: sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==}
+ peerDependencies:
+ react: '>=16.6.0 || 17'
+ react-dom: '>=16.6.0 || 17'
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 17.0.2
+ react-dom: 17.0.2_react@17.0.2
+ dev: false
+
+ /react/17.0.2:
+ resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ dev: false
+
+ /read-only-stream/2.0.0:
+ resolution: {integrity: sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=}
+ dependencies:
+ readable-stream: 2.3.7
+ dev: true
+
+ /read-pkg-up/7.0.1:
+ resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==}
+ engines: {node: '>=8'}
+ dependencies:
+ find-up: 4.1.0
+ read-pkg: 5.2.0
+ type-fest: 0.8.1
+ dev: true
+
+ /read-pkg/5.2.0:
+ resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@types/normalize-package-data': 2.4.1
+ normalize-package-data: 2.5.0
+ parse-json: 5.2.0
+ type-fest: 0.6.0
+ dev: true
+
+ /readable-stream/2.3.7:
+ resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==}
+ dependencies:
+ core-util-is: 1.0.3
+ inherits: 2.0.4
+ isarray: 1.0.0
+ process-nextick-args: 2.0.1
+ safe-buffer: 5.1.2
+ string_decoder: 1.1.1
+ util-deprecate: 1.0.2
+ dev: true
+
+ /readable-stream/3.6.0:
+ resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
+ engines: {node: '>= 6'}
+ dependencies:
+ inherits: 2.0.4
+ string_decoder: 1.3.0
+ util-deprecate: 1.0.2
+ dev: true
+
+ /readdirp/2.2.1:
+ resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==}
+ engines: {node: '>=0.10'}
+ dependencies:
+ graceful-fs: 4.2.9
+ micromatch: 3.1.10
+ readable-stream: 2.3.7
+ dev: true
+ optional: true
+
+ /readdirp/3.6.0:
+ resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
+ engines: {node: '>=8.10.0'}
+ dependencies:
+ picomatch: 2.3.1
+ dev: true
+
+ /redux-persist/6.0.0_redux@4.1.2:
+ resolution: {integrity: sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==}
+ peerDependencies:
+ redux: '>4.0.0'
+ dependencies:
+ redux: 4.1.2
+ dev: false
+
+ /redux-saga/1.1.3:
+ resolution: {integrity: sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==}
+ dependencies:
+ '@redux-saga/core': 1.1.3
+ dev: false
+
+ /redux-thunk/2.4.1_redux@4.1.2:
+ resolution: {integrity: sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q==}
+ peerDependencies:
+ redux: ^4
+ dependencies:
+ redux: 4.1.2
+ dev: false
+
+ /redux/4.1.2:
+ resolution: {integrity: sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: false
+
+ /refractor/3.5.0:
+ resolution: {integrity: sha512-QwPJd3ferTZ4cSPPjdP5bsYHMytwWYnAN5EEnLtGvkqp/FCCnGsBgxrm9EuIDnjUC3Uc/kETtvVi7fSIVC74Dg==}
+ dependencies:
+ hastscript: 6.0.0
+ parse-entities: 2.0.0
+ prismjs: 1.25.0
+ dev: true
+
+ /regenerate-unicode-properties/10.0.1:
+ resolution: {integrity: sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==}
+ engines: {node: '>=4'}
+ dependencies:
+ regenerate: 1.4.2
+ dev: true
+
+ /regenerate/1.4.2:
+ resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==}
+ dev: true
+
+ /regenerator-runtime/0.13.9:
+ resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
+
+ /regenerator-transform/0.14.5:
+ resolution: {integrity: sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==}
+ dependencies:
+ '@babel/runtime': 7.17.0
+ dev: true
+
+ /regex-not/1.0.2:
+ resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ extend-shallow: 3.0.2
+ safe-regex: 1.1.0
+ dev: true
+
+ /regexp.prototype.flags/1.4.1:
+ resolution: {integrity: sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ dev: true
+
+ /regexpp/3.2.0:
+ resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /regexpu-core/5.0.1:
+ resolution: {integrity: sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==}
+ engines: {node: '>=4'}
+ dependencies:
+ regenerate: 1.4.2
+ regenerate-unicode-properties: 10.0.1
+ regjsgen: 0.6.0
+ regjsparser: 0.8.4
+ unicode-match-property-ecmascript: 2.0.0
+ unicode-match-property-value-ecmascript: 2.0.0
+ dev: true
+
+ /regjsgen/0.6.0:
+ resolution: {integrity: sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==}
+ dev: true
+
+ /regjsparser/0.8.4:
+ resolution: {integrity: sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==}
+ hasBin: true
+ dependencies:
+ jsesc: 0.5.0
+ dev: true
+
+ /relateurl/0.2.7:
+ resolution: {integrity: sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /release-zalgo/1.0.0:
+ resolution: {integrity: sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=}
+ engines: {node: '>=4'}
+ dependencies:
+ es6-error: 4.1.1
+ dev: true
+
+ /remark-external-links/8.0.0:
+ resolution: {integrity: sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==}
+ dependencies:
+ extend: 3.0.2
+ is-absolute-url: 3.0.3
+ mdast-util-definitions: 4.0.0
+ space-separated-tokens: 1.1.5
+ unist-util-visit: 2.0.3
+ dev: true
+
+ /remark-footnotes/2.0.0:
+ resolution: {integrity: sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==}
+ dev: true
+
+ /remark-mdx/1.6.22:
+ resolution: {integrity: sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==}
+ dependencies:
+ '@babel/core': 7.12.9
+ '@babel/helper-plugin-utils': 7.10.4
+ '@babel/plugin-proposal-object-rest-spread': 7.12.1_@babel+core@7.12.9
+ '@babel/plugin-syntax-jsx': 7.12.1_@babel+core@7.12.9
+ '@mdx-js/util': 1.6.22
+ is-alphabetical: 1.0.4
+ remark-parse: 8.0.3
+ unified: 9.2.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /remark-parse/8.0.3:
+ resolution: {integrity: sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==}
+ dependencies:
+ ccount: 1.1.0
+ collapse-white-space: 1.0.6
+ is-alphabetical: 1.0.4
+ is-decimal: 1.0.4
+ is-whitespace-character: 1.0.4
+ is-word-character: 1.0.4
+ markdown-escapes: 1.0.4
+ parse-entities: 2.0.0
+ repeat-string: 1.6.1
+ state-toggle: 1.0.3
+ trim: 0.0.1
+ trim-trailing-lines: 1.1.4
+ unherit: 1.1.3
+ unist-util-remove-position: 2.0.1
+ vfile-location: 3.2.0
+ xtend: 4.0.2
+ dev: true
+
+ /remark-slug/6.1.0:
+ resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==}
+ dependencies:
+ github-slugger: 1.4.0
+ mdast-util-to-string: 1.1.0
+ unist-util-visit: 2.0.3
+ dev: true
+
+ /remark-squeeze-paragraphs/4.0.0:
+ resolution: {integrity: sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==}
+ dependencies:
+ mdast-squeeze-paragraphs: 4.0.0
+ dev: true
+
+ /remove-bom-buffer/3.0.0:
+ resolution: {integrity: sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-buffer: 1.1.6
+ is-utf8: 0.2.1
+ dev: true
+
+ /remove-bom-stream/1.2.0:
+ resolution: {integrity: sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ remove-bom-buffer: 3.0.0
+ safe-buffer: 5.2.1
+ through2: 2.0.5
+ dev: true
+
+ /remove-trailing-separator/1.1.0:
+ resolution: {integrity: sha1-wkvOKig62tW8P1jg1IJJuSN52O8=}
+ dev: true
+
+ /renderkid/2.0.7:
+ resolution: {integrity: sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==}
+ dependencies:
+ css-select: 4.2.1
+ dom-converter: 0.2.0
+ htmlparser2: 6.1.0
+ lodash: 4.17.21
+ strip-ansi: 3.0.1
+ dev: true
+
+ /repeat-element/1.1.4:
+ resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /repeat-string/1.6.1:
+ resolution: {integrity: sha1-jcrkcOHIirwtYA//Sndihtp15jc=}
+ engines: {node: '>=0.10'}
+ dev: true
+
+ /replace-ext/1.0.1:
+ resolution: {integrity: sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /request-progress/3.0.0:
+ resolution: {integrity: sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=}
+ dependencies:
+ throttleit: 1.0.0
+ dev: true
+
+ /require-directory/2.1.1:
+ resolution: {integrity: sha1-jGStX9MNqxyXbiNE/+f3kqam30I=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /require-main-filename/2.0.0:
+ resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
+ dev: true
+
+ /reselect/4.1.5:
+ resolution: {integrity: sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ==}
+ dev: false
+
+ /resize-observer-polyfill/1.5.1:
+ resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
+ dev: false
+
+ /resolve-from/4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /resolve-from/5.0.0:
+ resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /resolve-options/1.1.0:
+ resolution: {integrity: sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ value-or-function: 3.0.0
+ dev: true
+
+ /resolve-pathname/3.0.0:
+ resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==}
+ dev: false
+
+ /resolve-url/0.2.1:
+ resolution: {integrity: sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=}
+ deprecated: https://github.com/lydell/resolve-url#deprecated
+ dev: true
+
+ /resolve/1.22.0:
+ resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==}
+ hasBin: true
+ dependencies:
+ is-core-module: 2.8.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+ dev: true
+
+ /resolve/2.0.0-next.3:
+ resolution: {integrity: sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==}
+ dependencies:
+ is-core-module: 2.8.1
+ path-parse: 1.0.7
+ dev: true
+
+ /resq/1.10.2:
+ resolution: {integrity: sha512-HmgVS3j+FLrEDBTDYysPdPVF9/hioDMJ/otOiQDKqk77YfZeeLOj0qi34yObumcud1gBpk+wpBTEg4kMicD++A==}
+ dependencies:
+ fast-deep-equal: 2.0.1
+ dev: true
+
+ /restore-cursor/3.1.0:
+ resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==}
+ engines: {node: '>=8'}
+ dependencies:
+ onetime: 5.1.2
+ signal-exit: 3.0.7
+ dev: true
+
+ /ret/0.1.15:
+ resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==}
+ engines: {node: '>=0.12'}
+ dev: true
+
+ /reusify/1.0.4:
+ resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
+ engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ dev: true
+
+ /rfdc/1.3.0:
+ resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==}
+ dev: true
+
+ /rimraf/2.7.1:
+ resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.0
+ dev: true
+
+ /rimraf/3.0.2:
+ resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ hasBin: true
+ dependencies:
+ glob: 7.2.0
+ dev: true
+
+ /ripemd160/2.0.2:
+ resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==}
+ dependencies:
+ hash-base: 3.1.0
+ inherits: 2.0.4
+ dev: true
+
+ /robust-predicates/3.0.1:
+ resolution: {integrity: sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==}
+ dev: false
+
+ /rollup/2.67.1:
+ resolution: {integrity: sha512-1Sbcs4OuW+aD+hhqpIRl+RqooIpF6uQcfzU/QSI7vGkwADY6cM4iLsBGRM2CGLXDTDN5y/yShohFmnKegSPWzg==}
+ engines: {node: '>=10.0.0'}
+ hasBin: true
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /rsvp/3.2.1:
+ resolution: {integrity: sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo=}
+ dev: true
+
+ /rsvp/4.8.5:
+ resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==}
+ engines: {node: 6.* || >= 7.*}
+ dev: true
+
+ /run-parallel/1.2.0:
+ resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
+ dependencies:
+ queue-microtask: 1.2.3
+ dev: true
+
+ /run-queue/1.0.3:
+ resolution: {integrity: sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=}
+ dependencies:
+ aproba: 1.2.0
+ dev: true
+
+ /rw/1.3.3:
+ resolution: {integrity: sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q=}
+ dev: false
+
+ /rxjs/7.5.2:
+ resolution: {integrity: sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==}
+ dependencies:
+ tslib: 2.3.1
+ dev: true
+
+ /safe-buffer/5.1.1:
+ resolution: {integrity: sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==}
+ dev: true
+
+ /safe-buffer/5.1.2:
+ resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
+ dev: true
+
+ /safe-buffer/5.2.1:
+ resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
+ dev: true
+
+ /safe-regex/1.1.0:
+ resolution: {integrity: sha1-QKNmnzsHfR6UPURinhV91IAjvy4=}
+ dependencies:
+ ret: 0.1.15
+ dev: true
+
+ /safer-buffer/2.1.2:
+ resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
+
+ /sane/4.1.0:
+ resolution: {integrity: sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==}
+ engines: {node: 6.* || 8.* || >= 10.*}
+ deprecated: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added
+ hasBin: true
+ dependencies:
+ '@cnakazawa/watch': 1.0.4
+ anymatch: 2.0.0
+ capture-exit: 2.0.0
+ exec-sh: 0.3.6
+ execa: 1.0.0
+ fb-watchman: 2.0.1
+ micromatch: 3.1.10
+ minimist: 1.2.5
+ walker: 1.0.8
+ dev: true
+
+ /sass/1.49.7:
+ resolution: {integrity: sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ==}
+ engines: {node: '>=12.0.0'}
+ hasBin: true
+ dependencies:
+ chokidar: 3.5.3
+ immutable: 4.0.0
+ source-map-js: 1.0.2
+ dev: true
+
+ /scheduler/0.20.2:
+ resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==}
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ dev: false
+
+ /schema-utils/1.0.0:
+ resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==}
+ engines: {node: '>= 4'}
+ dependencies:
+ ajv: 6.12.6
+ ajv-errors: 1.0.1_ajv@6.12.6
+ ajv-keywords: 3.5.2_ajv@6.12.6
+ dev: true
+
+ /schema-utils/2.7.0:
+ resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==}
+ engines: {node: '>= 8.9.0'}
+ dependencies:
+ '@types/json-schema': 7.0.9
+ ajv: 6.12.6
+ ajv-keywords: 3.5.2_ajv@6.12.6
+ dev: true
+
+ /schema-utils/2.7.1:
+ resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==}
+ engines: {node: '>= 8.9.0'}
+ dependencies:
+ '@types/json-schema': 7.0.9
+ ajv: 6.12.6
+ ajv-keywords: 3.5.2_ajv@6.12.6
+ dev: true
+
+ /schema-utils/3.1.1:
+ resolution: {integrity: sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==}
+ engines: {node: '>= 10.13.0'}
+ dependencies:
+ '@types/json-schema': 7.0.9
+ ajv: 6.12.6
+ ajv-keywords: 3.5.2_ajv@6.12.6
+ dev: true
+
+ /semver/5.7.1:
+ resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
+ hasBin: true
+ dev: true
+
+ /semver/6.3.0:
+ resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
+ hasBin: true
+ dev: true
+
+ /semver/7.0.0:
+ resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==}
+ hasBin: true
+ dev: true
+
+ /semver/7.3.5:
+ resolution: {integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==}
+ engines: {node: '>=10'}
+ hasBin: true
+ dependencies:
+ lru-cache: 6.0.0
+ dev: true
+
+ /send/0.17.2:
+ resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ debug: 2.6.9
+ depd: 1.1.2
+ destroy: 1.0.4
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ etag: 1.8.1
+ fresh: 0.5.2
+ http-errors: 1.8.1
+ mime: 1.6.0
+ ms: 2.1.3
+ on-finished: 2.3.0
+ range-parser: 1.2.1
+ statuses: 1.5.0
+ dev: true
+
+ /serialize-javascript/4.0.0:
+ resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==}
+ dependencies:
+ randombytes: 2.1.0
+ dev: true
+
+ /serialize-javascript/5.0.1:
+ resolution: {integrity: sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==}
+ dependencies:
+ randombytes: 2.1.0
+ dev: true
+
+ /serve-favicon/2.5.0:
+ resolution: {integrity: sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ etag: 1.8.1
+ fresh: 0.5.2
+ ms: 2.1.1
+ parseurl: 1.3.3
+ safe-buffer: 5.1.1
+ dev: true
+
+ /serve-static/1.14.2:
+ resolution: {integrity: sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ encodeurl: 1.0.2
+ escape-html: 1.0.3
+ parseurl: 1.3.3
+ send: 0.17.2
+ dev: true
+
+ /set-blocking/2.0.0:
+ resolution: {integrity: sha1-BF+XgtARrppoA93TgrJDkrPYkPc=}
+ dev: true
+
+ /set-value/2.0.1:
+ resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ extend-shallow: 2.0.1
+ is-extendable: 0.1.1
+ is-plain-object: 2.0.4
+ split-string: 3.1.0
+ dev: true
+
+ /setimmediate/1.0.5:
+ resolution: {integrity: sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=}
+ dev: true
+
+ /setprototypeof/1.2.0:
+ resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ dev: true
+
+ /sha.js/2.4.11:
+ resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==}
+ hasBin: true
+ dependencies:
+ inherits: 2.0.4
+ safe-buffer: 5.2.1
+ dev: true
+
+ /shallow-clone/3.0.1:
+ resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==}
+ engines: {node: '>=8'}
+ dependencies:
+ kind-of: 6.0.3
+ dev: true
+
+ /shallow-compare/1.2.2:
+ resolution: {integrity: sha512-LUMFi+RppPlrHzbqmFnINTrazo0lPNwhcgzuAXVVcfy/mqPDrQmHAyz5bvV0gDAuRFrk804V0HpQ6u9sZ0tBeg==}
+ dev: false
+
+ /shallowequal/1.1.0:
+ resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==}
+ dev: true
+
+ /shasum-object/1.0.0:
+ resolution: {integrity: sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==}
+ dependencies:
+ fast-safe-stringify: 2.1.1
+ dev: true
+
+ /shasum/1.0.2:
+ resolution: {integrity: sha1-5wEjENj0F/TetXEhUOVni4euVl8=}
+ dependencies:
+ json-stable-stringify: 0.0.1
+ sha.js: 2.4.11
+ dev: true
+
+ /shebang-command/1.2.0:
+ resolution: {integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ shebang-regex: 1.0.0
+ dev: true
+
+ /shebang-command/2.0.0:
+ resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
+ engines: {node: '>=8'}
+ dependencies:
+ shebang-regex: 3.0.0
+ dev: true
+
+ /shebang-regex/1.0.0:
+ resolution: {integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /shebang-regex/3.0.0:
+ resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /shell-quote/1.7.3:
+ resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==}
+ dev: true
+
+ /side-channel/1.0.4:
+ resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
+ dependencies:
+ call-bind: 1.0.2
+ get-intrinsic: 1.1.1
+ object-inspect: 1.12.0
+ dev: true
+
+ /signal-exit/3.0.7:
+ resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
+ dev: true
+
+ /simple-concat/1.0.1:
+ resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
+ dev: true
+
+ /sisteransi/1.0.5:
+ resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ dev: true
+
+ /slash/2.0.0:
+ resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /slash/3.0.0:
+ resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /slice-ansi/3.0.0:
+ resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-styles: 4.3.0
+ astral-regex: 2.0.0
+ is-fullwidth-code-point: 3.0.0
+ dev: true
+
+ /slice-ansi/4.0.0:
+ resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ astral-regex: 2.0.0
+ is-fullwidth-code-point: 3.0.0
+ dev: true
+
+ /slice-ansi/5.0.0:
+ resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-styles: 6.1.0
+ is-fullwidth-code-point: 4.0.0
+ dev: true
+
+ /snapdragon-node/2.1.1:
+ resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ define-property: 1.0.0
+ isobject: 3.0.1
+ snapdragon-util: 3.0.1
+ dev: true
+
+ /snapdragon-util/3.0.1:
+ resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 3.2.2
+ dev: true
+
+ /snapdragon/0.8.2:
+ resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ base: 0.11.2
+ debug: 2.6.9
+ define-property: 0.2.5
+ extend-shallow: 2.0.1
+ map-cache: 0.2.2
+ source-map: 0.5.7
+ source-map-resolve: 0.5.3
+ use: 3.1.1
+ dev: true
+
+ /sort-keys/4.2.0:
+ resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==}
+ engines: {node: '>=8'}
+ dependencies:
+ is-plain-obj: 2.1.0
+ dev: true
+
+ /source-list-map/2.0.1:
+ resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==}
+ dev: true
+
+ /source-map-js/1.0.2:
+ resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map-resolve/0.5.3:
+ resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==}
+ deprecated: See https://github.com/lydell/source-map-resolve#deprecated
+ dependencies:
+ atob: 2.1.2
+ decode-uri-component: 0.2.0
+ resolve-url: 0.2.1
+ source-map-url: 0.4.1
+ urix: 0.1.0
+ dev: true
+
+ /source-map-support/0.5.21:
+ resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==}
+ dependencies:
+ buffer-from: 1.1.2
+ source-map: 0.6.1
+ dev: true
+
+ /source-map-url/0.4.1:
+ resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==}
+ deprecated: See https://github.com/lydell/source-map-url#deprecated
+ dev: true
+
+ /source-map/0.5.7:
+ resolution: {integrity: sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map/0.6.1:
+ resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /source-map/0.7.3:
+ resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==}
+ engines: {node: '>= 8'}
+ dev: true
+
+ /space-separated-tokens/1.1.5:
+ resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
+ dev: true
+
+ /spawn-wrap/2.0.0:
+ resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==}
+ engines: {node: '>=8'}
+ dependencies:
+ foreground-child: 2.0.0
+ is-windows: 1.0.2
+ make-dir: 3.1.0
+ rimraf: 3.0.2
+ signal-exit: 3.0.7
+ which: 2.0.2
+ dev: true
+
+ /spdx-correct/3.1.1:
+ resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
+ dependencies:
+ spdx-expression-parse: 3.0.1
+ spdx-license-ids: 3.0.11
+ dev: true
+
+ /spdx-exceptions/2.3.0:
+ resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
+ dev: true
+
+ /spdx-expression-parse/3.0.1:
+ resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
+ dependencies:
+ spdx-exceptions: 2.3.0
+ spdx-license-ids: 3.0.11
+ dev: true
+
+ /spdx-license-ids/3.0.11:
+ resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==}
+ dev: true
+
+ /split-string/3.1.0:
+ resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ extend-shallow: 3.0.2
+ dev: true
+
+ /sprintf-js/1.0.3:
+ resolution: {integrity: sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=}
+ dev: true
+
+ /sprintf-js/1.1.2:
+ resolution: {integrity: sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==}
+ dev: true
+
+ /sshpk/1.17.0:
+ resolution: {integrity: sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==}
+ engines: {node: '>=0.10.0'}
+ hasBin: true
+ dependencies:
+ asn1: 0.2.6
+ assert-plus: 1.0.0
+ bcrypt-pbkdf: 1.0.2
+ dashdash: 1.14.1
+ ecc-jsbn: 0.1.2
+ getpass: 0.1.7
+ jsbn: 0.1.1
+ safer-buffer: 2.1.2
+ tweetnacl: 0.14.5
+ dev: true
+
+ /ssri/6.0.2:
+ resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==}
+ dependencies:
+ figgy-pudding: 3.5.2
+ dev: true
+
+ /ssri/8.0.1:
+ resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==}
+ engines: {node: '>= 8'}
+ dependencies:
+ minipass: 3.1.6
+ dev: true
+
+ /stable/0.1.8:
+ resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
+ dev: true
+
+ /stackframe/1.2.0:
+ resolution: {integrity: sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA==}
+ dev: true
+
+ /state-toggle/1.0.3:
+ resolution: {integrity: sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==}
+ dev: true
+
+ /static-extend/0.1.2:
+ resolution: {integrity: sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ define-property: 0.2.5
+ object-copy: 0.1.0
+ dev: true
+
+ /statuses/1.5.0:
+ resolution: {integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=}
+ engines: {node: '>= 0.6'}
+ dev: true
+
+ /store2/2.13.1:
+ resolution: {integrity: sha512-iJtHSGmNgAUx0b/MCS6ASGxb//hGrHHRgzvN+K5bvkBTN7A9RTpPSf1WSp+nPGvWCJ1jRnvY7MKnuqfoi3OEqg==}
+ dev: true
+
+ /storybook-builder-vite/0.1.15_tittu3jxgxganfythqbtfovvv4:
+ resolution: {integrity: sha512-FFNbODnvzMsvwUgtsUhNaOvfUV0Hl/8XVGDU8fbIYttbTmTzVWDu2bpKOgRRuQTzHLnZmnaZraxQlWBujihtow==}
+ peerDependencies:
+ '@storybook/core-common': ^6.4.3
+ vite: '>=2.6.7'
+ peerDependenciesMeta:
+ '@storybook/core-common':
+ optional: true
+ dependencies:
+ '@joshwooding/vite-plugin-react-docgen-typescript': 0.0.2_opd4ws7dumj54hnyecb3t4fnpq
+ '@mdx-js/mdx': 1.6.22
+ '@storybook/csf-tools': 6.4.18
+ '@storybook/source-loader': 6.4.18_sfoxds7t5ydpegc3knd667wn6m
+ '@vitejs/plugin-react': 1.1.4
+ es-module-lexer: 0.9.3
+ glob: 7.2.0
+ glob-promise: 4.2.2_glob@7.2.0
+ slash: 3.0.0
+ vite: 2.7.13_sass@1.49.7
+ vite-plugin-mdx: 3.5.10_k4bmpxmaqlgvoeub2z775fx6ma
+ transitivePeerDependencies:
+ - react
+ - react-dom
+ - supports-color
+ - typescript
+ dev: true
+
+ /stream-browserify/2.0.2:
+ resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /stream-browserify/3.0.0:
+ resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 3.6.0
+ dev: true
+
+ /stream-combiner2/1.1.1:
+ resolution: {integrity: sha1-+02KFCDqNidk4hrUeAOXvry0HL4=}
+ dependencies:
+ duplexer2: 0.1.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /stream-each/1.2.3:
+ resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==}
+ dependencies:
+ end-of-stream: 1.4.4
+ stream-shift: 1.0.1
+ dev: true
+
+ /stream-http/2.8.3:
+ resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==}
+ dependencies:
+ builtin-status-codes: 3.0.0
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ to-arraybuffer: 1.0.1
+ xtend: 4.0.2
+ dev: true
+
+ /stream-http/3.2.0:
+ resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==}
+ dependencies:
+ builtin-status-codes: 3.0.0
+ inherits: 2.0.4
+ readable-stream: 3.6.0
+ xtend: 4.0.2
+ dev: true
+
+ /stream-shift/1.0.1:
+ resolution: {integrity: sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==}
+ dev: true
+
+ /stream-splicer/2.0.1:
+ resolution: {integrity: sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==}
+ dependencies:
+ inherits: 2.0.4
+ readable-stream: 2.3.7
+ dev: true
+
+ /string-argv/0.3.1:
+ resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==}
+ engines: {node: '>=0.6.19'}
+ dev: true
+
+ /string-width/4.2.3:
+ resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
+ engines: {node: '>=8'}
+ dependencies:
+ emoji-regex: 8.0.0
+ is-fullwidth-code-point: 3.0.0
+ strip-ansi: 6.0.1
+ dev: true
+
+ /string-width/5.1.0:
+ resolution: {integrity: sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==}
+ engines: {node: '>=12'}
+ dependencies:
+ eastasianwidth: 0.2.0
+ emoji-regex: 9.2.2
+ strip-ansi: 7.0.1
+ dev: true
+
+ /string.prototype.matchall/4.0.6:
+ resolution: {integrity: sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ get-intrinsic: 1.1.1
+ has-symbols: 1.0.2
+ internal-slot: 1.0.3
+ regexp.prototype.flags: 1.4.1
+ side-channel: 1.0.4
+ dev: true
+
+ /string.prototype.padend/3.1.3:
+ resolution: {integrity: sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /string.prototype.padstart/3.1.3:
+ resolution: {integrity: sha512-NZydyOMtYxpTjGqp0VN5PYUF/tsU15yDMZnUdj16qRUIUiMJkHHSDElYyQFrMu+/WloTpA7MQSiADhBicDfaoA==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ es-abstract: 1.19.1
+ dev: true
+
+ /string.prototype.trimend/1.0.4:
+ resolution: {integrity: sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ dev: true
+
+ /string.prototype.trimstart/1.0.4:
+ resolution: {integrity: sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==}
+ dependencies:
+ call-bind: 1.0.2
+ define-properties: 1.1.3
+ dev: true
+
+ /string_decoder/1.1.1:
+ resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
+ dependencies:
+ safe-buffer: 5.1.2
+ dev: true
+
+ /string_decoder/1.3.0:
+ resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /strip-ansi/3.0.1:
+ resolution: {integrity: sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ ansi-regex: 2.1.1
+ dev: true
+
+ /strip-ansi/6.0.1:
+ resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-regex: 5.0.1
+ dev: true
+
+ /strip-ansi/7.0.1:
+ resolution: {integrity: sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==}
+ engines: {node: '>=12'}
+ dependencies:
+ ansi-regex: 6.0.1
+ dev: true
+
+ /strip-bom/4.0.0:
+ resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /strip-eof/1.0.0:
+ resolution: {integrity: sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /strip-final-newline/2.0.0:
+ resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /strip-indent/3.0.0:
+ resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
+ engines: {node: '>=8'}
+ dependencies:
+ min-indent: 1.0.1
+ dev: true
+
+ /strip-json-comments/3.1.1:
+ resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /style-loader/1.3.0_webpack@4.46.0:
+ resolution: {integrity: sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==}
+ engines: {node: '>= 8.9.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ loader-utils: 2.0.2
+ schema-utils: 2.7.1
+ webpack: 4.46.0
+ dev: true
+
+ /style-to-object/0.3.0:
+ resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==}
+ dependencies:
+ inline-style-parser: 0.1.1
+ dev: true
+
+ /style-value-types/5.0.0:
+ resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==}
+ dependencies:
+ hey-listen: 1.0.8
+ tslib: 2.3.1
+ dev: false
+
+ /stylis/4.0.13:
+ resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==}
+
+ /subarg/1.0.0:
+ resolution: {integrity: sha1-9izxdYHplrSPyWVpn1TAauJouNI=}
+ dependencies:
+ minimist: 1.2.5
+ dev: true
+
+ /supports-color/5.5.0:
+ resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
+ engines: {node: '>=4'}
+ dependencies:
+ has-flag: 3.0.0
+ dev: true
+
+ /supports-color/7.2.0:
+ resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
+ engines: {node: '>=8'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-color/8.1.1:
+ resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ has-flag: 4.0.0
+ dev: true
+
+ /supports-color/9.2.1:
+ resolution: {integrity: sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==}
+ engines: {node: '>=12'}
+ dev: true
+
+ /supports-preserve-symlinks-flag/1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+ dev: true
+
+ /svg-parser/2.0.4:
+ resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==}
+ dev: true
+
+ /symbol.prototype.description/1.0.5:
+ resolution: {integrity: sha512-x738iXRYsrAt9WBhRCVG5BtIC3B7CUkFwbHW2zOvGtwM33s7JjrCDyq8V0zgMYVb5ymsL8+qkzzpANH63CPQaQ==}
+ engines: {node: '>= 0.11.15'}
+ dependencies:
+ call-bind: 1.0.2
+ get-symbol-description: 1.0.0
+ has-symbols: 1.0.2
+ object.getownpropertydescriptors: 2.1.3
+ dev: true
+
+ /symlink-or-copy/1.3.1:
+ resolution: {integrity: sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==}
+ dev: true
+
+ /synchronous-promise/2.0.15:
+ resolution: {integrity: sha512-k8uzYIkIVwmT+TcglpdN50pS2y1BDcUnBPK9iJeGu0Pl1lOI8pD6wtzgw91Pjpe+RxtTncw32tLxs/R0yNL2Mg==}
+ dev: true
+
+ /syntax-error/1.4.0:
+ resolution: {integrity: sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==}
+ dependencies:
+ acorn-node: 1.8.2
+ dev: true
+
+ /tapable/1.1.3:
+ resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==}
+ engines: {node: '>=6'}
+ dev: true
+
+ /tar/6.1.11:
+ resolution: {integrity: sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==}
+ engines: {node: '>= 10'}
+ dependencies:
+ chownr: 2.0.0
+ fs-minipass: 2.1.0
+ minipass: 3.1.6
+ minizlib: 2.1.2
+ mkdirp: 1.0.4
+ yallist: 4.0.0
+ dev: true
+
+ /telejson/5.3.3:
+ resolution: {integrity: sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==}
+ dependencies:
+ '@types/is-function': 1.0.1
+ global: 4.4.0
+ is-function: 1.0.2
+ is-regex: 1.1.4
+ is-symbol: 1.0.4
+ isobject: 4.0.0
+ lodash: 4.17.21
+ memoizerific: 1.11.3
+ dev: true
+
+ /terser-webpack-plugin/1.4.5_webpack@4.46.0:
+ resolution: {integrity: sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==}
+ engines: {node: '>= 6.9.0'}
+ peerDependencies:
+ webpack: ^4.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ cacache: 12.0.4
+ find-cache-dir: 2.1.0
+ is-wsl: 1.1.0
+ schema-utils: 1.0.0
+ serialize-javascript: 4.0.0
+ source-map: 0.6.1
+ terser: 4.8.0
+ webpack: 4.46.0
+ webpack-sources: 1.4.3
+ worker-farm: 1.7.0
+ dev: true
+
+ /terser-webpack-plugin/4.2.3_acorn@7.4.1+webpack@4.46.0:
+ resolution: {integrity: sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ cacache: 15.3.0
+ find-cache-dir: 3.3.2
+ jest-worker: 26.6.2
+ p-limit: 3.1.0
+ schema-utils: 3.1.1
+ serialize-javascript: 5.0.1
+ source-map: 0.6.1
+ terser: 5.10.0_acorn@7.4.1
+ webpack: 4.46.0
+ webpack-sources: 1.4.3
+ transitivePeerDependencies:
+ - acorn
+ dev: true
+
+ /terser-webpack-plugin/4.2.3_webpack@4.46.0:
+ resolution: {integrity: sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ cacache: 15.3.0
+ find-cache-dir: 3.3.2
+ jest-worker: 26.6.2
+ p-limit: 3.1.0
+ schema-utils: 3.1.1
+ serialize-javascript: 5.0.1
+ source-map: 0.6.1
+ terser: 5.10.0
+ webpack: 4.46.0
+ webpack-sources: 1.4.3
+ transitivePeerDependencies:
+ - acorn
+ dev: true
+
+ /terser/4.8.0:
+ resolution: {integrity: sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+ dependencies:
+ commander: 2.20.3
+ source-map: 0.6.1
+ source-map-support: 0.5.21
+ dev: true
+
+ /terser/5.10.0:
+ resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==}
+ engines: {node: '>=10'}
+ hasBin: true
+ peerDependencies:
+ acorn: ^8.5.0 || 7
+ peerDependenciesMeta:
+ acorn:
+ optional: true
+ dependencies:
+ commander: 2.20.3
+ source-map: 0.7.3
+ source-map-support: 0.5.21
+ dev: true
+
+ /terser/5.10.0_acorn@7.4.1:
+ resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==}
+ engines: {node: '>=10'}
+ hasBin: true
+ peerDependencies:
+ acorn: ^8.5.0 || 7
+ peerDependenciesMeta:
+ acorn:
+ optional: true
+ dependencies:
+ acorn: 7.4.1
+ commander: 2.20.3
+ source-map: 0.7.3
+ source-map-support: 0.5.21
+ dev: true
+
+ /test-exclude/6.0.0:
+ resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==}
+ engines: {node: '>=8'}
+ dependencies:
+ '@istanbuljs/schema': 0.1.3
+ glob: 7.2.0
+ minimatch: 3.0.5
+ dev: true
+
+ /text-segmentation/1.0.3:
+ resolution: {integrity: sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==}
+ dependencies:
+ utrie: 1.0.2
+ dev: false
+
+ /text-table/0.2.0:
+ resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=}
+ dev: true
+
+ /throttle-debounce/3.0.1:
+ resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /throttleit/1.0.0:
+ resolution: {integrity: sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=}
+ dev: true
+
+ /through/2.3.8:
+ resolution: {integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=}
+ dev: true
+
+ /through2-filter/3.0.0:
+ resolution: {integrity: sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==}
+ dependencies:
+ through2: 2.0.5
+ xtend: 4.0.2
+ dev: true
+
+ /through2/2.0.5:
+ resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==}
+ dependencies:
+ readable-stream: 2.3.7
+ xtend: 4.0.2
+ dev: true
+
+ /through2/4.0.2:
+ resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==}
+ dependencies:
+ readable-stream: 3.6.0
+ dev: true
+
+ /timers-browserify/1.4.2:
+ resolution: {integrity: sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=}
+ engines: {node: '>=0.6.0'}
+ dependencies:
+ process: 0.11.10
+ dev: true
+
+ /timers-browserify/2.0.12:
+ resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==}
+ engines: {node: '>=0.6.0'}
+ dependencies:
+ setimmediate: 1.0.5
+ dev: true
+
+ /tiny-invariant/1.2.0:
+ resolution: {integrity: sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==}
+ dev: false
+
+ /tiny-warning/1.0.3:
+ resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
+ dev: false
+
+ /tmp/0.2.1:
+ resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==}
+ engines: {node: '>=8.17.0'}
+ dependencies:
+ rimraf: 3.0.2
+ dev: true
+
+ /tmpl/1.0.5:
+ resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
+ dev: true
+
+ /to-absolute-glob/2.0.2:
+ resolution: {integrity: sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-absolute: 1.0.0
+ is-negated-glob: 1.0.0
+ dev: true
+
+ /to-arraybuffer/1.0.1:
+ resolution: {integrity: sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=}
+ dev: true
+
+ /to-fast-properties/2.0.0:
+ resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=}
+ engines: {node: '>=4'}
+ dev: true
+
+ /to-object-path/0.3.0:
+ resolution: {integrity: sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ kind-of: 3.2.2
+ dev: true
+
+ /to-regex-range/2.1.1:
+ resolution: {integrity: sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ is-number: 3.0.0
+ repeat-string: 1.6.1
+ dev: true
+
+ /to-regex-range/5.0.1:
+ resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
+ engines: {node: '>=8.0'}
+ dependencies:
+ is-number: 7.0.0
+ dev: true
+
+ /to-regex/3.0.2:
+ resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ define-property: 2.0.2
+ extend-shallow: 3.0.2
+ regex-not: 1.0.2
+ safe-regex: 1.1.0
+ dev: true
+
+ /to-through/2.0.0:
+ resolution: {integrity: sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ through2: 2.0.5
+ dev: true
+
+ /toggle-selection/1.0.6:
+ resolution: {integrity: sha1-bkWxJj8gF/oKzH2J14sVuL932jI=}
+ dev: true
+
+ /toidentifier/1.0.1:
+ resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
+ engines: {node: '>=0.6'}
+ dev: true
+
+ /tough-cookie/2.5.0:
+ resolution: {integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==}
+ engines: {node: '>=0.8'}
+ dependencies:
+ psl: 1.8.0
+ punycode: 2.1.1
+ dev: true
+
+ /tr46/0.0.3:
+ resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=}
+ dev: true
+
+ /trim-trailing-lines/1.1.4:
+ resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==}
+ dev: true
+
+ /trim/0.0.1:
+ resolution: {integrity: sha1-WFhUf2spB1fulczMZm+1AITEYN0=}
+ dev: true
+
+ /trough/1.0.5:
+ resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==}
+ dev: true
+
+ /ts-dedent/2.2.0:
+ resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
+ engines: {node: '>=6.10'}
+ dev: true
+
+ /ts-pnp/1.2.0_typescript@4.5.5:
+ resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==}
+ engines: {node: '>=6'}
+ peerDependencies:
+ typescript: '*'
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ dependencies:
+ typescript: 4.5.5
+ dev: true
+
+ /tslib/1.14.1:
+ resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
+
+ /tslib/2.3.1:
+ resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
+
+ /tsutils/3.21.0_typescript@4.5.5:
+ resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
+ engines: {node: '>= 6'}
+ peerDependencies:
+ typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
+ dependencies:
+ tslib: 1.14.1
+ typescript: 4.5.5
+ dev: true
+
+ /tty-browserify/0.0.0:
+ resolution: {integrity: sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=}
+ dev: true
+
+ /tty-browserify/0.0.1:
+ resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==}
+ dev: true
+
+ /tunnel-agent/0.6.0:
+ resolution: {integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=}
+ dependencies:
+ safe-buffer: 5.2.1
+ dev: true
+
+ /tweetnacl/0.14.5:
+ resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=}
+ dev: true
+
+ /type-check/0.3.2:
+ resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.1.2
+ dev: true
+
+ /type-check/0.4.0:
+ resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
+ engines: {node: '>= 0.8.0'}
+ dependencies:
+ prelude-ls: 1.2.1
+ dev: true
+
+ /type-fest/0.20.2:
+ resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest/0.21.3:
+ resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /type-fest/0.6.0:
+ resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /type-fest/0.8.1:
+ resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /type-is/1.6.18:
+ resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==}
+ engines: {node: '>= 0.6'}
+ dependencies:
+ media-typer: 0.3.0
+ mime-types: 2.1.34
+ dev: true
+
+ /type/1.2.0:
+ resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==}
+ dev: false
+
+ /type/2.6.0:
+ resolution: {integrity: sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ==}
+ dev: false
+
+ /typedarray-to-buffer/3.1.5:
+ resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==}
+ dependencies:
+ is-typedarray: 1.0.0
+ dev: true
+
+ /typedarray/0.0.6:
+ resolution: {integrity: sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=}
+ dev: true
+
+ /typescript-compare/0.0.2:
+ resolution: {integrity: sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==}
+ dependencies:
+ typescript-logic: 0.0.0
+ dev: false
+
+ /typescript-logic/0.0.0:
+ resolution: {integrity: sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q==}
+ dev: false
+
+ /typescript-tuple/2.2.1:
+ resolution: {integrity: sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==}
+ dependencies:
+ typescript-compare: 0.0.2
+ dev: false
+
+ /typescript/4.5.5:
+ resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==}
+ engines: {node: '>=4.2.0'}
+ hasBin: true
+ dev: true
+
+ /uglify-js/3.15.1:
+ resolution: {integrity: sha512-FAGKF12fWdkpvNJZENacOH0e/83eG6JyVQyanIJaBXCN1J11TUQv1T1/z8S+Z0CG0ZPk1nPcreF/c7lrTd0TEQ==}
+ engines: {node: '>=0.8.0'}
+ hasBin: true
+ requiresBuild: true
+ dev: true
+ optional: true
+
+ /umd/3.0.3:
+ resolution: {integrity: sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==}
+ hasBin: true
+ dev: true
+
+ /unbox-primitive/1.0.1:
+ resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==}
+ dependencies:
+ function-bind: 1.1.1
+ has-bigints: 1.0.1
+ has-symbols: 1.0.2
+ which-boxed-primitive: 1.0.2
+ dev: true
+
+ /unc-path-regex/0.1.2:
+ resolution: {integrity: sha1-5z3T17DXxe2G+6xrCufYxqadUPo=}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /undeclared-identifiers/1.1.3:
+ resolution: {integrity: sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==}
+ hasBin: true
+ dependencies:
+ acorn-node: 1.8.2
+ dash-ast: 1.0.0
+ get-assigned-identifiers: 1.2.0
+ simple-concat: 1.0.1
+ xtend: 4.0.2
+ dev: true
+
+ /underscore.string/3.3.6:
+ resolution: {integrity: sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==}
+ dependencies:
+ sprintf-js: 1.1.2
+ util-deprecate: 1.0.2
+ dev: true
+
+ /unfetch/4.2.0:
+ resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==}
+ dev: true
+
+ /unherit/1.1.3:
+ resolution: {integrity: sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==}
+ dependencies:
+ inherits: 2.0.4
+ xtend: 4.0.2
+ dev: true
+
+ /unicode-canonical-property-names-ecmascript/2.0.0:
+ resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unicode-match-property-ecmascript/2.0.0:
+ resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==}
+ engines: {node: '>=4'}
+ dependencies:
+ unicode-canonical-property-names-ecmascript: 2.0.0
+ unicode-property-aliases-ecmascript: 2.0.0
+ dev: true
+
+ /unicode-match-property-value-ecmascript/2.0.0:
+ resolution: {integrity: sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unicode-property-aliases-ecmascript/2.0.0:
+ resolution: {integrity: sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==}
+ engines: {node: '>=4'}
+ dev: true
+
+ /unified/9.2.0:
+ resolution: {integrity: sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==}
+ dependencies:
+ bail: 1.0.5
+ extend: 3.0.2
+ is-buffer: 2.0.5
+ is-plain-obj: 2.1.0
+ trough: 1.0.5
+ vfile: 4.2.1
+ dev: true
+
+ /unified/9.2.2:
+ resolution: {integrity: sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ==}
+ dependencies:
+ bail: 1.0.5
+ extend: 3.0.2
+ is-buffer: 2.0.5
+ is-plain-obj: 2.1.0
+ trough: 1.0.5
+ vfile: 4.2.1
+ dev: true
+
+ /union-value/1.0.1:
+ resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ arr-union: 3.1.0
+ get-value: 2.0.6
+ is-extendable: 0.1.1
+ set-value: 2.0.1
+ dev: true
+
+ /unique-filename/1.1.1:
+ resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==}
+ dependencies:
+ unique-slug: 2.0.2
+ dev: true
+
+ /unique-slug/2.0.2:
+ resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==}
+ dependencies:
+ imurmurhash: 0.1.4
+ dev: true
+
+ /unique-stream/2.3.1:
+ resolution: {integrity: sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==}
+ dependencies:
+ json-stable-stringify-without-jsonify: 1.0.1
+ through2-filter: 3.0.0
+ dev: true
+
+ /unist-builder/2.0.3:
+ resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==}
+ dev: true
+
+ /unist-util-generated/1.1.6:
+ resolution: {integrity: sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==}
+ dev: true
+
+ /unist-util-is/4.1.0:
+ resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==}
+ dev: true
+
+ /unist-util-position/3.1.0:
+ resolution: {integrity: sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==}
+ dev: true
+
+ /unist-util-remove-position/2.0.1:
+ resolution: {integrity: sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==}
+ dependencies:
+ unist-util-visit: 2.0.3
+ dev: true
+
+ /unist-util-remove/2.1.0:
+ resolution: {integrity: sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==}
+ dependencies:
+ unist-util-is: 4.1.0
+ dev: true
+
+ /unist-util-stringify-position/2.0.3:
+ resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==}
+ dependencies:
+ '@types/unist': 2.0.6
+ dev: true
+
+ /unist-util-visit-parents/3.1.1:
+ resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-is: 4.1.0
+ dev: true
+
+ /unist-util-visit/2.0.3:
+ resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-is: 4.1.0
+ unist-util-visit-parents: 3.1.1
+ dev: true
+
+ /universalify/0.1.2:
+ resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
+ engines: {node: '>= 4.0.0'}
+ dev: true
+
+ /universalify/2.0.0:
+ resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==}
+ engines: {node: '>= 10.0.0'}
+ dev: true
+
+ /unpipe/1.0.0:
+ resolution: {integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /unset-value/1.0.0:
+ resolution: {integrity: sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=}
+ engines: {node: '>=0.10.0'}
+ dependencies:
+ has-value: 0.3.1
+ isobject: 3.0.1
+ dev: true
+
+ /untildify/4.0.0:
+ resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==}
+ engines: {node: '>=8'}
+ dev: true
+
+ /upath/1.2.0:
+ resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==}
+ engines: {node: '>=4'}
+ dev: true
+ optional: true
+
+ /uri-js/4.4.1:
+ resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ dependencies:
+ punycode: 2.1.1
+ dev: true
+
+ /urix/0.1.0:
+ resolution: {integrity: sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=}
+ deprecated: Please see https://github.com/lydell/urix#deprecated
+ dev: true
+
+ /url-loader/4.1.1_lit45vopotvaqup7lrvlnvtxwy:
+ resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==}
+ engines: {node: '>= 10.13.0'}
+ peerDependencies:
+ file-loader: '*'
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ file-loader:
+ optional: true
+ webpack:
+ optional: true
+ dependencies:
+ file-loader: 6.2.0_webpack@4.46.0
+ loader-utils: 2.0.2
+ mime-types: 2.1.34
+ schema-utils: 3.1.1
+ webpack: 4.46.0
+ dev: true
+
+ /url/0.11.0:
+ resolution: {integrity: sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=}
+ dependencies:
+ punycode: 1.3.2
+ querystring: 0.2.0
+ dev: true
+
+ /use-composed-ref/1.2.1_react@17.0.2:
+ resolution: {integrity: sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw==}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || 17
+ dependencies:
+ react: 17.0.2
+ dev: true
+
+ /use-isomorphic-layout-effect/1.1.1_udcsdvdzjr5ns727jqoeu7kyda:
+ resolution: {integrity: sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 17.0.39
+ react: 17.0.2
+ dev: true
+
+ /use-latest/1.2.0_udcsdvdzjr5ns727jqoeu7kyda:
+ resolution: {integrity: sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==}
+ peerDependencies:
+ '@types/react': '*'
+ react: ^16.8.0 || ^17.0.0 || 17
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+ dependencies:
+ '@types/react': 17.0.39
+ react: 17.0.2
+ use-isomorphic-layout-effect: 1.1.1_udcsdvdzjr5ns727jqoeu7kyda
+ dev: true
+
+ /use/3.1.1:
+ resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /util-deprecate/1.0.2:
+ resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=}
+ dev: true
+
+ /util.promisify/1.0.0:
+ resolution: {integrity: sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==}
+ dependencies:
+ define-properties: 1.1.3
+ object.getownpropertydescriptors: 2.1.3
+ dev: true
+
+ /util/0.10.3:
+ resolution: {integrity: sha1-evsa/lCAUkZInj23/g7TeTNqwPk=}
+ dependencies:
+ inherits: 2.0.1
+ dev: true
+
+ /util/0.11.1:
+ resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==}
+ dependencies:
+ inherits: 2.0.3
+ dev: true
+
+ /util/0.12.4:
+ resolution: {integrity: sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==}
+ dependencies:
+ inherits: 2.0.4
+ is-arguments: 1.1.1
+ is-generator-function: 1.0.10
+ is-typed-array: 1.1.8
+ safe-buffer: 5.2.1
+ which-typed-array: 1.1.7
+ dev: true
+
+ /utila/0.4.0:
+ resolution: {integrity: sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=}
+ dev: true
+
+ /utils-merge/1.0.1:
+ resolution: {integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=}
+ engines: {node: '>= 0.4.0'}
+ dev: true
+
+ /utrie/1.0.2:
+ resolution: {integrity: sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==}
+ dependencies:
+ base64-arraybuffer: 1.0.2
+ dev: false
+
+ /uuid-browser/3.1.0:
+ resolution: {integrity: sha1-DwWkCu90+eWVHiDvv0SxGHHlZBA=}
+ dev: true
+
+ /uuid/3.4.0:
+ resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==}
+ deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
+ hasBin: true
+ dev: true
+
+ /uuid/8.3.2:
+ resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
+ hasBin: true
+
+ /v8-compile-cache/2.3.0:
+ resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==}
+ dev: true
+
+ /v8-to-istanbul/8.1.1:
+ resolution: {integrity: sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==}
+ engines: {node: '>=10.12.0'}
+ dependencies:
+ '@types/istanbul-lib-coverage': 2.0.4
+ convert-source-map: 1.8.0
+ source-map: 0.7.3
+ dev: true
+
+ /validate-npm-package-license/3.0.4:
+ resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
+ dependencies:
+ spdx-correct: 3.1.1
+ spdx-expression-parse: 3.0.1
+ dev: true
+
+ /value-equal/1.0.1:
+ resolution: {integrity: sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==}
+ dev: false
+
+ /value-or-function/3.0.0:
+ resolution: {integrity: sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=}
+ engines: {node: '>= 0.10'}
+ dev: true
+
+ /vary/1.1.2:
+ resolution: {integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=}
+ engines: {node: '>= 0.8'}
+ dev: true
+
+ /verror/1.10.0:
+ resolution: {integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=}
+ engines: {'0': node >=0.6.0}
+ dependencies:
+ assert-plus: 1.0.0
+ core-util-is: 1.0.2
+ extsprintf: 1.3.0
+ dev: true
+
+ /vfile-location/3.2.0:
+ resolution: {integrity: sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==}
+ dev: true
+
+ /vfile-message/2.0.4:
+ resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==}
+ dependencies:
+ '@types/unist': 2.0.6
+ unist-util-stringify-position: 2.0.3
+ dev: true
+
+ /vfile/4.2.1:
+ resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==}
+ dependencies:
+ '@types/unist': 2.0.6
+ is-buffer: 2.0.5
+ unist-util-stringify-position: 2.0.3
+ vfile-message: 2.0.4
+ dev: true
+
+ /vinyl-fs/3.0.3:
+ resolution: {integrity: sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ fs-mkdirp-stream: 1.0.0
+ glob-stream: 6.1.0
+ graceful-fs: 4.2.9
+ is-valid-glob: 1.0.0
+ lazystream: 1.0.1
+ lead: 1.0.0
+ object.assign: 4.1.2
+ pumpify: 1.5.1
+ readable-stream: 2.3.7
+ remove-bom-buffer: 3.0.0
+ remove-bom-stream: 1.2.0
+ resolve-options: 1.1.0
+ through2: 2.0.5
+ to-through: 2.0.0
+ value-or-function: 3.0.0
+ vinyl: 2.2.1
+ vinyl-sourcemap: 1.1.0
+ dev: true
+
+ /vinyl-sourcemap/1.1.0:
+ resolution: {integrity: sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ append-buffer: 1.0.2
+ convert-source-map: 1.8.0
+ graceful-fs: 4.2.9
+ normalize-path: 2.1.1
+ now-and-later: 2.0.1
+ remove-bom-buffer: 3.0.0
+ vinyl: 2.2.1
+ dev: true
+
+ /vinyl/2.2.1:
+ resolution: {integrity: sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==}
+ engines: {node: '>= 0.10'}
+ dependencies:
+ clone: 2.1.2
+ clone-buffer: 1.0.0
+ clone-stats: 1.0.0
+ cloneable-readable: 1.1.3
+ remove-trailing-separator: 1.1.0
+ replace-ext: 1.0.1
+ dev: true
+
+ /vite-plugin-istanbul/2.7.1:
+ resolution: {integrity: sha512-mIMbXBPFsxlvLrKAbHty7wMNLF3ClKQ6nLssE5eOiy3XXdA3gxpbvIvEIvUtvcWN6phldxk66VMM7oVFfCx/uA==}
+ dependencies:
+ istanbul-lib-instrument: 5.1.0
+ picocolors: 1.0.0
+ test-exclude: 6.0.0
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /vite-plugin-mdx/3.5.10_k4bmpxmaqlgvoeub2z775fx6ma:
+ resolution: {integrity: sha512-tfGNRwkO23pln9EYqhbsOLEx9Qot5+enl+727gop7+HGEoC87+88hLRWGL+FU/It1Y0a5P3OAyDbTKKHX6tEJw==}
+ peerDependencies:
+ '@mdx-js/mdx': '*'
+ vite: '*'
+ dependencies:
+ '@alloc/quick-lru': 5.2.0
+ '@mdx-js/mdx': 1.6.22
+ esbuild: 0.13.8
+ resolve: 1.22.0
+ unified: 9.2.2
+ vite: 2.7.13_sass@1.49.7
+ dev: true
+
+ /vite-plugin-svgr/1.0.1_vite@2.7.13:
+ resolution: {integrity: sha512-7jHIC2Bi83KRwBB/b5FLcQdqWfzOSDVy7BtE9g4GXoY1axTZRKeqyWMEK3LCySQ70+BSYFtoSwHJaNLeqxjYlg==}
+ peerDependencies:
+ vite: ^2.6.0
+ dependencies:
+ '@svgr/core': 6.2.1
+ vite: 2.7.13_sass@1.49.7
+ transitivePeerDependencies:
+ - supports-color
+ dev: true
+
+ /vite/2.7.13_sass@1.49.7:
+ resolution: {integrity: sha512-Mq8et7f3aK0SgSxjDNfOAimZGW9XryfHRa/uV0jseQSilg+KhYDSoNb9h1rknOy6SuMkvNDLKCYAYYUMCE+IgQ==}
+ engines: {node: '>=12.2.0'}
+ hasBin: true
+ peerDependencies:
+ less: '*'
+ sass: '*'
+ stylus: '*'
+ peerDependenciesMeta:
+ less:
+ optional: true
+ sass:
+ optional: true
+ stylus:
+ optional: true
+ dependencies:
+ esbuild: 0.13.15
+ postcss: 8.4.6
+ resolve: 1.22.0
+ rollup: 2.67.1
+ sass: 1.49.7
+ optionalDependencies:
+ fsevents: 2.3.2
+ dev: true
+
+ /vm-browserify/1.1.2:
+ resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==}
+ dev: true
+
+ /void-elements/3.1.0:
+ resolution: {integrity: sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=}
+ engines: {node: '>=0.10.0'}
+ dev: false
+
+ /vue-template-compiler/2.6.14:
+ resolution: {integrity: sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==}
+ dependencies:
+ de-indent: 1.0.2
+ he: 1.2.0
+ dev: true
+
+ /walk-sync/2.2.0:
+ resolution: {integrity: sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==}
+ engines: {node: 8.* || >= 10.*}
+ dependencies:
+ '@types/minimatch': 3.0.5
+ ensure-posix-path: 1.1.1
+ matcher-collection: 2.0.1
+ minimatch: 3.0.5
+ dev: true
+
+ /walker/1.0.8:
+ resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
+ dependencies:
+ makeerror: 1.0.12
+ dev: true
+
+ /warning/4.0.3:
+ resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==}
+ dependencies:
+ loose-envify: 1.4.0
+
+ /watchify/4.0.0:
+ resolution: {integrity: sha512-2Z04dxwoOeNxa11qzWumBTgSAohTC0+ScuY7XMenPnH+W2lhTcpEOJP4g2EIG/SWeLadPk47x++Yh+8BqPM/lA==}
+ engines: {node: '>= 8.10.0'}
+ hasBin: true
+ dependencies:
+ anymatch: 3.1.2
+ browserify: 17.0.0
+ chokidar: 3.5.3
+ defined: 1.0.0
+ outpipe: 1.1.1
+ through2: 4.0.2
+ xtend: 4.0.2
+ dev: true
+
+ /watchpack-chokidar2/2.0.1:
+ resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==}
+ requiresBuild: true
+ dependencies:
+ chokidar: 2.1.8
+ dev: true
+ optional: true
+
+ /watchpack/1.7.5:
+ resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==}
+ dependencies:
+ graceful-fs: 4.2.9
+ neo-async: 2.6.2
+ optionalDependencies:
+ chokidar: 3.5.3
+ watchpack-chokidar2: 2.0.1
+ dev: true
+
+ /watchpack/2.3.1:
+ resolution: {integrity: sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==}
+ engines: {node: '>=10.13.0'}
+ dependencies:
+ glob-to-regexp: 0.4.1
+ graceful-fs: 4.2.9
+ dev: true
+
+ /web-namespaces/1.1.4:
+ resolution: {integrity: sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==}
+ dev: true
+
+ /webidl-conversions/3.0.1:
+ resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=}
+ dev: true
+
+ /webpack-dev-middleware/3.7.3_webpack@4.46.0:
+ resolution: {integrity: sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==}
+ engines: {node: '>= 6'}
+ peerDependencies:
+ webpack: ^4.0.0 || ^5.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ memory-fs: 0.4.1
+ mime: 2.6.0
+ mkdirp: 0.5.5
+ range-parser: 1.2.1
+ webpack: 4.46.0
+ webpack-log: 2.0.0
+ dev: true
+
+ /webpack-filter-warnings-plugin/1.2.1_webpack@4.46.0:
+ resolution: {integrity: sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==}
+ engines: {node: '>= 4.3 < 5.0.0 || >= 5.10'}
+ peerDependencies:
+ webpack: ^2.0.0 || ^3.0.0 || ^4.0.0
+ peerDependenciesMeta:
+ webpack:
+ optional: true
+ dependencies:
+ webpack: 4.46.0
+ dev: true
+
+ /webpack-hot-middleware/2.25.1:
+ resolution: {integrity: sha512-Koh0KyU/RPYwel/khxbsDz9ibDivmUbrRuKSSQvW42KSDdO4w23WI3SkHpSUKHE76LrFnnM/L7JCrpBwu8AXYw==}
+ dependencies:
+ ansi-html-community: 0.0.8
+ html-entities: 2.3.2
+ querystring: 0.2.1
+ strip-ansi: 6.0.1
+ dev: true
+
+ /webpack-log/2.0.0:
+ resolution: {integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==}
+ engines: {node: '>= 6'}
+ dependencies:
+ ansi-colors: 3.2.4
+ uuid: 3.4.0
+ dev: true
+
+ /webpack-sources/1.4.3:
+ resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==}
+ dependencies:
+ source-list-map: 2.0.1
+ source-map: 0.6.1
+ dev: true
+
+ /webpack-virtual-modules/0.2.2:
+ resolution: {integrity: sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==}
+ dependencies:
+ debug: 3.2.7
+ dev: true
+
+ /webpack/4.46.0:
+ resolution: {integrity: sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==}
+ engines: {node: '>=6.11.5'}
+ hasBin: true
+ peerDependencies:
+ webpack-cli: '*'
+ webpack-command: '*'
+ peerDependenciesMeta:
+ webpack-cli:
+ optional: true
+ webpack-command:
+ optional: true
+ dependencies:
+ '@webassemblyjs/ast': 1.9.0
+ '@webassemblyjs/helper-module-context': 1.9.0
+ '@webassemblyjs/wasm-edit': 1.9.0
+ '@webassemblyjs/wasm-parser': 1.9.0
+ acorn: 6.4.2
+ ajv: 6.12.6
+ ajv-keywords: 3.5.2_ajv@6.12.6
+ chrome-trace-event: 1.0.3
+ enhanced-resolve: 4.5.0
+ eslint-scope: 4.0.3
+ json-parse-better-errors: 1.0.2
+ loader-runner: 2.4.0
+ loader-utils: 1.4.0
+ memory-fs: 0.4.1
+ micromatch: 3.1.10
+ mkdirp: 0.5.5
+ neo-async: 2.6.2
+ node-libs-browser: 2.2.1
+ schema-utils: 1.0.0
+ tapable: 1.1.3
+ terser-webpack-plugin: 1.4.5_webpack@4.46.0
+ watchpack: 1.7.5
+ webpack-sources: 1.4.3
+ dev: true
+
+ /whatwg-url/5.0.0:
+ resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=}
+ dependencies:
+ tr46: 0.0.3
+ webidl-conversions: 3.0.1
+ dev: true
+
+ /which-boxed-primitive/1.0.2:
+ resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
+ dependencies:
+ is-bigint: 1.0.4
+ is-boolean-object: 1.1.2
+ is-number-object: 1.0.6
+ is-string: 1.0.7
+ is-symbol: 1.0.4
+ dev: true
+
+ /which-module/2.0.0:
+ resolution: {integrity: sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=}
+ dev: true
+
+ /which-typed-array/1.1.7:
+ resolution: {integrity: sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==}
+ engines: {node: '>= 0.4'}
+ dependencies:
+ available-typed-arrays: 1.0.5
+ call-bind: 1.0.2
+ es-abstract: 1.19.1
+ foreach: 2.0.5
+ has-tostringtag: 1.0.0
+ is-typed-array: 1.1.8
+ dev: true
+
+ /which/1.3.1:
+ resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /which/2.0.2:
+ resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
+ engines: {node: '>= 8'}
+ hasBin: true
+ dependencies:
+ isexe: 2.0.0
+ dev: true
+
+ /wide-align/1.1.5:
+ resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
+ dependencies:
+ string-width: 4.2.3
+ dev: true
+
+ /widest-line/3.1.0:
+ resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==}
+ engines: {node: '>=8'}
+ dependencies:
+ string-width: 4.2.3
+ dev: true
+
+ /word-wrap/1.2.3:
+ resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
+ engines: {node: '>=0.10.0'}
+ dev: true
+
+ /wordwrap/1.0.0:
+ resolution: {integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=}
+ dev: true
+
+ /worker-farm/1.7.0:
+ resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==}
+ dependencies:
+ errno: 0.1.8
+ dev: true
+
+ /worker-rpc/0.1.1:
+ resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==}
+ dependencies:
+ microevent.ts: 0.1.1
+ dev: true
+
+ /wrap-ansi/6.2.0:
+ resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
+ engines: {node: '>=8'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ dev: true
+
+ /wrap-ansi/7.0.0:
+ resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
+ engines: {node: '>=10'}
+ dependencies:
+ ansi-styles: 4.3.0
+ string-width: 4.2.3
+ strip-ansi: 6.0.1
+ dev: true
+
+ /wrappy/1.0.2:
+ resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
+ dev: true
+
+ /write-file-atomic/3.0.3:
+ resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
+ dependencies:
+ imurmurhash: 0.1.4
+ is-typedarray: 1.0.0
+ signal-exit: 3.0.7
+ typedarray-to-buffer: 3.1.5
+ dev: true
+
+ /ws/8.5.0:
+ resolution: {integrity: sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==}
+ engines: {node: '>=10.0.0'}
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ dev: true
+
+ /xtend/4.0.2:
+ resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
+ engines: {node: '>=0.4'}
+ dev: true
+
+ /y18n/4.0.3:
+ resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==}
+ dev: true
+
+ /y18n/5.0.8:
+ resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yallist/3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+ dev: true
+
+ /yallist/4.0.0:
+ resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
+ dev: true
+
+ /yaml/1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+ dev: true
+
+ /yargs-parser/18.1.3:
+ resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==}
+ engines: {node: '>=6'}
+ dependencies:
+ camelcase: 5.3.1
+ decamelize: 1.2.0
+ dev: true
+
+ /yargs-parser/20.2.9:
+ resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /yargs/15.4.1:
+ resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==}
+ engines: {node: '>=8'}
+ dependencies:
+ cliui: 6.0.0
+ decamelize: 1.2.0
+ find-up: 4.1.0
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ require-main-filename: 2.0.0
+ set-blocking: 2.0.0
+ string-width: 4.2.3
+ which-module: 2.0.0
+ y18n: 4.0.3
+ yargs-parser: 18.1.3
+ dev: true
+
+ /yargs/16.2.0:
+ resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==}
+ engines: {node: '>=10'}
+ dependencies:
+ cliui: 7.0.4
+ escalade: 3.1.1
+ get-caller-file: 2.0.5
+ require-directory: 2.1.1
+ string-width: 4.2.3
+ y18n: 5.0.8
+ yargs-parser: 20.2.9
+ dev: true
+
+ /yauzl/2.10.0:
+ resolution: {integrity: sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=}
+ dependencies:
+ buffer-crc32: 0.2.13
+ fd-slicer: 1.1.0
+ dev: true
+
+ /yocto-queue/0.1.0:
+ resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
+ engines: {node: '>=10'}
+ dev: true
+
+ /zwitch/1.0.5:
+ resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==}
+ dev: true
diff --git a/packages/webapp/prod.Dockerfile b/packages/webapp/prod.Dockerfile
index daea50ebd1..661acf2d28 100644
--- a/packages/webapp/prod.Dockerfile
+++ b/packages/webapp/prod.Dockerfile
@@ -1,18 +1,18 @@
-FROM node:14.16.1 as build
+FROM node:16.13.2 as build
WORKDIR /usr/src/app
-COPY ./package*.json /usr/src/app/
+COPY ./package.json ./.npmrc ./pnpm-lock.yaml /usr/src/app/
-RUN npm install
+RUN npm install pnpm -g && pnpm install
COPY ./ /usr/src/app/
-RUN npm run build
+RUN pnpm run build
FROM nginx:1.15
-COPY --from=build /usr/src/app/build /var/www/litefarm
+COPY --from=build /usr/src/app/dist /var/www/litefarm
COPY --from=build /usr/src/app/nginx.conf /etc/nginx/
diff --git a/packages/webapp/public/global.css b/packages/webapp/public/global.css
index 0eceaeab00..4d7a1a8ae7 100644
--- a/packages/webapp/public/global.css
+++ b/packages/webapp/public/global.css
@@ -12,7 +12,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see .
*/
-
+/*TODO: deprecated*/
:root {
--primary: #FFFFFF;
--aux: #E6E6E6;
diff --git a/packages/webapp/public/index.html b/packages/webapp/public/index.html
deleted file mode 100644
index 439c467f69..0000000000
--- a/packages/webapp/public/index.html
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Lite Farm
-
-
- You need to enable JavaScript to run this app.
-
-
-
-
-
diff --git a/packages/webapp/public/locales/en/common.json b/packages/webapp/public/locales/en/common.json
index 0f773a921e..3532888518 100644
--- a/packages/webapp/public/locales/en/common.json
+++ b/packages/webapp/public/locales/en/common.json
@@ -14,6 +14,7 @@
"DELETE": "Delete",
"DO_NOT_SHOW": "Don’t show this message again.",
"EDIT": "Edit",
+ "EDIT_DATE": "Edit date",
"EXPORT": "Export",
"FINISH": "Finish",
"FROM": "from",
@@ -28,10 +29,12 @@
"MAX_ERROR": "Please enter a value less than {{value}}",
"MIN_ERROR": "Please enter a value greater than {{value}}",
"NAME": "Name",
+ "NEEDS_PLAN": "Needs plan",
"NEXT": "Next",
"NO": "No",
"NOT_SURE": "Not sure",
"NOTES": "Notes",
+ "OK": "OK",
"OPTIONAL": "(optional)",
"OTHER": "Other",
"PAST": "Past",
@@ -44,11 +47,13 @@
"SAVE_CHANGES": "Save Changes",
"SEARCH": "Search",
"SELECT": "Select",
+ "CREATE": "Create",
+ "SKIP": "Skip",
"SORRY": "Sorry",
"SUBMIT": "Submit",
"SUBMITTING": "Submitting...",
"UPDATE": "Update",
"WORD_LIMIT_ERROR": "Only {{value}} characters can be displayed",
- "YES": "Yes",
- "EDIT_DATE": "Edit date"
+ "YEAR": "Year",
+ "YES": "Yes"
}
diff --git a/packages/webapp/public/locales/en/disease.json b/packages/webapp/public/locales/en/disease.json
index 86260838c4..c1c2d83cf2 100644
--- a/packages/webapp/public/locales/en/disease.json
+++ b/packages/webapp/public/locales/en/disease.json
@@ -287,7 +287,6 @@
"EUROPEAN_CORN_BORER": "European Corn Borer",
"CORN_EARWORM": "Corn Earworm",
"JASSIDS_ON_PEANUT": "Jassids on Peanut",
- "MEALYBUG": "Mealybug",
"COTTONY_CUSHION_SCALE": "Cottony Cushion Scale",
"MANGO_FRUIT_FLY": "Mango Fruit Fly",
"FLEA_BEETLE": "Flea Beetle",
diff --git a/packages/webapp/public/locales/en/filter.json b/packages/webapp/public/locales/en/filter.json
index 7fa19d8907..11839a3bd0 100644
--- a/packages/webapp/public/locales/en/filter.json
+++ b/packages/webapp/public/locales/en/filter.json
@@ -18,6 +18,24 @@
"SOIL_AMENDMENT": "Soil amendment",
"SOIL_SAMPLE_RESULTS": "Soil sample results",
"WATER_SAMPLE_RESULTS": "Water sample results",
- "UNCATEGORIZED": "Uncategorized"
+ "UNCATEGORIZED": "Uncategorized",
+ "RECEIPTS": "Receipts",
+ "INVOICES": "Invoices"
+ },
+ "TASKS": {
+ "LOCATION": "Location",
+ "STATUS": "Status",
+ "SUPPLIERS": "Suppliers",
+ "ACTIVE": "Active",
+ "ABANDONED": "Abandoned",
+ "COMPLETED": "Completed",
+ "LATE": "Late",
+ "PLANNED": "Planned",
+ "FOR_REVIEW": "For Review"
+ },
+ "FILTER": {
+ "VALID_ON": "Valid on",
+ "FROM_DATE": "From",
+ "TO_DATE": "To"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/en/message.json b/packages/webapp/public/locales/en/message.json
index fb0615e066..a5764bec3e 100644
--- a/packages/webapp/public/locales/en/message.json
+++ b/packages/webapp/public/locales/en/message.json
@@ -7,15 +7,25 @@
"ERROR": {
"CREATE": "Failed to create document",
"FAILED_ARCHIVE": "Failed to archive document",
+ "FAILED_UNARCHIVE": "Failed to unarchive document",
"FAILED_UPLOAD": "Failed to upload attachments",
"UPDATE": "Failed to update document"
},
"SUCCESS": {
"ARCHIVE": "Successfully archived document",
"CREATE": "Successfully created document",
+ "UNARCHIVE": "Successfully unarchived document",
"UPDATE": "Successfully updated document"
}
},
+ "CROP": {
+ "ERROR": {
+ "DELETE": "Failed To Delete Field Crop"
+ },
+ "SUCCESS": {
+ "DELETE": "Successfully Deleted Crop"
+ }
+ },
"CROP_VARIETY": {
"ERROR": {
"ADD": "Error: failed to add varietal to database",
@@ -29,14 +39,6 @@
"UPDATE": "Successfully updated crop variety"
}
},
- "CROP": {
- "ERROR": {
- "DELETE": "Failed To Delete Field Crop"
- },
- "SUCCESS": {
- "DELETE": "Successfully Deleted Crop"
- }
- },
"EXPENSE": {
"ERROR": {
"ADD": "Failed to add new expenses",
@@ -76,22 +78,22 @@
},
"MANAGEMENT_PLAN": {
"ERROR": {
- "ABANDON": "Failed to abandon management plan!",
- "COMPLETE": "Failed to complete management plan!",
- "POST": "Failed to add management plan!"
+ "ABANDON": "Failed to abandon crop plan!",
+ "COMPLETE": "Failed to complete crop plan!",
+ "POST": "Failed to add crop plan!"
},
"SUCCESS": {
- "ABANDON": "Successfully abandoned management plan!",
- "COMPLETE": "Successfully completed management plan!",
- "POST": "Successfully added management plan!"
+ "ABANDON": "Successfully abandoned crop plan!",
+ "COMPLETE": "Successfully completed crop plan!",
+ "POST": "Successfully added crop plan!"
}
},
"MAP": {
"FAIL_PATCH": "Failed to update",
"FAIL_POST": "Failed to add new",
- "SUCCESS_DELETE": " successfully retired",
- "SUCCESS_PATCH": " successfully updated",
- "SUCCESS_POST": " successfully saved"
+ "SUCCESS_DELETE": "Successfully retired",
+ "SUCCESS_PATCH": "Successfully updated",
+ "SUCCESS_POST": "Successfully saved"
},
"ORGANIC_CERTIFIER_SURVEY": {
"ERROR": {
@@ -101,10 +103,10 @@
},
"PLAN": {
"ERROR": {
- "EDIT": "Failed to update management plan"
+ "EDIT": "Failed to update crop plan"
},
"SUCCESS": {
- "EDIT": "Management plan successfully updated"
+ "EDIT": "crop plan successfully updated"
}
},
"REVENUE": {
@@ -144,16 +146,6 @@
"UPDATE": "Successfully updated shift!"
}
},
- "TASK_TYPE": {
- "CREATE": {
- "FAILED": "Failed to create custom task",
- "SUCCESS": "Successfully created custom task"
- },
- "DELETE": {
- "FAILED": "Failed to delete custom task",
- "SUCCESS": "Successfully deleted custom task"
- }
- },
"TASK": {
"ABANDON": {
"FAILED": "Failed to abandon task",
@@ -168,6 +160,16 @@
"SUCCESS": "Successfully created task"
}
},
+ "TASK_TYPE": {
+ "CREATE": {
+ "FAILED": "Failed to create custom task",
+ "SUCCESS": "Successfully created custom task"
+ },
+ "DELETE": {
+ "FAILED": "Failed to delete custom task",
+ "SUCCESS": "Successfully deleted custom task"
+ }
+ },
"USER": {
"ERROR": {
"ADD": "Failed to add user",
diff --git a/packages/webapp/public/locales/en/translation.json b/packages/webapp/public/locales/en/translation.json
index a44d69737f..aaab9c6609 100644
--- a/packages/webapp/public/locales/en/translation.json
+++ b/packages/webapp/public/locales/en/translation.json
@@ -8,7 +8,8 @@
"FARM_LOCATION": "Farm location",
"FARM_LOCATION_INPUT_INFO": "Street address or comma separated latitude and longitude (e.g. 49.250945, -123.238492)",
"FARM_NAME": "Farm name",
- "INVALID_FARM_LOCATION": "Invalid farm location",
+ "FARM_NAME_ERROR": "Farm name character limit exceeded",
+ "INVALID_FARM_LOCATION": "No country for this location",
"LOCATING": "Locating...",
"NO_ADDRESS": "No location found! Try latitude and longitude",
"TELL_US_ABOUT_YOUR_FARM": "Tell us about your farm"
@@ -25,6 +26,7 @@
"ADD_CUSTOM_TASK": "Add custom task",
"AFFECT_PLANS": "Will this task affect any plans?",
"ASSIGN_ALL_TO_PERSON": "Assign all unassigned tasks on this date to this person",
+ "ASSIGN_DATE": "Change task date",
"ASSIGN_TASK": "Assign task",
"ASSIGNEE": "Assignee",
"CANCEL": "task creation",
@@ -45,7 +47,6 @@
"EDIT_CUSTOM_TASK": "Edit custom task",
"FIELD_WORK_VIEW": {
"OTHER_TYPE_OF_FIELD_WORK": "Describe the type of field work",
- "TYPE_OF_FIELD_WORK": "Type of field work",
"TYPE": {
"COVERING_SOIL": "Covering soil",
"FENCING": "Fencing",
@@ -56,7 +57,8 @@
"TERMINATION": "Termination",
"TILLAGE": "Tillage",
"WEEDING": "Weeding"
- }
+ },
+ "TYPE_OF_FIELD_WORK": "Type of field work"
},
"GO_TO_CATALOGUE": "Go to Crop Catalogue",
"HARVEST_EVERYTHING": "Harvest everything that is ready",
@@ -64,8 +66,8 @@
"HOW_MUCH_IS_HARVESTED": "How much is being harvested?",
"HR": "/hr",
"MANAGE_CUSTOM_TASKS": "Manage custom tasks",
- "NEED_MANAGEMENT_PLAN": "You’ll need an active or planned crop management plan before you can schedule a harvest task or transplant task. Go to the crop catalogue to create a plan now.",
- "NO_MANAGEMENT_PLAN": "No eligible crop management plans",
+ "NEED_MANAGEMENT_PLAN": "You'll need an active or planned crop plan before you can schedule a harvest task or transplant task. Go to the crop catalogue to create a plan now.",
+ "NO_MANAGEMENT_PLAN": "No eligible crop plans",
"PEST_CONTROL_VIEW": {
"BIOLOGICAL_CONTROL": "Biological control",
"FLAME_WEEDING": "Flame weeding",
@@ -84,7 +86,7 @@
"PLANTING_METHOD": "Planting method",
"PLANTING_STOCK": "Planting stock",
"PLANTING_TASK": "Planting Task",
- "PLANTING_TASK_MODAL": "Starting a new planting task creates a new management plan. Go to the crop catalogue to select the crop you would like to plant.",
+ "PLANTING_TASK_MODAL": "Starting a new planting task creates a new crop plan. Go to the crop catalogue to select the crop you would like to plant.",
"QUANTITY": "Quantity",
"RETIRE_CUSTOM_TASK": "Retire custom task?",
"RETIRE_CUSTOM_TASK_CONTENT": "Are you sure you want to delete this custom task?",
@@ -182,19 +184,10 @@
"YOUR_CERTIFICATION": "Your certification"
}
},
- "CERTIFICATIONS_MODAL": {
- "MAYBE_LATER": "Maybe later",
- "STEP_ONE": {
- "DESCRIPTION": "We've added support for certifications and certifiers! Want to see what’s available in your area?",
- "TITLE": "New feature!"
- },
- "STEP_TWO": {
- "DESCRIPTION": "That’s okay! You can add certifications and certifiers later under “my farm”.",
- "TITLE": "Viewing certifications"
- }
- },
"CERTIFICATIONS": {
"COULD_NOT_CONTACT_CERTIFIER": "It looks like LiteFarm doesn’t currently export in the format of your certifier. You can still export your documents but your certifier may require additional information. We’ll send them to you at:",
+ "EMAIL": "Email",
+ "EMAIL_ERROR": "Valid email required",
"EXPORT": "Export",
"EXPORT_DOCS": "Export certification docs",
"EXPORT_DOWNLOADING_MESSAGE": "Downloading your organic certification files ...",
@@ -208,10 +201,19 @@
"ORGANIC_CERTIFICATION_FROM": "Organic certification from",
"SELECT_REPORTING_PERIOD": "Select your reporting period",
"UH_OH": "Uh oh!",
- "WOULD_LIKE_ANSWERS": "Your certifier would like you to answer a few additional questions before we can export your documents.",
- "EMAIL": "Email",
- "EMAIL_ERROR": "Valid email required",
- "WHERE_TO_SEND_DOCS": "Where do you want your documents sent?"
+ "WHERE_TO_SEND_DOCS": "Where do you want your documents sent?",
+ "WOULD_LIKE_ANSWERS": "Your certifier would like you to answer a few additional questions before we can export your documents."
+ },
+ "CERTIFICATIONS_MODAL": {
+ "MAYBE_LATER": "Maybe later",
+ "STEP_ONE": {
+ "DESCRIPTION": "We've added support for certifications and certifiers! Want to see what’s available in your area?",
+ "TITLE": "New feature!"
+ },
+ "STEP_TWO": {
+ "DESCRIPTION": "That’s okay! You can add certifications and certifiers later under “my farm”.",
+ "TITLE": "Viewing certifications"
+ }
},
"CHOOSE_FARM": {
"ADD_NEW": "Add new farm",
@@ -242,16 +244,40 @@
"PASSWORD": "Password",
"TITLE": "Create new user account"
},
+ "CROP": {
+ "ADD_COMPLIANCE_FILE": "Link to a compliance file",
+ "ADD_CROP": "Add a crop",
+ "ADD_IMAGE": "Add Custom Image",
+ "ANNUAL": "Annual",
+ "ANNUAL_OR_PERENNIAL": "Is the crop an annual or perennial?",
+ "EDIT_CROP": "Edit crop",
+ "EDIT_MODAL": {
+ "BODY": "Editing this crop will not modify any existing crop plans. Only crop plans created after your edits will be impacted. Proceed to edit?",
+ "TITLE": "Edit crop?"
+ },
+ "IS_GENETICALLY_ENGINEERED": "Is the crop genetically engineered?",
+ "IS_ORGANIC": "Is the seed or crop certified organic?",
+ "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Your certifier may ask for documentation supporting your claim this crop isn't genetically engineered.",
+ "NEED_DOCUMENT_PERFORM_SEARCH": "Your certifier may ask for documentation supporting your search.",
+ "NEED_DOCUMENT_TREATED": "Your certifier may ask for documentation describing any treatments.",
+ "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrients in edible portion (per 100g)",
+ "PERENNIAL": "Perennial",
+ "PERFORM_SEARCH": "Did you perform a commercial availability search?",
+ "PHYSIOLOGY_AND_ANATOMY": "Physiology and Anatomy",
+ "TREATED": "Have the seeds for this crop been treated?",
+ "UPLOAD_LATER": "You can upload files at a later time as well"
+ },
"CROP_CATALOGUE": {
"ADD_CROP": "Add a new crop",
"ADD_CROPS_T0_YOUR_FARM": "Add crops to your farm",
"ADD_TO_YOUR_FARM": "Add to your farm",
"CAN_NOT_FIND": "Can't find what you're looking for?",
"COVER_CROP": "Can this be grown as a cover crop?",
- "CREATE_MANAGEMENT_PLANS": "Create management plans",
+ "CREATE_MANAGEMENT_PLANS": "Create crop plans",
"CROP_CATALOGUE": "Crop catalogue",
"CROP_GROUP": "Crop group",
"CROP_GROUP_TOOL_TIP": "Selecting a crop group allows LiteFarm to pre-populate a lot of information about this crop such as growing season, nutritional values, and estimated annual yield. Don't worry, you can change these values below once you've selected a crop group.",
+ "CROP_STATUS": "Crop status on:",
"DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Document necessary info for organic production",
"FILTER": {
"LOCATION": "Location",
@@ -259,14 +285,13 @@
"SUPPLIERS": "Suppliers",
"TITLE": "Crop Catalogue Filter"
},
+ "FILTER_TITLE": "Crop Catalogue Filter",
"HERE_YOU_CAN": "Here you can:",
"LETS_BEGIN": "Let's begin",
"NEW_CROP_NAME": "New Crop Name",
"NO_RESULTS_FOUND": "No results found. Please change your filters.",
"ON_YOUR_FARM": "On your farm",
- "SELECT_A_CROP": "Select a crop to add it to your farm. Use search and filters to find crops more quickly.",
- "CROP_STATUS": "Crop status on:",
- "FILTER_TITLE": "Crop Catalogue Filter"
+ "SELECT_A_CROP": "Select a crop to add it to your farm. Use search and filters to find crops more quickly."
},
"CROP_DETAIL": {
"ADD_PLAN": "Add a plan",
@@ -277,12 +302,12 @@
"EDIT_CROP_DETAIL": "Edit crop details",
"GENETICALLY_ENGINEERED": "Is this crop genetically engineered?",
"HS_CODE": "HS Code",
- "MANAGEMENT_PLANS": "Management Plans",
+ "MANAGEMENT_PLANS": "Crop Plans",
"MANAGEMENT_TAB": "Management",
"ORGANIC": "Is the seed or crop certified organic?",
+ "ORGANIC_COMPLIANCE": "Organic Compliance",
"PERENNIAL": "Perennial",
- "TREATED": "Have the seeds for this crop been treated?",
- "ORGANIC_COMPLIANCE": "Organic Compliance"
+ "TREATED": "Have the seeds for this crop been treated?"
},
"CROP_MANAGEMENT": {
"GERMINATE": "Germinate",
@@ -297,48 +322,27 @@
"CROP_VARIETIES": "variety",
"NEEDS_PLAN": "Needs Plan",
"RETIRE": {
- "CONFIRMATION": "Retiring this crop will remove it and all its management plans from your crop catalogue. Do you want to proceed?",
+ "CONFIRMATION": "Retiring this crop will remove it and all its crop plans from your crop catalogue. Do you want to proceed?",
"RETIRE_CROP_TITLE": "Retire crop?",
- "UNABLE_TO_RETIRE": "You can only retire crops that have no active or future management plans. You'll need to complete or abandon those plans to retire this crop",
+ "UNABLE_TO_RETIRE": "You can only retire crops that have no active or future crop plans. You'll need to complete or abandon those plans to retire this crop",
"UNABLE_TO_RETIRE_TITLE": "Unable to retire"
},
"SUPPLIER": "Supplier"
},
- "CROP": {
- "ADD_CROP": "Add a crop",
- "ADD_IMAGE": "Add Custom Image",
- "ANNUAL": "Annual",
- "ANNUAL_OR_PERENNIAL": "Is the crop an annual or perennial?",
- "EDIT_CROP": "Edit crop",
- "EDIT_MODAL": {
- "BODY": "Editing this crop will not modify any existing crop management plans. Only management plans created after your edits will be impacted. Proceed to edit?",
- "TITLE": "Edit crop?"
- },
- "IS_GENETICALLY_ENGINEERED": "Is the crop genetically engineered?",
- "IS_ORGANIC": "Is the seed or crop certified organic?",
- "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Your certifier may ask for documentation supporting your claim this crop isn't genetically engineered.",
- "NEED_DOCUMENT_PERFORM_SEARCH": "Your certifier may ask for documentation supporting your search.",
- "NEED_DOCUMENT_TREATED": "Your certifier may ask for documentation describing any treatments.",
- "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrients in edible portion (per 100g)",
- "PERENNIAL": "Perennial",
- "PERFORM_SEARCH": "Did you perform a commercial availability search?",
- "PHYSIOLOGY_AND_ANATOMY": "Physiology and Anatomy",
- "TREATED": "Have the seeds for this crop been treated?",
- "ADD_COMPLIANCE_FILE": "Link to a compliance file",
- "UPLOAD_LATER": "You can upload files at a later time as well"
+ "DATE_RANGE": {
+ "HELP_BODY": "Select the date range to create a financial report for your farm for a given time window.",
+ "HELP_TITLE": "Date Range Help",
+ "TITLE": "Filter Report by Date",
+ "INVALID_RANGE_MESSAGE": "End date must be after start date to return results"
},
"DATE_RANGE_PICKER": {
"FROM": "From",
"TO": "To",
- "TO_MUST_BE_AFTER_FROM": "'To' date must come after the 'From' date"
- },
- "DATE_RANGE": {
- "HELP_BODY": "Select the date range to create a financial report for your farm for a given time window.",
- "HELP_TITLE": "Date Range Help",
- "TITLE": "Filter Report by Date"
+ "TO_MUST_BE_AFTER_FROM": "'To' date must come after the 'From' date",
+ "REVENUE_HELP_TITLE": "Date Range Help",
+ "REVENUE_HELP_BODY": "Only plans that have a planned or completed harvest task within the indicated date range will be shown."
},
"DOCUMENTS": {
- "ADD_DOCUMENT": "Add a new document",
"ADD": {
"ADD_MORE_PAGES": "Add more pages",
"DOCUMENT_NAME": "Document name",
@@ -347,6 +351,7 @@
"TYPE": "Type",
"VALID_UNTIL": "Valid until"
},
+ "ADD_DOCUMENT": "Add a new document",
"ARCHIVE": "Archive",
"ARCHIVE_DOCUMENT": "Archive document?",
"ARCHIVE_DOCUMENT_TEXT": "Archiving this document will move it to the archived section of your documents, but not delete it. Archived documents will not be exported for your certifications. Do you want to proceed?",
@@ -372,12 +377,18 @@
"CLEANING_PRODUCT": "Cleaning product",
"CROP_COMPLIANCE": "Crop compliance",
"FERTILIZING_PRODUCT": "Fertilizing product",
+ "INVOICES": "Invoices",
"OTHER": "Other",
"PEST_CONTROL_PRODUCT": "Pest control product",
+ "RECEIPTS": "Receipts",
"SOIL_AMENDMENT": "Soil amendment",
"SOIL_SAMPLE_RESULTS": "Soil sample results",
"WATER_SAMPLE_RESULTS": "Water sample results"
},
+ "UNARCHIVE": "Unarchive",
+ "UNARCHIVE_DOCUMENT": "Unarchive document?",
+ "UNARCHIVE_DOCUMENT_TEXT": "Unarchiving this document will return it to your list of currently valid documents. Valid documents will be exported for your certifications. Do you want to proceed?",
+ "UNARCHIVED": "Unarchived",
"VALID": "Valid"
},
"ENTER_PASSWORD": {
@@ -391,6 +402,7 @@
},
"EXPENSE": {
"ADD_EXPENSE": {
+ "ALL_FIELDS_REQUIRED": "All fields are required",
"MIN_ERROR": "Please enter a value greater than ",
"REQUIRED_ERROR": "Expense is required",
"TITLE_1": "New Expense (1 of 2)",
@@ -417,6 +429,7 @@
"RESET_PASSWORD_LINK": "Send new password link."
},
"FARM_MAP": {
+ "TUTORIALS": "Map Tutorials",
"AREA_DETAILS": {
"NETWORK": "Network connectivity issues.",
"PERIMETER": "Perimeter",
@@ -454,7 +467,8 @@
"DOWNLOAD": "Download",
"EMAIL_TO_ME": "Email to me",
"EMAILING": "Emailing",
- "TITLE": "Export your farm map"
+ "TITLE": "Export your farm map",
+ "LOADING": "Loading..."
},
"FARM_SITE_BOUNDARY": {
"EDIT_TITLE": "Edit farm site boundary",
@@ -567,7 +581,8 @@
},
"TAB": {
"CROPS": "Crops",
- "DETAILS": "Details"
+ "DETAILS": "Details",
+ "TASKS": "Tasks"
},
"TITLE": "Farm map",
"TUTORIAL": {
@@ -638,7 +653,7 @@
"DATE": "Date",
"ESTIMATED_REVENUE": {
"ESTIMATED_ANNUAL_REVENUE": "Estimated annual revenue",
- "ESTIMATED_ANNUAL_YIELD": "Estimated annual yield",
+ "ESTIMATED_ANNUAL_YIELD": "Estimated annual harvest",
"ESTIMATED_PRICE_PER_UNIT": "Estimated price per unit",
"TITLE": "Estimated Revenue"
},
@@ -672,11 +687,24 @@
"AMPHIBIANS": "Amphibians",
"BIRDS": "Birds",
"CROP_VARIETIES": "Crop varieties",
+ "ERROR": {
+ "BODY": "LiteFarm generates biodiversity insights based on several sources and was unable to do so at this time. Please try again after {{minutes}} minutes.",
+ "PREVIEW": "Unavailable",
+ "TITLE": "There was a problem"
+ },
"HEADER": "Number of species",
"INFO": "Biodiversity is great for people and the planet. We count species richness from all known records of biodiversity within your farm boundary(ies). You can increase the crop biodiversity on your farm by planting new varieties. You can increase the non-crop biodiversity count on your farm by recording sightings on https://inaturalist.org/app",
"INSECTS": "Insects",
+ "LOADING": {
+ "BODY": "We're generating the latest biodiversity insights for your farm. This can take up to 60 seconds.",
+ "PREVIEW": "Loading...",
+ "TITLE": "Generating the latest biodiversity insights..."
+ },
+ "MAMMALS": "Mammals",
"PLANTS": "Plants",
"SPECIES_COUNT": "{{count}} species",
+ "SPECIES_COUNT_one": "{{count}} species",
+ "SPECIES_COUNT_other": "{{count}} species",
"SPECIES_COUNT_plural": "{{count}} species",
"TITLE": "Biodiversity"
},
@@ -692,6 +720,8 @@
"CHOOSE_A_FREQUENCY": "Choose a frequency",
"CHOOSE_FREQUENCY": "Choose Frequency...",
"COUNT_MONTHS": "{{count}} month",
+ "COUNT_MONTHS_one": "{{count}} month",
+ "COUNT_MONTHS_other": "{{count}} months",
"COUNT_MONTHS_plural": "{{count}} months",
"CYCLE_INDICATOR": "Your Nitrogen Balance is on a {{frequency}} months cycle and data will show on: {{refreshDate}}",
"FIRST_TIME": "It looks like it's your first time running this! Please select a frequency to calculate your nitrogen balance.",
@@ -708,6 +738,8 @@
"HEADER": "Number of Meals",
"INFO": "We estimate the number of potential meals provided by your farm based on sales data, and crop composition databases. We assume that daily requirements are divided equally across three meals a day.",
"MEAL_COUNT": "{{count}} meal",
+ "MEAL_COUNT_one": "{{count}} meal",
+ "MEAL_COUNT_other": "{{count}} meals",
"MEAL_COUNT_plural": "{{count}} meals",
"MEALS": "meals",
"PROTEIN": "Protein",
@@ -718,6 +750,8 @@
"PRICES": {
"INFO": "We show you the trajectory of your sales prices against the sales prices for the same goods within a given distance of you, collected across the LiteFarm network.",
"NEARBY_FARMS": "Network price is based on {{count}} farms in your local area",
+ "NEARBY_FARMS_one": "Network price is based on {{count}} farm in your local area",
+ "NEARBY_FARMS_other": "Network price is based on {{count}} farms in your local area",
"NEARBY_FARMS_plural": "Network price is based on {{count}} farms in your local area",
"NETWORK_PRICE": "Network Price",
"NO_ADDRESS": "You currently do not have an address in LiteFarm. Please update it in your Profile to get nearby prices information!",
@@ -774,6 +808,8 @@
"BIRTH_YEAR_ERROR": "Birth year needs to be between 1900 and",
"BIRTH_YEAR_TOOLTIP": "Age information is collected for research purposes only and will only be shared with personally identifying information removed",
"CHOOSE_ROLE": "Choose Role",
+ "DEFAULT_LANGUAGE": "English",
+ "DEFAULT_LANGUAGE_VALUE": "en",
"EMAIL": "Email",
"EMAIL_INFO": "Users without an email won't be able to log in",
"FULL_NAME": "Full name",
@@ -781,6 +817,7 @@
"GENDER_TOOLTIP": "Gender information is collected for research purposes only and will only be shared with personally identifying information removed",
"INVALID_EMAIL_ERROR": "Please enter a valid email",
"INVITE": "Invite",
+ "LANGUAGE_OF_INVITE": "Language of invitation",
"PHONE": "Phone",
"PHONE_ERROR": "Please enter a valid phone number",
"ROLE": "Role",
@@ -839,15 +876,15 @@
"DISEASE": "Disease",
"HARVEST": "Harvest",
"HARVEST_ALLOCATION_SUBTITLE": "About how much of the harvest will be used for each purpose?",
+ "HARVEST_ALLOCATION_SUBTITLE_TWO": "Amount to allocate",
+ "HARVEST_QUANTITY": "Harvest Quantity",
+ "HARVEST_USE": "Harvest Use",
"HARVEST_USE_TYPE_SUBTITLE": "How will the harvest be used?",
"OTHER": "Other",
"PEST": "Pest",
"QUANTITY_ERROR": "Quantity must be up to 2 decimal places",
"TITLE": "Harvest Log",
- "WEED": "Weed",
- "HARVEST_QUANTITY": "Harvest Quantity",
- "HARVEST_USE": "Harvest Use",
- "HARVEST_ALLOCATION_SUBTITLE_TWO": "Amount to allocate"
+ "WEED": "Weed"
},
"LOG_IRRIGATION": {
"DRIP": "Drip",
@@ -856,27 +893,30 @@
"SUBSURFACE": "Subsurface"
},
"MANAGEMENT_DETAIL": {
- "ABANDON_PLAN": "Abandon this management plan",
+ "ABANDON_PLAN": "Abandon this crop plan",
"ADD_A_TASK": "Add a task",
"DETAILS": "Details",
"FAILED_CROP": "Failed crop?",
"TASKS": "Tasks"
},
"MANAGEMENT_PLAN": {
- "ABANDON_MANAGEMENT_PLAN_CONTENT": "Abandoning this management plan will abandon all the incomplete tasks associated with it and remove it from your farm map.",
- "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandon mangement plan?",
- "ADD_MANAGEMENT_PLAN": "Add a management plan",
+ "ABANDON_MANAGEMENT_PLAN_CONTENT": "Abandoning this crop plan will abandon all the incomplete tasks associated with it and remove it from your farm map.",
+ "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandon crop plan?",
+ "ADD_MANAGEMENT_PLAN": "Add a crop plan",
"AGE": "Age",
"AS_COVER_CROP": "As cover crop",
"BEDS": "Beds",
"BROADCAST": "Broadcast or drill",
"COMPLETE_PLAN": {
+ "ABANDON_DATE": "Abandonment date",
+ "ABANDON_NOTES": "Abandonment notes",
"ABANDON_PLAN": "Abandon plan",
"ABANDON_REASON": "Reason for abandoning",
+ "COMPLETE_DATE": "Completed date",
"COMPLETE_PLAN": "Complete plan",
"DATE_OF_CHANGE": "Date of status change",
"NOTES_CHAR_LIMIT": "Notes must be less than 10,000 characters",
- "RATING": "Rate this management plan",
+ "RATING": "Rate this crop plan",
"REASON": {
"CROP_FAILURE": "Crop failure",
"LABOUR_ISSUE": "Labour issue",
@@ -888,6 +928,7 @@
},
"WHAT_HAPPENED": "What happened?"
},
+ "COMPLETION_NOTES": "Completion notes",
"CONTAINER": "Container",
"CONTAINER_OR_IN_GROUND": "Are you planting in a container or in ground?",
"CONTAINER_TYPE": "Type of container",
@@ -904,11 +945,11 @@
"DURATION_TOOLTIP": "These are suggested values. Please adjust for your local conditions.",
"EDITING_PLAN_WILL_NOT_MODIFY": "Editing this plan will not modify tasks assigned to it.",
"ESTIMATED_SEED": "Estimated seed required",
- "ESTIMATED_YIELD": "Estimated annual yield",
+ "ESTIMATED_YIELD": "Estimated annual harvest",
"FIRST_MP_SPOTLIGHT": {
"BODY_PART1": "LiteFarm has generated a few tasks based on your plan. You can add more tasks or assign them on this screen.",
"BODY_PART2": "Your plan will become active once you complete a task.",
- "TITLE": "Congrats! You’ve made your first management plan!"
+ "TITLE": "Congrats! You've made your first crop plan!"
},
"FOR_HARVEST": "For harvest",
"GERMINATION": "Germination",
@@ -916,13 +957,13 @@
"HARVEST_DATE": "When do you expect your next harvest?",
"HISTORICAL_CONTAINER_OR_IN_GROUND": "Was it planted in a container or in the ground?",
"IN_GROUND": "In ground",
- "INCOMPLETE_TASK_CONTENT": "This plan has tasks that aren’t completed yet. You’ll need to mark the tasks complete in order to complete this crop management plan.",
+ "INCOMPLETE_TASK_CONTENT": "This plan has tasks that aren’t completed yet. You’ll need to mark the tasks complete in order to complete this crop plan.",
"INCOMPLETE_TASK_TITLE": "You have incomplete tasks",
"INDIVIDUAL_CONTAINER": "Individual or container",
"IS_TRANSPLANT": "Will this crop be transplanted?",
"KNOW_HOW_IS_CROP_PLANTED": "Do you know how the crop was planted?",
"LOCATION_SUBTEXT": "Only locations that can grow crops are shown.",
- "MANAGEMENT_PLAN_FLOW": "management plan creation",
+ "MANAGEMENT_PLAN_FLOW": "crop plan creation",
"MANAGEMENT_SPOTLIGHT_1": "Create new plans for this crop",
"MANAGEMENT_SPOTLIGHT_2": "View and modify plans for this crop",
"MANAGEMENT_SPOTLIGHT_3": "Create and assign tasks",
@@ -932,7 +973,7 @@
"NUMBER_OF_CONTAINER": "# of containers",
"PENDING_TASK": "Pending tasks",
"PLAN_AND_ID": "Plan {{id}}",
- "PLAN_NAME": "Management plan name",
+ "PLAN_NAME": "Crop plan name",
"PLAN_NOTES": "Plan notes",
"PLANT_SPACING": "Plant spacing",
"PLANTED_ALREADY": "Will you be planting this crop or is it already in the ground?",
@@ -946,6 +987,7 @@
"PLANTING_NOTE": "Planting notes",
"PLANTING_SOIL": "Planting soil to be used",
"PLANTS_PER_CONTAINER": "# of plants/container",
+ "RATE_THIS_MANAGEMENT_PLAN": "Plan rating",
"REMOVE_PIN": "Remove pin",
"ROW_METHOD": {
"HISTORICAL_SAME_LENGTH": "Were the rows all the same length?",
@@ -967,12 +1009,19 @@
"SELECTED_STARTING_LOCATION": "Always select this as the starting location for crops that will be transplanted",
"SPOTLIGHT_HERE_YOU_CAN": "Here you can:",
"STARTED": "Let's get started",
+ "STATUS": {
+ "ABANDONED": "Abandoned",
+ "ACTIVE": "Active",
+ "COMPLETED": "Completed",
+ "PLANNED": "Planned"
+ },
"SUPPLIER": "Supplier",
"TERMINATION": "Termination",
"TERMINATION_DATE": "When will you terminate this crop?",
"TOTAL_PLANTS": "# of plants",
"TRANSPLANT": "Transplant",
"TRANSPLANT_DATE": "What is your transplant date?",
+ "TRANSPLANT_LOCATION": "Where will you transplant to?",
"TRANSPLANT_SPOTLIGHT": {
"BODY": {
"PLANTED": "planted",
@@ -988,17 +1037,10 @@
"VARIETY": "Variety",
"WHAT_IS_AGE": "What is the approximate age of the crop?",
"WHAT_WAS_PLANTING_METHOD": "What was the planting method?",
+ "WHAT_WAS_PLANTING_METHOD_INFO": "Selecting the right planting method will help LiteFarm more accurately estimate the quantity of seed needed, yield, and other helpful insights.",
"WHERE_START_LOCATION": "Where is your starting location?",
"WHERE_TRANSPLANT_LOCATION": "Where will you transplant to?",
- "WILD_CROP": "Are you harvesting a wild crop?",
- "STATUS": {
- "ABANDONED": "Abandoned",
- "ACTIVE": "Active",
- "COMPLETED": "Completed",
- "PLANNED": "Planned"
- },
- "WHAT_WAS_PLANTING_METHOD_INFO": "Selecting the right planting method will help LiteFarm more accurately estimate the quantity of seed needed, yield, and other helpful insights.",
- "TRANSPLANT_LOCATION": "Where will you transplant to?"
+ "WILD_CROP": "Are you harvesting a wild crop?"
},
"MY_FARM": {
"CERTIFICATIONS": "Certifications",
@@ -1008,35 +1050,77 @@
},
"NAVIGATION": {
"SPOTLIGHT": {
+ "COORDINATE_ACTIVITIES": "Coordinate farm activities",
+ "EDIT_FARM_SETTING": "Edit your farm settings",
"FARM": "Here you can:, • Edit your farm settings, • Map your farm, • Manage your employees",
"FARM_TITLE": "This is your farm profile",
- "NOTIFICATION": "Here you can:, • Manage your tasks, • See what else is going on, • Coordinate farm activities",
- "NOTIFICATION_TITLE": "This is your farm tasks",
+ "INFO": "Your info",
+ "LOG_OUT": "The log out button",
+ "MANAGE_EMPLOYEE": "Manage your employees",
+ "MANAGE_TASK": "Manage your tasks",
+ "MAP_FARM": "Map your farm",
+ "SEE_UPDATES": "See important updates",
+ "NOTIFICATION": "Here you can:, • See important updates, • Manage your tasks, • Coordinate farm activities",
+ "NOTIFICATION_TITLE": "This is your notification centre",
"PROFILE": "Here you will find:, • Your info, • Helpful tips, • The log out button",
- "PROFILE_TITLE": "This is your profile"
+ "PROFILE_TITLE": "This is your profile",
+ "SEE_TASK": "See what else is going on",
+ "TASK_TITLE": "This is your farm tasks",
+ "TIPS": "Helpful tips",
+ "YOU_CAN": "Here you can:",
+ "YOU_WILL_FIND": "Here you will find:"
}
},
"NOTIFICATION": {
- "NOTIFICATION_TEASER": "Coming Soon!"
+ "DAILY_TASKS_DUE_TODAY": {
+ "BODY": "You have tasks due today.",
+ "TITLE": "Tasks due today"
+ },
+ "NONE_TO_DISPLAY": "There are no notifications to display.",
+ "NOTIFICATION_TEASER": "Coming Soon!",
+ "PAGE_TITLE": "Notifications",
+ "TAKE_ME_THERE": "Take me there",
+ "TASK_ABANDONED": {
+ "BODY": "A {{taskType}} task assigned to you has been abandoned by {{abandoner}}.",
+ "TITLE": "Task abandoned"
+ },
+ "TASK_ASSIGNED": {
+ "BODY": "A {{taskType}} task has been assigned to {{assignee}}.",
+ "TITLE": "Assigned task"
+ },
+ "TASK_COMPLETED_BY_OTHER_USER": {
+ "BODY": "A {{taskType}} task assigned to you has been marked completed by {{assigner}}.",
+ "TITLE": "Task completed"
+ },
+ "TASK_REASSIGNED": {
+ "BODY": "A {{taskType}} task previously assigned to you has been assigned to someone else by {{assigner}}.",
+ "TITLE": "Task re-assigned"
+ },
+ "WEEKLY_UNASSIGNED_TASKS": {
+ "BODY": "You have unassigned tasks due this week.",
+ "TITLE": "Unassigned tasks"
+ }
},
"OUTRO": {
"ALL_DONE": "Great! You're all done. Ready to get your hands dirty?",
"IMPORTANT_THINGS": "And finally, let us show you a couple of important things!"
},
- "PASSWORD_RESET_SUCCESS_MODAL": {
- "BUTTON": "Great!",
- "DESCRIPTION": "Your password has been updated. Redirecting you to your farms in 10 seconds...",
- "TITLE": "Success!"
- },
"PASSWORD_RESET": {
"BUTTON": "Resend Link",
"BUTTON_SENDING": "Sending...",
"DESCRIPTION_BOTTOM": "Please check your email.",
"DESCRIPTION_TOP": "A link has been sent.",
+ "LABEL_EMAIL": "Email",
+ "LABEL_NEW_PASSWORD": "New Password",
"NEW_ACCOUNT_BUTTON": "Update",
"NEW_ACCOUNT_TITLE": "Set your new password",
"TITLE": "Link Sent"
},
+ "PASSWORD_RESET_SUCCESS_MODAL": {
+ "BUTTON": "Great!",
+ "DESCRIPTION": "Your password has been updated. Redirecting you to your farms in 10 seconds...",
+ "TITLE": "Success!"
+ },
"PLAN_GUIDANCE": {
"ADDITIONAL_GUIDANCE": "Is there additional guidance you want to provide for this seeding task?",
"BED": "Bed",
@@ -1048,7 +1132,7 @@
"SPACE_BETWEEN": "Space between {{types}}",
"SPECIFY": "Specify {{types}}",
"SPECIFY_PLACEHOLDER": "Ex. {{types}} 1 - 4",
- "TOOLTIP": "The first 40 characters of this field will display anywhere your management plan is visible.",
+ "TOOLTIP": "The first 40 characters of this field will display anywhere your crop plan is visible.",
"WIDTH": "{{type}} width",
"WORD_LIMIT": "Only {{limit}} characters can be displayed"
},
@@ -1056,15 +1140,7 @@
"MESSAGE": "LiteFarm is putting together your certification documents in the background and you’ll receive an email when we’re done - it could take a few minutes... You can click outside this box to continue using LiteFarm without interrupting the process.",
"TITLE": "Your export is being prepared"
},
- "PROFILE_FLOATER": {
- "HELP": "Help",
- "INFO": "My info",
- "LOG_OUT": "Log Out",
- "SWITCH": "Switch Farm",
- "TUTORIALS": "Tutorials"
- },
"PROFILE": {
- "ACCOUNT_TAB": "Account",
"ACCOUNT": {
"CONVERT_TO_HAVE_ACCOUNT": "Convert this worker to a user with account",
"EDIT_USER": "Edit user",
@@ -1080,7 +1156,7 @@
"SPANISH": "Spanish",
"USER_ADDRESS": "User Address"
},
- "FARM_TAB": "Farm",
+ "ACCOUNT_TAB": "Account",
"FARM": {
"ADDRESS": "Address",
"CURRENCY": "Currency",
@@ -1090,7 +1166,7 @@
"PHONE_NUMBER": "Phone Number",
"UNITS": "Units"
},
- "PEOPLE_TAB": "People",
+ "FARM_TAB": "Farm",
"PEOPLE": {
"DO_YOU_WANT_TO_REMOVE": "Do you want to remove this user from your farm?",
"EO": "Extension Officer",
@@ -1108,6 +1184,7 @@
"THIS_WILL_REMOVE": "This action will remove the user from your farm.",
"USERS_FOUND": "Users found"
},
+ "PEOPLE_TAB": "People",
"TABLE": {
"HEADER_EMAIL": "Email",
"HEADER_NAME": "Name",
@@ -1115,6 +1192,13 @@
"HEADER_STATUS": "Status"
}
},
+ "PROFILE_FLOATER": {
+ "HELP": "Help",
+ "INFO": "My info",
+ "LOG_OUT": "Log Out",
+ "SWITCH": "Switch Farm",
+ "TUTORIALS": "Tutorials"
+ },
"REACT_SELECT": {
"CLEAR": "Clear",
"CLEAR_ALL": "Clear all"
@@ -1278,12 +1362,14 @@
"EMAIL_INVALID": "Email is invalid",
"ENTER_EMAIL": "Enter your email address",
"EXPIRED_ERROR": "We've updated our infrastructure and you'll need to reset your password. Check your inbox to proceed.",
+ "EXPIRED_INVITATION_LINK_ERROR": "Invalid or expired invitation",
"GOOGLE_BUTTON": "CONTINUE WITH GOOGLE",
"INVITED_ERROR": "We've updated our infrastructure and you'll need to check your inbox for a farm invitation to proceed.",
"LITEFARM_UPDATED": "We've updated LiteFarm!",
"PASSWORD_ERROR": "Password incorrect",
"SIGN_IN": "Sign In",
"SSO_ERROR": "Please login by clicking the Google button above",
+ "USED_INVITATION_LINK_ERROR": "This invitation has already been used, please log in to access this farm",
"WELCOME_BACK": "Welcome back",
"WRONG_BROWSER": "LiteFarm is not optimized for this browser.",
"WRONG_BROWSER_BOTTOM": "Please login using Chrome."
@@ -1322,14 +1408,12 @@
"ROWS_TEXT": "rows"
},
"TASK": {
- "ABANDON_TASK": "Abandon this task",
- "ABANDON_TASK_DURATION": "Was any work completed for this task?",
"ABANDON": {
"ABANDON": "Abandon",
+ "DATE": "Abandonment date",
"INFO": "Abandoning this task will change its' status to abandoned and remove it from all users ‘To do’ and ‘Unassigned’ lists.",
"NOTES": "Task abandonment notes",
"NOTES_CHAR_LIMIT": "Notes must be less than 10,000 characters",
- "REASON_FOR_ABANDONMENT": "Reason for abandoning",
"REASON": {
"CROP_FAILURE": "Crop failure",
"LABOUR_ISSUE": "Labour issue",
@@ -1339,9 +1423,13 @@
"SCHEDULING_ISSUE": "Scheduling issue",
"WEATHER": "Weather"
},
+ "REASON_FOR_ABANDONMENT": "Reason for abandoning",
"TITLE": "Abandon task",
- "WHAT_HAPPENED": "What happened?"
+ "WHAT_HAPPENED": "What happened?",
+ "WHEN": "When was the task abandoned?"
},
+ "ABANDON_TASK": "Abandon this task",
+ "ABANDON_TASK_DURATION": "Was any work completed for this task?",
"ABANDONMENT_DETAILS": "Task abandonment details",
"ADD_CUSTOM_HARVEST_USE": "Create a custom harvest use",
"ADD_HARVEST_USE": "Add another harvest use",
@@ -1353,6 +1441,10 @@
"MULTIPLE_CROPS": "Multiple crops",
"MULTIPLE_LOCATIONS": "Multiple locations"
},
+ "COMPLETE": {
+ "DATE": "Completion date",
+ "WHEN": "When was the task completed?"
+ },
"COMPLETE_HARVEST_QUANTITY": "How much was harvested?",
"COMPLETE_TASK": "Complete task",
"COMPLETE_TASK_CHANGES": "Did you have to make any changes to this task?",
@@ -1368,6 +1460,23 @@
"DID_YOU_ENJOY": "Did you enjoy this task?",
"DUE_DATE": "Due date",
"DURATION": "Duration",
+ "FILTER": {
+ "ASCENDING": "oldest first",
+ "ASSIGNEE": "Assignee",
+ "CROP": "Crop",
+ "DATE_RANGE": "Filter by date range",
+ "DESCENDING": "newest first",
+ "FROM": "From",
+ "LOCATION": "Location",
+ "MY_TASK": "My tasks",
+ "SORT_BY": "Sort by",
+ "STATUS": "Status",
+ "TITLE": "Task Filter",
+ "TO": "To",
+ "TYPE": "Type",
+ "UNASSIGNED": "Unassigned",
+ "VIEW": "View"
+ },
"HARVEST_USE": "Harvest use",
"HARVEST_USE_ALREADY_EXISTS": "Harvest use already exists",
"HOW_WILL_HARVEST_BE_USED": "How will the harvest be used?",
@@ -1383,20 +1492,22 @@
"SELECT_DATE": "Select the task date",
"SELECT_TASK_LOCATIONS": "Select the task location(s)",
"SELECT_WILD_CROP": "This task targets a wild crop",
- "TASK": "task",
- "TASKS_COUNT": "{{count}} task",
- "TASKS_COUNT_plural": "{{count}} tasks",
- "TODO": "To do",
- "TRANSPLANT": "Transplant",
- "TRANSPLANT_LOCATIONS": "Select a transplant location",
- "UNASSIGNED": "Unassigned",
"STATUS": {
"ABANDONED": "Abandoned",
"COMPLETED": "Completed",
"FOR_REVIEW": "For Review",
"LATE": "Late",
"PLANNED": "Planned"
- }
+ },
+ "TASK": "task",
+ "TASKS_COUNT": "{{count}} task",
+ "TASKS_COUNT_one": "{{count}} task",
+ "TASKS_COUNT_other": "{{count}} tasks",
+ "TASKS_COUNT_plural": "{{count}} tasks",
+ "TODO": "To do",
+ "TRANSPLANT": "Transplant",
+ "TRANSPLANT_LOCATIONS": "Select a transplant location",
+ "UNASSIGNED": "Unassigned"
},
"UNIT": {
"TIME": {
@@ -1417,4 +1528,4 @@
"YEAR_SELECTOR": {
"TITLE": "Select Year"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/es/common.json b/packages/webapp/public/locales/es/common.json
index 2a4fb588dd..cf4daff623 100644
--- a/packages/webapp/public/locales/es/common.json
+++ b/packages/webapp/public/locales/es/common.json
@@ -14,6 +14,7 @@
"DELETE": "Borrar",
"DO_NOT_SHOW": "No vuelva a mostrar este mensaje.",
"EDIT": "Editar",
+ "EDIT_DATE": "Editar fecha",
"EXPORT": "Exportar",
"FINISH": "Terminar",
"FROM": "de",
@@ -28,10 +29,12 @@
"MAX_ERROR": "Por favor, ingrese un valor menor que {{value}}",
"MIN_ERROR": "Por favor, ingrese un valor mayor que {{value}}",
"NAME": "Nombre",
+ "NEEDS_PLAN": "Necesita un plan",
"NEXT": "Próximo",
"NO": "No",
"NOT_SURE": "No estoy seguro/a",
"NOTES": "Notas",
+ "OK": "Está bien",
"OPTIONAL": "(opcional)",
"OTHER": "Otro",
"PAST": "Pasado",
@@ -44,11 +47,13 @@
"SAVE_CHANGES": "Guardar cambios",
"SEARCH": "Buscar",
"SELECT": "Seleccionar",
+ "CREATE": "Agregar",
+ "SKIP": "Omitir",
"SORRY": "Disculpa",
"SUBMIT": "Enviar",
"SUBMITTING": "Submitting...",
"UPDATE": "Actualizar",
"WORD_LIMIT_ERROR": "Solo se pueden mostrar {{value}} caracteres",
- "YES": "Sí",
- "EDIT_DATE": "Editar fecha"
+ "YEAR": "Año",
+ "YES": "Sí"
}
diff --git a/packages/webapp/public/locales/es/crop.json b/packages/webapp/public/locales/es/crop.json
index 99097a7f58..01d7ce0977 100644
--- a/packages/webapp/public/locales/es/crop.json
+++ b/packages/webapp/public/locales/es/crop.json
@@ -7,7 +7,7 @@
"APPLE": "Manzana",
"APRICOT": "Damasco",
"ARECA_BETEL_NUT": "Nuez de Areca",
- "ARRACHA": "La zanahoria blanca",
+ "ARRACHA": "Zanahoria (blanca)",
"ARROWROOT": "Arrurruz",
"ARTICHOKE": "Alcachofas",
"ASPARAGUS": "Esparrago",
@@ -139,7 +139,7 @@
"GUINEA_CORN_SORGHUM": "Maíz de Guinea",
"HAZELNUT_FILBERT": "Avellana",
"HEMPSEED": "Cáñamo",
- "HEMP_": " Cáñamo ",
+ "HEMP_": "Cáñamo ",
"HEMP_FIBRE": "Fibra de cáñamo",
"HEMP_MANILA_ABACA": "Cáñamo, de Manila (abaca)",
"HEMP_SUN": "Cáñamo, del sol",
@@ -179,11 +179,11 @@
"MACE": "Maza",
"MAGUEY": "Maguey",
"MAIZE_CORN": "Maíz",
- "MAIZE_CORN_FOR_SILAGE": " Maíz para ensilaje",
- "MAIZE_GRAIN": " Maíz (grano)",
- "MAIZE_HYBRID": " Maíz (híbrido)",
- "MAIZE_ORDINARY": " Maíz, ordinario",
- "MAIZE_SWEET_CORN": " Maíz (Maíz dulce)",
+ "MAIZE_CORN_FOR_SILAGE": "Maíz para ensilaje",
+ "MAIZE_GRAIN": "Maíz (grano)",
+ "MAIZE_HYBRID": "Maíz (híbrido)",
+ "MAIZE_ORDINARY": "Maíz, ordinario",
+ "MAIZE_SWEET_CORN": "Maíz (Maíz dulce)",
"MANDARIN": "Mandarina",
"MANGEL_FODDER_BEET": "Remolacha (forrajera de mangel)",
"MANGO": "Mango",
@@ -269,7 +269,7 @@
"RED_BEET": "Remolacha roja",
"RHEA": "Ñandú",
"RHUBARB": "Ruibarbo",
- "RICE": " Arroz ",
+ "RICE": "Arroz ",
"RICE_AFRICAN": "Arroz africano",
"ROSE": "Rosa",
"RUBBER": "Caucho",
@@ -301,7 +301,7 @@
"SUGARCANE": "Caña de azúcar",
"SUGARCANE_FOR_FODDER": "Caña de azúcar para forraje",
"SUGARCANE_FOR_SUGAR_OR_ALCOHOL": "Caña de azúcar para azúcar o alcohol",
- "SUGARCANE_FOR_THATCHING": " Caña de azúcar para construcción con paja",
+ "SUGARCANE_FOR_THATCHING": "Caña de azúcar para construcción con paja",
"SUGAR_BEET": "Azúcar de remolacha",
"SUGAR_BEET_FOR_FODDER": "Azúcar de remolacha para forraje",
"SUGAR_BEET_FOR_SEED": "Azúcar de remolacha para semilla",
@@ -351,7 +351,7 @@
"APPLE_BANANA": "Manzana banana",
"APPLE_MALAY_MALAY_APPLE": "Pomarrosa",
"ARAZA_FRUIT": "Arazá",
- "ARRACACHA": "La zanahoria blanca",
+ "ARRACACHA": "Zanahoria (blanca)",
"ARUGULA": "Rúcula",
"BAMBOO_COMMON": "Bambú, comun",
"BANANA_PASSIONFRUIT": "Tumbo",
diff --git a/packages/webapp/public/locales/es/filter.json b/packages/webapp/public/locales/es/filter.json
index fe58daaf0f..469f001be7 100644
--- a/packages/webapp/public/locales/es/filter.json
+++ b/packages/webapp/public/locales/es/filter.json
@@ -18,6 +18,24 @@
"SOIL_AMENDMENT": "Aditivo de suelo",
"SOIL_SAMPLE_RESULTS": "Resultados de muestras del suelo",
"WATER_SAMPLE_RESULTS": "Resultados de la muestra de agua",
- "UNCATEGORIZED": "Sin categorizar"
+ "UNCATEGORIZED": "Sin categorizar",
+ "RECEIPTS": "Recibos",
+ "INVOICES": "Facturas"
+ },
+ "TASKS": {
+ "LOCATION": "Ubicación",
+ "ABANDONED": "Abandonada",
+ "COMPLETED": "Completada",
+ "FOR_REVIEW": "Para la revisión",
+ "LATE": "Tarde",
+ "PLANNED": "Planificada",
+ "STATUS": "Estatus",
+ "SUPPLIERS": "Proveedores",
+ "ACTIVE": "Activo"
+ },
+ "FILTER": {
+ "VALID_ON": "Válido en",
+ "FROM_DATE": "Desde",
+ "TO_DATE": "Hasta"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/es/message.json b/packages/webapp/public/locales/es/message.json
index 50e45beb95..01aae5ab0a 100644
--- a/packages/webapp/public/locales/es/message.json
+++ b/packages/webapp/public/locales/es/message.json
@@ -7,15 +7,25 @@
"ERROR": {
"CREATE": "No se pudo crear el documento",
"FAILED_ARCHIVE": "No se pudo archivar el documento",
+ "FAILED_UNARCHIVE": "No se pudo desarchivar el documento",
"FAILED_UPLOAD": "No se pudo subir los archivos adjuntos",
"UPDATE": "No se pudo actualizar el documento"
},
"SUCCESS": {
"ARCHIVE": "Documento archivado exitosamente",
"CREATE": "Documento creado exitosamente",
+ "UNARCHIVE": "Documento desarchivado con éxito",
"UPDATE": "Documento actualizado exitosamente"
}
},
+ "CROP": {
+ "ERROR": {
+ "DELETE": "No se pudo borrar campo de cultivo"
+ },
+ "SUCCESS": {
+ "DELETE": "Cultivo borrado exitosamente"
+ }
+ },
"CROP_VARIETY": {
"ERROR": {
"ADD": "Error: no se pudo agregar variedad a la base de datos",
@@ -29,14 +39,6 @@
"UPDATE": "Cultivo actualizado exitosamente"
}
},
- "CROP": {
- "ERROR": {
- "DELETE": "No se pudo borrar campo de cultivo"
- },
- "SUCCESS": {
- "DELETE": "Cultivo borrado exitosamente"
- }
- },
"EXPENSE": {
"ERROR": {
"ADD": "No se pudo agregar nuevos gastos",
@@ -89,9 +91,9 @@
"MAP": {
"FAIL_PATCH": "Fallo al actualizar",
"FAIL_POST": "Fallo al crear",
- "SUCCESS_DELETE": " se retiro exitosamente.",
- "SUCCESS_PATCH": " se actualizo exitosamente.",
- "SUCCESS_POST": " se creo exitosamente."
+ "SUCCESS_DELETE": " retirada/o con éxito",
+ "SUCCESS_PATCH": " actualizo/a con éxito.",
+ "SUCCESS_POST": " creo/a con éxito."
},
"ORGANIC_CERTIFIER_SURVEY": {
"ERROR": {
@@ -144,16 +146,6 @@
"UPDATE": "Turno agregado exitosamente!"
}
},
- "TASK_TYPE": {
- "CREATE": {
- "FAILED": "No se pudo crear la tarea personalizada",
- "SUCCESS": "Tarea personalizada creada con éxito"
- },
- "DELETE": {
- "FAILED": "No se pudo borrar la tarea personalizada",
- "SUCCESS": "Tarea personalizada borrada con éxito"
- }
- },
"TASK": {
"ABANDON": {
"FAILED": "No se pudo abandonar la tarea",
@@ -168,6 +160,16 @@
"SUCCESS": "Tarea creada con éxito"
}
},
+ "TASK_TYPE": {
+ "CREATE": {
+ "FAILED": "No se pudo crear la tarea personalizada",
+ "SUCCESS": "Tarea personalizada creada con éxito"
+ },
+ "DELETE": {
+ "FAILED": "No se pudo borrar la tarea personalizada",
+ "SUCCESS": "Tarea personalizada borrada con éxito"
+ }
+ },
"USER": {
"ERROR": {
"ADD": "No se pudo agregar usuario",
@@ -185,7 +187,7 @@
"ADD": "Usuario(a) de la finca agregado exitosamente!",
"RESTORE": "Acceso de usuario(a) restaurado exitosamente",
"REVOKE": "Acceso de usuario(a) revocado!",
- "UPDATE": "Información del(a) usuario(a) actualizado exitosamente!"
+ "UPDATE": "Información del(a) usuario(a) actualizada exitosamente!"
}
}
}
diff --git a/packages/webapp/public/locales/es/translation.json b/packages/webapp/public/locales/es/translation.json
index d1f095b326..8e6363f943 100644
--- a/packages/webapp/public/locales/es/translation.json
+++ b/packages/webapp/public/locales/es/translation.json
@@ -8,7 +8,8 @@
"FARM_LOCATION": "Ubicación de la finca",
"FARM_LOCATION_INPUT_INFO": "Dirección de la calle o usa latitud y longitud separadas con una coma (p. ej 49.250945, -123.238492)",
"FARM_NAME": "Nombre de la finca",
- "INVALID_FARM_LOCATION": "Ubicación de la finca inválida",
+ "FARM_NAME_ERROR": "Límite de caracteres del nombre de la granja excedido",
+ "INVALID_FARM_LOCATION": "Ningún país para esta ubicación",
"LOCATING": "Localizando...",
"NO_ADDRESS": "Ubicación no encontrada! Trate latitud y longitud",
"TELL_US_ABOUT_YOUR_FARM": "Cuéntenos sobre su finca"
@@ -25,6 +26,7 @@
"ADD_CUSTOM_TASK": "Agregar tarea personalizada",
"AFFECT_PLANS": "¿Esta tarea afectará algún plan?",
"ASSIGN_ALL_TO_PERSON": "Asignar todas las tareas no asignadas en esta fecha a esta persona",
+ "ASSIGN_DATE": "Asignar fecha de vencimiento",
"ASSIGN_TASK": "Asignar tarea",
"ASSIGNEE": "Responsable",
"CANCEL": "creación de la tarea",
@@ -45,7 +47,6 @@
"EDIT_CUSTOM_TASK": "Editar la tarea personalizada",
"FIELD_WORK_VIEW": {
"OTHER_TYPE_OF_FIELD_WORK": "Describe el tipo de trabajo de campo",
- "TYPE_OF_FIELD_WORK": "Tipo de trabajo de campo",
"TYPE": {
"COVERING_SOIL": "Cubriendo el suelo",
"FENCING": "Cercar",
@@ -56,7 +57,8 @@
"TERMINATION": "Terminar",
"TILLAGE": "Labrar",
"WEEDING": "Desyerbar"
- }
+ },
+ "TYPE_OF_FIELD_WORK": "Tipo de trabajo de campo"
},
"GO_TO_CATALOGUE": "Ir al catálogo de cultivos",
"HARVEST_EVERYTHING": "Cosecha todo lo que esté listo",
@@ -160,7 +162,7 @@
},
"INPUT_PLACEHOLDER": "Tipo de busqueda",
"INTERESTED_IN_CERTIFICATION": {
- "PARAGRAPH": "Planea conseguir o renovar certificación orgánica esta temporada?",
+ "PARAGRAPH": "Planea conseguir o renovar su certificación orgánica durante esta temporada?",
"TITLE": "Está interesado(a) en certificaciones?",
"WHY_ANSWER": "LiteFarm genera formularios requiridos para certificación orgánica. Parte de la información será obligatoria."
},
@@ -176,25 +178,16 @@
"BAD_NEWS": "LiteFarm no recopila actualmente la información que necesita para generar sus documentos de certificación - Lo sentimos!",
"BAD_NEWS_INFO": "Sin embargo, podemos crear formularios genéricos que sean útiles para la mayoría de los certificadores. Indicaremos esta información en toda la aplicación con un icono de hoja.",
"CERTIFICATION": "certificacion",
- "GOOD_NEWS": "Buenas noticias! Litefarm puede recolectar la informacion que necesita para generar sus documentos de certificacion!",
- "INFORMATION": "Indicaremos esta informacion a traves de la aplicacion con el icono de la hoja.",
+ "GOOD_NEWS": "Buenas noticias! Litefarm puede recolectar la información que necesita para generar sus documentos de certificacion!",
+ "INFORMATION": "Indicaremos esta información a traves de la aplicacion con el icono de la hoja.",
"TITLE": "Está interesado(a) en aplicar para:",
"YOUR_CERTIFICATION": "Su certificación"
}
},
- "CERTIFICATIONS_MODAL": {
- "MAYBE_LATER": "Quizas mas tarde",
- "STEP_ONE": {
- "DESCRIPTION": "¡Hemos agregado soporte para certificaciones y certificadores! ¿Quiere ver qué hay disponible en su área?",
- "TITLE": "¡Nueva caracteristica!"
- },
- "STEP_TWO": {
- "DESCRIPTION": "¡Esta bien! Puede agregar certificaciones y certificadores más adelante en “mi granja”.",
- "TITLE": "Ver certificaciones"
- }
- },
"CERTIFICATIONS": {
"COULD_NOT_CONTACT_CERTIFIER": "Parece que LiteFarm no exporta actualmente en el formato de su certificador. Aún puede exportar sus documentos, pero su certificador puede requerir información adicional. Se los enviaremos a:",
+ "EMAIL": "Correo electrónico",
+ "EMAIL_ERROR": "Se requiere un correo válido",
"EXPORT": "Exportar",
"EXPORT_DOCS": "Exportar documentos de certificación",
"EXPORT_DOWNLOADING_MESSAGE": "Descargando sus archivos de certificación orgánica...",
@@ -208,14 +201,23 @@
"ORGANIC_CERTIFICATION_FROM": "Certificación orgánica de",
"SELECT_REPORTING_PERIOD": "Seleccione su período de informe",
"UH_OH": "¡Oh, no!",
- "WOULD_LIKE_ANSWERS": "Su certificador desea que responda algunas preguntas adicionales antes de que podamos exportar sus documentos.",
- "EMAIL": "Correo electrónico",
- "EMAIL_ERROR": "Se requiere un correo válido",
- "WHERE_TO_SEND_DOCS": "¿Dónde quiere que se envíen sus documentos?"
+ "WHERE_TO_SEND_DOCS": "¿Dónde quiere que se envíen sus documentos?",
+ "WOULD_LIKE_ANSWERS": "Su certificador desea que responda algunas preguntas adicionales antes de que podamos exportar sus documentos."
+ },
+ "CERTIFICATIONS_MODAL": {
+ "MAYBE_LATER": "Quizas mas tarde",
+ "STEP_ONE": {
+ "DESCRIPTION": "¡Hemos agregado soporte para certificaciones y certificadores! ¿Quiere ver qué hay disponible en su área?",
+ "TITLE": "¡Nueva caracteristica!"
+ },
+ "STEP_TWO": {
+ "DESCRIPTION": "¡Esta bien! Puede agregar certificaciones y certificadores más adelante en “mi granja”.",
+ "TITLE": "Ver certificaciones"
+ }
},
"CHOOSE_FARM": {
"ADD_NEW": "Agregar otra finca",
- "CHOOSE_TITLE": "Eliger otra finca",
+ "CHOOSE_TITLE": "Elegir otra finca",
"INPUT_PLACEHOLDER": "Buscar",
"SWITCH_TITLE": "Cambiar a otra finca"
},
@@ -242,6 +244,29 @@
"PASSWORD": "Contraseña",
"TITLE": "Crear nueva cuenta de usuario"
},
+ "CROP": {
+ "ADD_COMPLIANCE_FILE": "Enlace a un archivo de cumplimiento",
+ "ADD_CROP": "Agregar un cultivo",
+ "ADD_IMAGE": "Agregar imagen personalizada",
+ "ANNUAL": "Anual",
+ "ANNUAL_OR_PERENNIAL": "¿El cultivo es anual o perenne?",
+ "EDIT_CROP": "Editar cultivo",
+ "EDIT_MODAL": {
+ "BODY": "Editar este cultivo no modificará ningún plan de cultivo de cultivos existente. Solo se verán afectados los planes de gestión creados después de sus ediciones. ¿Proceder a editar?",
+ "TITLE": "Quiere editar este cultivo?"
+ },
+ "IS_GENETICALLY_ENGINEERED": "¿Este cultivo está modificado genéticamente?",
+ "IS_ORGANIC": "¿La semilla o el cultivo están certificados como orgánicos?",
+ "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Su certificador puede solicitar documentación que respalde su afirmación de que este cultivo no está modificado genéticamente.",
+ "NEED_DOCUMENT_PERFORM_SEARCH": "Su certificador puede solicitar documentación que respalde su búsqueda.",
+ "NEED_DOCUMENT_TREATED": "Su certificador puede solicitar documentación que describa cualquier tratamiento.",
+ "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrientes en porción comestible (por 100g)",
+ "PERENNIAL": "Perenne",
+ "PERFORM_SEARCH": "¿Realizó una búsqueda de disponibilidad comercial?",
+ "PHYSIOLOGY_AND_ANATOMY": "Fisiología y anatomía",
+ "TREATED": "¿Se han tratado las semillas de este cultivo?",
+ "UPLOAD_LATER": "También puede cargar archivos en otro momento."
+ },
"CROP_CATALOGUE": {
"ADD_CROP": "Agregar un nuevo cultivo",
"ADD_CROPS_T0_YOUR_FARM": "Agregar un cultivo a su granja",
@@ -252,6 +277,7 @@
"CROP_CATALOGUE": "Catálogo de cultivos",
"CROP_GROUP": "Grupo de cultivo",
"CROP_GROUP_TOOL_TIP": "La selección de un grupo de cultivos permite que LiteFarm rellene previamente mucha información sobre este cultivo, como la temporada de crecimiento, los valores nutricionales y el rendimiento estimado. No se preocupe, puede cambiar estos valores a continuación una vez que haya seleccionado un grupo de cultivos.",
+ "CROP_STATUS": "Estatus del cultivo activo",
"DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Documentar la información necesaria para la producción orgánica",
"FILTER": {
"LOCATION": "Ubicación",
@@ -259,14 +285,13 @@
"SUPPLIERS": "Proveedores",
"TITLE": "Filtro de catálogo de cultivos"
},
+ "FILTER_TITLE": "Filtro de catálogo de cultivos ",
"HERE_YOU_CAN": "Acá uno puede",
"LETS_BEGIN": "Vamos a comenzar",
"NEW_CROP_NAME": "Nombre de nuevo cultivo",
"NO_RESULTS_FOUND": "No se han encontrado resultados. Por favor, cambie sus filtros.",
"ON_YOUR_FARM": "En su granja",
- "SELECT_A_CROP": "Seleccione un cultivo para agregarlo a su granja. Utilice la búsqueda y los filtros para encontrar cultivos más rápidamente.",
- "CROP_STATUS": "Estatus del cultivo activo",
- "FILTER_TITLE": "Filtro de catálogo de cultivos "
+ "SELECT_A_CROP": "Seleccione un cultivo para agregarlo a su granja. Utilice la búsqueda y los filtros para encontrar cultivos más rápidamente."
},
"CROP_DETAIL": {
"ADD_PLAN": "Agregar un plan",
@@ -303,41 +328,20 @@
},
"SUPPLIER": "Proveedor/a"
},
- "CROP": {
- "ADD_CROP": "Agregar un cultivo",
- "ADD_IMAGE": "Agregar imagen personalizada",
- "ANNUAL": "Anual",
- "ANNUAL_OR_PERENNIAL": "¿El cultivo es anual o perenne?",
- "EDIT_CROP": "Editar cultivo",
- "EDIT_MODAL": {
- "BODY": "Editar este cultivo no modificará ningún plan de cultivo de cultivos existente. Solo se verán afectados los planes de gestión creados después de sus ediciones. ¿Proceder a editar?",
- "TITLE": "Quiere editar este cultivo?"
- },
- "IS_GENETICALLY_ENGINEERED": "¿Este cultivo está modificado genéticamente?",
- "IS_ORGANIC": "¿La semilla o el cultivo están certificados como orgánicos?",
- "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Su certificador puede solicitar documentación que respalde su afirmación de que este cultivo no está modificado genéticamente.",
- "NEED_DOCUMENT_PERFORM_SEARCH": "Su certificador puede solicitar documentación que respalde su búsqueda.",
- "NEED_DOCUMENT_TREATED": "Su certificador puede solicitar documentación que describa cualquier tratamiento.",
- "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrientes en porción comestible (por 100g)",
- "PERENNIAL": "Perenne",
- "PERFORM_SEARCH": "¿Realizó una búsqueda de disponibilidad comercial?",
- "PHYSIOLOGY_AND_ANATOMY": "Fisiología y anatomía",
- "TREATED": "¿Se han tratado las semillas de este cultivo?",
- "ADD_COMPLIANCE_FILE": "Enlace a un archivo de cumplimiento",
- "UPLOAD_LATER": "También puede cargar archivos en otro momento."
+ "DATE_RANGE": {
+ "HELP_BODY": "Selecciona el rango de fechas para crear un reporte financiero para su granja en ese rango.",
+ "HELP_TITLE": "Ayuda con el rango de fechas",
+ "TITLE": "Filtrar reporte por fecha",
+ "INVALID_RANGE_MESSAGE": "La fecha de finalización debe ser posterior a la fecha de inicio para obtener resultados"
},
"DATE_RANGE_PICKER": {
"FROM": "Desde",
"TO": "Hasta",
- "TO_MUST_BE_AFTER_FROM": "La fecha 'Hasta' debe ser posterior a la fecha 'Desde'"
- },
- "DATE_RANGE": {
- "HELP_BODY": "Selecciona el rango de fechas para crear un reporte financiero para su granja en ese rango.",
- "HELP_TITLE": "Ayuda con el rango de fechas",
- "TITLE": "Filtrar reporte por fecha"
+ "TO_MUST_BE_AFTER_FROM": "La fecha 'Hasta' debe ser posterior a la fecha 'Desde'",
+ "REVENUE_HELP_TITLE": "Ayuda con el rango de fechas",
+ "REVENUE_HELP_BODY": "Solo se mostrarán los planes que tengan una tarea de cosecha planificada o completada dentro del rango de fechas indicado."
},
"DOCUMENTS": {
- "ADD_DOCUMENT": "Agregar un nuevo documento",
"ADD": {
"ADD_MORE_PAGES": "Agregar más páginas",
"DOCUMENT_NAME": "Nombre del documento",
@@ -346,6 +350,7 @@
"TYPE": "Tipo",
"VALID_UNTIL": "Válido hasta"
},
+ "ADD_DOCUMENT": "Agregar un nuevo documento",
"ARCHIVE": "Archivar",
"ARCHIVE_DOCUMENT": "Archivar documento",
"ARCHIVE_DOCUMENT_TEXT": "Archivar este documento lo moverá a la sección de archivado de sus documentos, pero no lo eliminará. Los documentos archivados no se exportarán para sus certificaciones. Quiere proceder?",
@@ -371,12 +376,18 @@
"CLEANING_PRODUCT": "Producto de limpieza",
"CROP_COMPLIANCE": "Cumplimiento de cultivos",
"FERTILIZING_PRODUCT": "Producto fertilizante",
+ "INVOICES": "Facturas",
"OTHER": "Otro",
"PEST_CONTROL_PRODUCT": "Producto de control de plagas",
+ "RECEIPTS": "Recibos",
"SOIL_AMENDMENT": "Fertilización y correción del suelo",
"SOIL_SAMPLE_RESULTS": "Resultados de muestras del suelo",
"WATER_SAMPLE_RESULTS": "Resultados de la muestra de agua"
},
+ "UNARCHIVE": "Desarchivar",
+ "UNARCHIVE_DOCUMENT": "¿Desarchivar documento?",
+ "UNARCHIVE_DOCUMENT_TEXT": "Desarchivar este documento lo devolverá a su lista de documentos actualmente válidos. Los documentos válidos se exportarán para sus certificaciones. Quiere proceder?",
+ "UNARCHIVED": "Desarchivado",
"VALID": "Válido"
},
"ENTER_PASSWORD": {
@@ -390,8 +401,9 @@
},
"EXPENSE": {
"ADD_EXPENSE": {
- "MIN_ERROR": "Please enter a value greater than ",
- "REQUIRED_ERROR": "Expense is required",
+ "ALL_FIELDS_REQUIRED": "Todos los campos son obligatorios",
+ "MIN_ERROR": "Por favor ingrese un valor mayor que ",
+ "REQUIRED_ERROR": "Se requiere gasto",
"TITLE_1": "Nuevo gasto (1 de 2)",
"TITLE_2": "Nuevo gasto (2 de 2)"
},
@@ -416,6 +428,7 @@
"RESET_PASSWORD_LINK": "Envíar enlace para nueva contraseña."
},
"FARM_MAP": {
+ "TUTORIALS": "Tutoriales de mapas",
"AREA_DETAILS": {
"NETWORK": "Error de conexion.",
"PERIMETER": "Perimetro",
@@ -453,7 +466,8 @@
"DOWNLOAD": "Descargar",
"EMAIL_TO_ME": "Enviar a mi correo",
"EMAILING": "Enviando",
- "TITLE": "Exporta su mapa"
+ "TITLE": "Exporta su mapa",
+ "LOADING": "Cargando..."
},
"FARM_SITE_BOUNDARY": {
"EDIT_TITLE": "Editar limites de la granja",
@@ -550,11 +564,11 @@
"TITLE": "Agregar residencia"
},
"SPOTLIGHT": {
- "ADD": "Añade ubicaciones a su mapa",
- "ADD_TITLE": "Añade a su mapa",
- "EXPORT": "Descarga o comparte su mapa",
+ "ADD": "Añadir ubicaciones a su mapa",
+ "ADD_TITLE": "Añadir a su mapa",
+ "EXPORT": "Descargar o compartir su mapa",
"EXPORT_TITLE": "Exporta su mapa",
- "FILTER": "Cambia que se ve en el mapa",
+ "FILTER": "Cambiar que se ve en el mapa",
"FILTER_TITLE": "Filtra su mapa",
"HERE_YOU_CAN": "Aqui puede: "
},
@@ -565,8 +579,9 @@
"TITLE": "Agregar agua de superficie"
},
"TAB": {
- "CROPS": "Cultivo",
- "DETAILS": "Detalles"
+ "CROPS": "Cultivos",
+ "DETAILS": "Detalles",
+ "TASKS": "Tareas"
},
"TITLE": "Mapa de granja",
"TUTORIAL": {
@@ -637,7 +652,7 @@
"DATE": "Fecha",
"ESTIMATED_REVENUE": {
"ESTIMATED_ANNUAL_REVENUE": "Ingresos anuales estimados",
- "ESTIMATED_ANNUAL_YIELD": "Rendimiento anual estimado",
+ "ESTIMATED_ANNUAL_YIELD": "Cosecha anual estimada",
"ESTIMATED_PRICE_PER_UNIT": "Precio estimado por unidad",
"TITLE": "Ingresos estimados"
},
@@ -671,16 +686,30 @@
"AMPHIBIANS": "Anfibio",
"BIRDS": "Aves",
"CROP_VARIETIES": "Variedades de cultivos",
+ "ERROR": {
+ "BODY": "LiteFarm genera información sobre la biodiversidad basada en varias fuentes y no pudo hacerlo en este momento. Vuelva a intentarlo después de {{minutos}} minutos.",
+ "PREVIEW": "Indisponible",
+ "TITLE": "Había un problema"
+ },
"HEADER": "Numero de especies",
"INFO": "La biodiversidad es excelente para las personas y el planeta. Contamos la riqueza de especies de todos los registros conocidos de biodiversidad en su finca desde los límites de su finca. Puede aumentar la biodiversidad de los cultivos en su granja agregando cultivos adicionales. Puede aumentar el recuento de biodiversidad no agrícola en su granja registrando ubicaciones en https://www.inaturalist.org/app.",
"INSECTS": "Insectos",
+ "LOADING": {
+ "BODY": "Estamos generando las últimas reflexiones sobre biodiversidad para su granja. Esto puede tardar hasta 60 segundos.",
+ "PREVIEW": "Cargando...",
+ "TITLE": "Generando las reflexiones más recientes sobre biodiversidad..."
+ },
+ "MAMMALS": "Mamíferos",
"PLANTS": "Plantas",
- "SPECIES_COUNT": "{{count}} Especies",
- "SPECIES_COUNT_plural": "{{count}} Especies",
+ "SPECIES_COUNT": "{{count}} especies",
+ "SPECIES_COUNT_one": "{{count}} especies",
+ "SPECIES_COUNT_many": "{{count}} especies",
+ "SPECIES_COUNT_other": "{{count}} especies",
+ "SPECIES_COUNT_plural": "{{count}} especies",
"TITLE": "Biodiversidad"
},
"CURRENT": "Actual",
- "INFO": "Las reflexiones son caracteristicas de datos de que esta pasando en su granja. Mientras mas data proveas en la aplicacion mas reflexiones pueden ser generadas. Mira las reflexiones individuales para mas informacion.",
+ "INFO": "Las reflexiones son caracteristicas de datos de que esta pasando en su granja. Mientras mas data proveas en la aplicacion mas reflexiones pueden ser generadas. Mira las reflexiones individuales para mas información.",
"LABOUR_HAPPINESS": {
"HEADER": "Tareas",
"INFO": "Estimamos el impacto de las diferentes tareas en la satisfaccion con el trabajo usando los puntajes de satisfaccion y las horas trabajadas en cada turno.",
@@ -691,6 +720,9 @@
"CHOOSE_A_FREQUENCY": "Escoja una frecuencia",
"CHOOSE_FREQUENCY": "Escoja Frecuencia...",
"COUNT_MONTHS": "{{count}} mese",
+ "COUNT_MONTHS_one": "{{count}} mese",
+ "COUNT_MONTHS_many": "{{count}} meses",
+ "COUNT_MONTHS_other": "{{count}} meses",
"COUNT_MONTHS_plural": "{{count}} meses",
"CYCLE_INDICATOR": "Su balance de nitrogeno esta en {{frequency}} meses por ciclo y la data se vera en: {{refreshDate}}",
"FIRST_TIME": "Parece que es la primera vez que corres esto! Por favor, selecciona una frecuencia para calcular su balance de nitrogeno",
@@ -707,6 +739,9 @@
"HEADER": "Numero de comidas",
"INFO": "Estimamos el numero de comidas potenciales provistas por su granja basandonos en los datos de sus ventas y la base de datos de la composicion de cultivos. Asumimos que los requerimientos diarios se dividen en partes iguales en 3 comidas al dia.",
"MEAL_COUNT": "{{count}} comida",
+ "MEAL_COUNT_one": "{{count}} comida",
+ "MEAL_COUNT_many": "{{count}} comidas",
+ "MEAL_COUNT_other": "{{count}} comidas",
"MEAL_COUNT_plural": "{{count}} comidas",
"MEALS": "Comidas",
"PROTEIN": "Proteina",
@@ -716,7 +751,10 @@
},
"PRICES": {
"INFO": "Se mostramos la trayectoria de sus precios de venta contra el precio de venta de los mismos bienes en una distancia dada de su granja, recolectadas a traves de la red de Litefarm.",
- "NEARBY_FARMS": "Buscando data de ventas de {{count}} granja",
+ "NEARBY_FARMS": "El precio del mercado se basa en {{count}} granjas en su área local",
+ "NEARBY_FARMS_one": "El precio del mercado se basa en {{count}} granja en su área local",
+ "NEARBY_FARMS_many": "El precio del mercado se basa en {{count}} granjas en su área local",
+ "NEARBY_FARMS_other": "El precio del mercado se basa en {{count}} granjas en su área local",
"NEARBY_FARMS_plural": "Buscando data de ventas de {{count}} granjas",
"NETWORK_PRICE": "Precio de red",
"NO_ADDRESS": "Actualmente no tienes una direccion en Litefarm. Por favor actualizala en su Perfil para obtener data de ventas cercanas.",
@@ -735,7 +773,7 @@
"TITLE": "Reflexiones",
"UNAVAILABLE": "No Disponible",
"WATER_BALANCE": {
- "FIRST_TIME": "Parece que es la primera vez que llega aca! Para mas informacion en que hace esto, por favor cliquea el boton de informacion.",
+ "FIRST_TIME": "Parece que es la primera vez que llega aca! Para mas información en que hace esto, por favor cliquea el boton de información.",
"INFO_1": "El balance de agua se dice si sus cultivos tienen deficiencia de agua o exceso. Depende de los datos meterologicos, y es actualizado por sus registros de riego .",
"INFO_2": "Esta funcionalidad no ha sido probada ampliamente en las granjas con una baja densidad de estaciones metereologicas alrededor de ellas asi que uselo con precaucion. Por favor, cuentanos como funciona en su granja",
"NO_SCHEDULE_RUN": "Su balance de agua agendado aun no ha corrido, por favor, chequea en 2 dias y asegurate que tienes al menos un registro de textura de suelo para un campo para ver datos de balance de agua para cultivos en ese campo . Si el problema persiste, contacta a Litefarm.",
@@ -773,6 +811,8 @@
"BIRTH_YEAR_ERROR": "Año de nacimiento necesitar ser entre 1900 y",
"BIRTH_YEAR_TOOLTIP": "Información sobre la edad es recolectada sólo por propósitos de estudio y sólo será compartida sin identificar personalmente a Ud.",
"CHOOSE_ROLE": "Elegir rol",
+ "DEFAULT_LANGUAGE": "Español",
+ "DEFAULT_LANGUAGE_VALUE": "es",
"EMAIL": "Correo electrónico",
"EMAIL_INFO": "Usuarios sin correo electrónico no podrán iniciar sesión",
"FULL_NAME": "Nombre completo",
@@ -780,6 +820,7 @@
"GENDER_TOOLTIP": "Información sobre el género es recolectada sólo por propósitos de estudio y sólo será compartida sin identificar personalmente a Ud.",
"INVALID_EMAIL_ERROR": "Por favor ingrese una dirección de correo válida",
"INVITE": "Invitar",
+ "LANGUAGE_OF_INVITE": "Idioma de la invitación",
"PHONE": "Número de teléfono",
"PHONE_ERROR": "Por favor ingrese un número de teléfono válido",
"ROLE": "Rol",
@@ -838,15 +879,15 @@
"DISEASE": "Enfermedad",
"HARVEST": "Cosecha",
"HARVEST_ALLOCATION_SUBTITLE": "Aproximadamente cuanto de la cosecha se utilizará para cada propósito?",
+ "HARVEST_ALLOCATION_SUBTITLE_TWO": "Cantidad para asignar",
+ "HARVEST_QUANTITY": "Cantidad de cosecha",
+ "HARVEST_USE": "Uso de la cosecha",
"HARVEST_USE_TYPE_SUBTITLE": "Cómo será usada la cosecha?",
"OTHER": "Otro",
"PEST": "Peste",
"QUANTITY_ERROR": "La cantidad no debe de tener mas de 2 decimales",
"TITLE": "Registro de cosecha",
- "WEED": "Melaza",
- "HARVEST_QUANTITY": "Cantidad de cosecha",
- "HARVEST_USE": "Uso de la cosecha",
- "HARVEST_ALLOCATION_SUBTITLE_TWO": "Cantidad para asignar"
+ "WEED": "Melaza"
},
"LOG_IRRIGATION": {
"DRIP": "Goteo",
@@ -870,8 +911,11 @@
"BEDS": "Camas",
"BROADCAST": "Siembra a voleo o sembradora mecánica",
"COMPLETE_PLAN": {
+ "ABANDON_DATE": "Fecha de abandono",
+ "ABANDON_NOTES": "Notas de abandono",
"ABANDON_PLAN": "Abandonar plan",
"ABANDON_REASON": "Razón para abandonar",
+ "COMPLETE_DATE": "Fecha completada",
"COMPLETE_PLAN": "Completar plan",
"DATE_OF_CHANGE": "Fecha de cambio de estado",
"NOTES_CHAR_LIMIT": "Las notas deben tener menos de 10,000 caracteres",
@@ -887,6 +931,7 @@
},
"WHAT_HAPPENED": "¿Qué sucedió?"
},
+ "COMPLETION_NOTES": "Notas de conclusión",
"CONTAINER": "Maceta",
"CONTAINER_OR_IN_GROUND": "¿Está plantando en una maceta o en el suelo?",
"CONTAINER_TYPE": "Tipo de maceta",
@@ -903,11 +948,11 @@
"DURATION_TOOLTIP": "Estos son valores sugeridos. Ajústelo a las condiciones locales.",
"EDITING_PLAN_WILL_NOT_MODIFY": "La edición de este plan no modificará las tareas asignadas.",
"ESTIMATED_SEED": "Semilla estimada es obligatoria",
- "ESTIMATED_YIELD": "Rendimiento estimado",
+ "ESTIMATED_YIELD": "Cosecha anual estimada",
"FIRST_MP_SPOTLIGHT": {
"BODY_PART1": "LiteFarm ha generado algunas tareas basadas en su plan. Puede agregar más tareas o asignarlas en esta pantalla.",
"BODY_PART2": "Su plan se activará una vez que complete una tarea.",
- "TITLE": "Felicitaciones!¡Ha hecho su primer plan de cultivo!"
+ "TITLE": "¡Felicitaciones! ¡Ha hecho su primer plan de cultivo!"
},
"FOR_HARVEST": "Para la cosecha",
"GERMINATION": "Germinación",
@@ -922,9 +967,9 @@
"KNOW_HOW_IS_CROP_PLANTED": "¿Sabes cómo se plantó el cultivo?",
"LOCATION_SUBTEXT": "Solo se muestran las ubicaciones que pueden producir cultivos.",
"MANAGEMENT_PLAN_FLOW": "creación del plan de cultivo",
- "MANAGEMENT_SPOTLIGHT_1": "Crea nuevos planes para este cultivo",
+ "MANAGEMENT_SPOTLIGHT_1": "Crear nuevos planes para este cultivo",
"MANAGEMENT_SPOTLIGHT_2": "Ver y modificar planes para este cultivo",
- "MANAGEMENT_SPOTLIGHT_3": "Crea y asigna tareas",
+ "MANAGEMENT_SPOTLIGHT_3": "Crear y asigna tareas",
"MANAGEMENT_SPOTLIGHT_TITLE": "Manejo",
"NEXT_HARVEST": "¿Cuándo espera su próxima cosecha?",
"NOTES_CHAR_LIMIT": "Las notas deben tener menos de 10,000 caracteres",
@@ -945,6 +990,7 @@
"PLANTING_NOTE": "Notas de la siembra",
"PLANTING_SOIL": "Suelo de siembra que se utilizará",
"PLANTS_PER_CONTAINER": "# de plantas/maceta",
+ "RATE_THIS_MANAGEMENT_PLAN": "Valora este plan de manejo",
"REMOVE_PIN": "Quitar el pin",
"ROW_METHOD": {
"HISTORICAL_SAME_LENGTH": "¿Tenían todas las filas la misma longitud?",
@@ -966,12 +1012,19 @@
"SELECTED_STARTING_LOCATION": "Seleccione siempre esta como la ubicación de inicio para los cultivos que se trasplantarán",
"SPOTLIGHT_HERE_YOU_CAN": "Aqui une puede:",
"STARTED": "Empecemos",
+ "STATUS": {
+ "ABANDONED": "Abandonado",
+ "ACTIVE": "Activo",
+ "COMPLETED": "Terminado",
+ "PLANNED": "Planificado"
+ },
"SUPPLIER": "Proveedor",
"TERMINATION": "Terminar",
"TERMINATION_DATE": "¿Cuándo terminará este cultivo?",
"TOTAL_PLANTS": "# de plantas",
"TRANSPLANT": "Trasplantar",
"TRANSPLANT_DATE": "¿Cuál es la fecha de su trasplante?",
+ "TRANSPLANT_LOCATION": "¿A dónde vas a trasplantar?",
"TRANSPLANT_SPOTLIGHT": {
"BODY": {
"PLANTED": "plantado",
@@ -987,17 +1040,10 @@
"VARIETY": "Variedad",
"WHAT_IS_AGE": "¿Cuál es la edad aproximada del cultivo?",
"WHAT_WAS_PLANTING_METHOD": "¿Cuál fue el método de plantación?",
+ "WHAT_WAS_PLANTING_METHOD_INFO": "Seleccionar el método de siembra correcto ayudará a LiteFarm a estimar con mayor precisión la cantidad de semilla necesaria, el rendimiento y otros conocimientos útiles.",
"WHERE_START_LOCATION": "¿Dónde está su ubicación inicial?",
"WHERE_TRANSPLANT_LOCATION": "¿A dónde va a trasplantar?",
- "WILD_CROP": "¿Estás cosechando un cultivo silvestre?",
- "STATUS": {
- "ABANDONED": "Abandonado",
- "ACTIVE": "Activo",
- "COMPLETED": "Terminado",
- "PLANNED": "Planificado"
- },
- "WHAT_WAS_PLANTING_METHOD_INFO": "Seleccionar el método de siembra correcto ayudará a LiteFarm a estimar con mayor precisión la cantidad de semilla necesaria, el rendimiento y otros conocimientos útiles.",
- "TRANSPLANT_LOCATION": "¿A dónde vas a trasplantar?"
+ "WILD_CROP": "¿Estás cosechando un cultivo silvestre?"
},
"MY_FARM": {
"CERTIFICATIONS": "Certificaciones",
@@ -1007,35 +1053,77 @@
},
"NAVIGATION": {
"SPOTLIGHT": {
+ "COORDINATE_ACTIVITIES": "Coordinar actividades de la finca",
+ "EDIT_FARM_SETTING": "Editar las características de su finca",
"FARM": "Aquí puede:, • Editar las características de su finca, • Recorre el mapa su finca, • Manejar sus trabajadores",
"FARM_TITLE": "Este es el perfil de su finca",
+ "INFO": "Su información",
+ "LOG_OUT": "El botón para cerrar la sesión",
+ "MANAGE_EMPLOYEE": "Manejar sus trabajadores",
+ "MANAGE_TASK": "Manejar sus tareas",
+ "MAP_FARM": "Mapear su granja",
+ "SEE_UPDATES": "Ver actualizaciones importantes",
"NOTIFICATION": "Aqui puede:, • Manejar sus tareas, • Mira qué más está pasando, • Coordinar actividades de la finca",
- "NOTIFICATION_TITLE": "Estas son sus tareas de la granja",
+ "NOTIFICATION_TITLE": "Este es su centro de notificaciones",
"PROFILE": "Aquí encontrará:, • Su informacion, • Datos útiles, • El botón para cerrar la sesión",
- "PROFILE_TITLE": "Este es su perfil"
+ "PROFILE_TITLE": "Este es su perfil",
+ "SEE_TASK": "Mira qué más está pasando",
+ "TASK_TITLE": "Estas son sus tareas de la granja",
+ "TIPS": "Datos útiles",
+ "YOU_CAN": "Aquí puede:",
+ "YOU_WILL_FIND": "Aquí encontrará:"
}
},
"NOTIFICATION": {
- "NOTIFICATION_TEASER": "Proximamente!"
+ "DAILY_TASKS_DUE_TODAY": {
+ "BODY": "Tienes tareas para hoy.",
+ "TITLE": "Tareas para hoy"
+ },
+ "NONE_TO_DISPLAY": "No hay notificaciones para mostrar.",
+ "NOTIFICATION_TEASER": "Proximamente!",
+ "PAGE_TITLE": "Notificaciones",
+ "TAKE_ME_THERE": "Llévame allí",
+ "TASK_ABANDONED": {
+ "BODY": "Una {{taskType}} tarea que se te asignó ha sido abandonada por {{abandoner}}.",
+ "TITLE": "Tarea abandonada"
+ },
+ "TASK_ASSIGNED": {
+ "BODY": "Se ha asignado una tarea {{taskType}} a {{assignee}}.",
+ "TITLE": "Tarea asignada"
+ },
+ "TASK_COMPLETED_BY_OTHER_USER": {
+ "BODY": "Una tarea de {{taskType}} que se le asignó ha sido marcada como completada por {{assigner}}.",
+ "TITLE": "Tarea completada"
+ },
+ "TASK_REASSIGNED": {
+ "BODY": "Una {{taskType}} tarea que te asignó previamente ha sido asignada a otra persona por {{assigner}}.",
+ "TITLE": "Tarea reasignada"
+ },
+ "WEEKLY_UNASSIGNED_TASKS": {
+ "BODY": "Tiene tareas sin asignar que vencen esta semana.",
+ "TITLE": "Tareas sin responables"
+ }
},
"OUTRO": {
"ALL_DONE": "Excelente. Listo para ensuciarse las manos?",
"IMPORTANT_THINGS": "Y finalmente, déjenos mostrarle un par de cosas importantes!"
},
- "PASSWORD_RESET_SUCCESS_MODAL": {
- "BUTTON": "Muy bien!",
- "DESCRIPTION": "Su contraseña ha sido actualizada. Redirigiéndolo(a) a su finca en 10 segundos...",
- "TITLE": "Exito!"
- },
"PASSWORD_RESET": {
"BUTTON": "Reenviar link",
"BUTTON_SENDING": "Enviando...",
"DESCRIPTION_BOTTOM": "Por favor revise su correo electrónico.",
"DESCRIPTION_TOP": "Un enlace ha sido enviado.",
- "NEW_ACCOUNT_BUTTON": "Actualización",
+ "LABEL_EMAIL": "Correo electrónico",
+ "LABEL_NEW_PASSWORD": "Nueva contraseña",
+ "NEW_ACCOUNT_BUTTON": "Actualizar",
"NEW_ACCOUNT_TITLE": "Ajuste su nueva contraseña",
"TITLE": "Enlace enviado"
},
+ "PASSWORD_RESET_SUCCESS_MODAL": {
+ "BUTTON": "Muy bien!",
+ "DESCRIPTION": "Su contraseña ha sido actualizada. Redirigiéndolo(a) a su finca en 10 segundos...",
+ "TITLE": "Exito!"
+ },
"PLAN_GUIDANCE": {
"ADDITIONAL_GUIDANCE": "¿Hay alguna orientación adicional que desee proporcionar para esta tarea de siembra?",
"BED": "Cama",
@@ -1048,22 +1136,14 @@
"SPECIFY": "Especificar {{types}}",
"SPECIFY_PLACEHOLDER": "Eje. {{types}} 1-4",
"TOOLTIP": "Los primeros 40 caracteres de este campo se mostrarán en cualquier lugar donde esté visible su plan de cultivo.",
- "WIDTH": "{{type}} la anchcho",
+ "WIDTH": "El ancho de {{type}} ",
"WORD_LIMIT": "Solo se pueden mostrar {{limit}} caracteres"
},
"PREPARING_EXPORT": {
"MESSAGE": "LiteFarm está juntando sus documentos de certificación y usted recibirá un correo electrónico cuando hayamos terminado; puede demorar unos minutos ... Puede hacer clic fuera de este cuadro para continuar usando LiteFarm sin interrumpir el proceso.",
"TITLE": "Se está preparando su exportación"
},
- "PROFILE_FLOATER": {
- "HELP": "Ayuda",
- "INFO": "Mi información",
- "LOG_OUT": "Cerrar sesión",
- "SWITCH": "Cambiar de finca",
- "TUTORIALS": "Tutoriales"
- },
"PROFILE": {
- "ACCOUNT_TAB": "Cuenta",
"ACCOUNT": {
"CONVERT_TO_HAVE_ACCOUNT": "Convertir a este trabajador en usuario con cuenta",
"EDIT_USER": "Editar usuario",
@@ -1073,13 +1153,13 @@
"FRENCH": "Francés",
"LANGUAGE": "Idioma",
"LAST_NAME": "Apellido",
- "PERSONAL_INFORMATION": "Mi informacion",
+ "PERSONAL_INFORMATION": "Mi información",
"PHONE_NUMBER": "Número de teléfono",
"PORTUGUESE": "Portugués",
"SPANISH": "Español",
"USER_ADDRESS": "Dirección de usuario"
},
- "FARM_TAB": "Finca",
+ "ACCOUNT_TAB": "Cuenta",
"FARM": {
"ADDRESS": "Dirección",
"CURRENCY": "Moneda",
@@ -1089,7 +1169,7 @@
"PHONE_NUMBER": "Número de teléfono",
"UNITS": "Unidades"
},
- "PEOPLE_TAB": "Personas",
+ "FARM_TAB": "Finca",
"PEOPLE": {
"DO_YOU_WANT_TO_REMOVE": "¿Quiere eliminar a este usuario/a de su granja?",
"EO": "Oficial de extensión",
@@ -1107,6 +1187,7 @@
"THIS_WILL_REMOVE": "Esta acción eliminará al usuario/a de su granja.",
"USERS_FOUND": "Usuarios encontrados"
},
+ "PEOPLE_TAB": "Personas",
"TABLE": {
"HEADER_EMAIL": "Correo",
"HEADER_NAME": "Nombre",
@@ -1114,6 +1195,13 @@
"HEADER_STATUS": "Estatus"
}
},
+ "PROFILE_FLOATER": {
+ "HELP": "Ayuda",
+ "INFO": "Mi información",
+ "LOG_OUT": "Cerrar sesión",
+ "SWITCH": "Cambiar de finca",
+ "TUTORIALS": "Tutoriales"
+ },
"REACT_SELECT": {
"CLEAR": "Borrar",
"CLEAR_ALL": "Borrar todo"
@@ -1277,12 +1365,14 @@
"EMAIL_INVALID": "Correo invalido",
"ENTER_EMAIL": "Ingresar Correo",
"EXPIRED_ERROR": "Hemos actualizado nuestra infraestructura y deberá restablecer su contraseña. Revise su bandeja de entrada para continuar.",
+ "EXPIRED_INVITATION_LINK_ERROR": "La invitación no está válida o caducada",
"GOOGLE_BUTTON": "Continúe con Google",
"INVITED_ERROR": "Faltante",
"LITEFARM_UPDATED": "¡Hemos actualizado LiteFarm!",
"PASSWORD_ERROR": "Contraseña incorrecta",
"SIGN_IN": "Registrarse",
"SSO_ERROR": "Por favor inicie sesión haciendo clic el boton Google de arriba",
+ "USED_INVITATION_LINK_ERROR": "Esta invitación ya se ha utilizado, inicie sesión para acceder a esta granja",
"WELCOME_BACK": "Bienvenido",
"WRONG_BROWSER": "LiteFarm no es optimizada por este navegador.",
"WRONG_BROWSER_BOTTOM": "Por favor inicie sesión usando Chrome."
@@ -1312,23 +1402,21 @@
"TITLE": "Cambiando de finca"
},
"TABLE": {
- "LOADING_TEXT": "Loading...",
+ "LOADING_TEXT": "Cargando...",
"NEXT_TEXT": "Siguiente",
- "NO_DATA_TEXT": "No se encontro informacion",
+ "NO_DATA_TEXT": "No se encontro información",
"OF_TEXT": "De",
"PAGE_TEXT": "Pagina",
"PREVIOUS_TEXT": "Previa",
"ROWS_TEXT": "filas"
},
"TASK": {
- "ABANDON_TASK": "Abandonar esta tarea",
- "ABANDON_TASK_DURATION": "¿Se completó algún trabajo para esta tarea?",
"ABANDON": {
"ABANDON": "Abandonar",
+ "DATE": "Fecha de abandono",
"INFO": "Abandonar esta tarea cambiará su estado a abandonada y la eliminará de todas las listas de ‘Tareas pendientes’ y ‘No asignadas’ de todos los usuarios.",
"NOTES": "Notas de abandono de tarea",
"NOTES_CHAR_LIMIT": "Las notas deben tener menos de 10,000 caracteres",
- "REASON_FOR_ABANDONMENT": "Razón para abandonar",
"REASON": {
"CROP_FAILURE": "Falla del cultivo",
"LABOUR_ISSUE": "Problema laboral",
@@ -1338,13 +1426,17 @@
"SCHEDULING_ISSUE": "Problema de programación",
"WEATHER": "Clima"
},
+ "REASON_FOR_ABANDONMENT": "Razón para abandonar",
"TITLE": "Abandonar tarea",
- "WHAT_HAPPENED": "¿Qué sucedió?"
+ "WHAT_HAPPENED": "¿Qué sucedió?",
+ "WHEN": "¿Cuándo se abandonó la tarea?"
},
+ "ABANDON_TASK": "Abandonar esta tarea",
+ "ABANDON_TASK_DURATION": "¿Se completó algún trabajo para esta tarea?",
"ABANDONMENT_DETAILS": "Detalles del abandono de la tarea",
- "ADD_CUSTOM_HARVEST_USE": "Crea un uso de cosecha personalizado ",
+ "ADD_CUSTOM_HARVEST_USE": "Crear un uso de cosecha personalizado ",
"ADD_HARVEST_USE": "Agregar otro uso de la cosecha",
- "ADD_TASK": "Crea una tarea",
+ "ADD_TASK": "Crear una tarea",
"ADD_TASK_FLOW": "creación de tareas",
"ALL": "Todas",
"AMOUNT_TO_ALLOCATE": "Cantidad a asignar",
@@ -1352,6 +1444,10 @@
"MULTIPLE_CROPS": "Múltiples cultivos",
"MULTIPLE_LOCATIONS": "Múltiples ubicaciones"
},
+ "COMPLETE": {
+ "DATE": "Fecha de completar",
+ "WHEN": "¿Cuándo se completó la tarea?"
+ },
"COMPLETE_HARVEST_QUANTITY": "¿Cuánto se cosechó?",
"COMPLETE_TASK": "Completar tarea",
"COMPLETE_TASK_CHANGES": "¿Tuvo que hacer algún cambio en esta tarea?",
@@ -1360,13 +1456,30 @@
"COMPLETION_DETAILS": "Detalles de finalización de la tarea",
"COMPLETION_NOTES": "Notas de finalización de tarea",
"COMPLETION_NOTES_CHAR_LIMIT": "Las notas deben tener menos de 10,000 caracteres",
- "CREATE_CUSTOM_HARVEST_USE": "Crea un uso de cosecha personalizado",
+ "CREATE_CUSTOM_HARVEST_USE": "Crear un uso de cosecha personalizado",
"CURRENT": "Actual",
"DESCRIBE_HARVEST_USE": "Describe el uso de la cosecha",
"DETAILS": "Detalles",
"DID_YOU_ENJOY": "¿Disfrutaste esta tarea?",
"DUE_DATE": "Fecha de vencimiento",
"DURATION": "Duración",
+ "FILTER": {
+ "ASCENDING": "las más viejas primero",
+ "ASSIGNEE": "Responsable",
+ "CROP": "Cultivo",
+ "DATE_RANGE": "Filtrar por rango de fechas",
+ "DESCENDING": "Las más nuevas primero",
+ "FROM": "Desde",
+ "LOCATION": "Ubicación",
+ "MY_TASK": "Mis tareas",
+ "SORT_BY": "Ordenar por",
+ "STATUS": "Estatus",
+ "TITLE": "Filtro de tareas",
+ "TO": "Hasta",
+ "TYPE": "Tipo",
+ "UNASSIGNED": "Sin asignar",
+ "VIEW": "Vista"
+ },
"HARVEST_USE": "Usa de la cosecha?",
"HARVEST_USE_ALREADY_EXISTS": "El uso de cosecha ya existe",
"HOW_WILL_HARVEST_BE_USED": "Como va a usar la cosecha?",
@@ -1382,20 +1495,23 @@
"SELECT_DATE": "Seleccione la fecha de la tarea",
"SELECT_TASK_LOCATIONS": "Seleccione la(s) ubicación(es) de la tarea",
"SELECT_WILD_CROP": "Esta tarea se dirige a un cultivo silvestre",
- "TASK": "tarea",
- "TASKS_COUNT": "{{count}} tarea",
- "TASKS_COUNT_plural": "{{count}} tareas",
- "TODO": "Para hacer",
- "TRANSPLANT": "Trasplantar",
- "TRANSPLANT_LOCATIONS": "Seleccione una ubicación para el trasplante",
- "UNASSIGNED": "Sin asignar",
"STATUS": {
"ABANDONED": "Abandonada",
"COMPLETED": "Completada",
"FOR_REVIEW": "Para la revisión",
"LATE": "Tarde",
"PLANNED": "Planificada"
- }
+ },
+ "TASK": "tarea",
+ "TASKS_COUNT": "{{count}} tarea",
+ "TASKS_COUNT_one": "{{count}} tarea",
+ "TASKS_COUNT_many": "{{count}} tareas",
+ "TASKS_COUNT_other": "{{count}} tareas",
+ "TASKS_COUNT_plural": "{{count}} tareas",
+ "TODO": "Para hacer",
+ "TRANSPLANT": "Trasplantar",
+ "TRANSPLANT_LOCATIONS": "Seleccione una ubicación para el trasplante",
+ "UNASSIGNED": "Sin asignar"
},
"UNIT": {
"TIME": {
@@ -1416,4 +1532,4 @@
"YEAR_SELECTOR": {
"TITLE": "Seleccionar año"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/fr/certifications.json b/packages/webapp/public/locales/fr/certifications.json
index c73d642050..f915d9797b 100644
--- a/packages/webapp/public/locales/fr/certifications.json
+++ b/packages/webapp/public/locales/fr/certifications.json
@@ -1,4 +1,4 @@
{
"ORGANIC": "Biologique",
- "PGS": "Système de participation guaranti"
+ "PGS": "Système de participation garantie"
}
diff --git a/packages/webapp/public/locales/fr/common.json b/packages/webapp/public/locales/fr/common.json
index dde7ec04a9..89409cb71f 100644
--- a/packages/webapp/public/locales/fr/common.json
+++ b/packages/webapp/public/locales/fr/common.json
@@ -1,7 +1,7 @@
{
"ABANDON": "Abandonner",
"ACTIVE": "Actif",
- "ADD": "MISSING",
+ "ADD": "Ajouter",
"ALL": "Tout",
"APPLY": "Appliquer",
"BACK": "Retour",
@@ -14,11 +14,12 @@
"DELETE": "Effacer",
"DO_NOT_SHOW": "Ne plus afficher ce message",
"EDIT": "Modifier",
+ "EDIT_DATE": "Modifier la Date",
"EXPORT": "Exporter",
"FINISH": "Terminer",
"FROM": "De",
"GOT_IT": "J'ai compris !",
- "HERE": "MISSING",
+ "HERE": "Ici",
"HIDE": "Cacher",
"HOURS": "Heurs",
"LOADING": "Chargement en cours...",
@@ -28,27 +29,31 @@
"MAX_ERROR": "Veuillez saisir une valeur inférieure à {{value}}",
"MIN_ERROR": "Veuillez saisir une valeur supérieur à {{value}}",
"NAME": "Nom",
+ "NEEDS_PLAN": "A besoin d'un plan",
"NEXT": "Suivant",
"NO": "Non",
- "NOT_SURE": "Pas certain",
+ "NOT_SURE": "Incertain(e)",
"NOTES": "Notes",
+ "OK": "OK",
"OPTIONAL": "(optionnel)",
"OTHER": "Autre",
"PAST": "Passé",
"PLANNED": "Planifié",
"PROCEED": "Procéder",
"REMOVE": "Supprimer",
- "REQUIRED": "Requi",
+ "REQUIRED": "Réponse requise",
"RETIRE": "Retirer",
"SAVE": "Enregistrer",
"SAVE_CHANGES": "Enregistrer les changements",
"SEARCH": "Rechercher",
"SELECT": "Selectionner",
+ "CREATE": "Ajouter",
+ "SKIP": "Sauter",
"SORRY": "Désoler",
"SUBMIT": "Soumettre",
"SUBMITTING": "Soumission en cours...",
"UPDATE": "Mettre à Jour",
"WORD_LIMIT_ERROR": "Seulement les charactères{{value}} peuvent être affichés",
- "YES": "Oui",
- "EDIT_DATE": "Modifier la Date"
+ "YEAR": "Année",
+ "YES": "Oui"
}
diff --git a/packages/webapp/public/locales/fr/crop.json b/packages/webapp/public/locales/fr/crop.json
index 7dd2be636b..3166d7632f 100644
--- a/packages/webapp/public/locales/fr/crop.json
+++ b/packages/webapp/public/locales/fr/crop.json
@@ -1,22 +1,22 @@
{
"ABACA_MANILA_HEMP": "Chanvre, Manila",
"ALFALFA_FOR_FODDER": "Luzerne Fourragère",
- "ALFALFA_FOR_SEED": "Graines de Luzerne",
+ "ALFALFA_FOR_SEED": "Luzerne, pour les graines",
"ALMOND": "Amande",
"ANISE_SEEDS": "Graines d'Anis",
"APPLE": "Pomme",
"APRICOT": "Abricot",
- "ARECA_BETEL_NUT": "Noix d'Arec",
+ "ARECA_BETEL_NUT": "Noix d'Arec (noix de bétel)",
"ARRACHA": "Arracha",
- "ARROWROOT": "Marante",
- "ARTICHOKE": "Artichaute",
+ "ARROWROOT": "Marante (arrowroot)",
+ "ARTICHOKE": "Artichaut",
"ASPARAGUS": "Asperge",
"AVOCADO": "Avocat",
"BAJRA_PEARL_MILLET": "Mil (à Chandelle, Pénicillaire)",
"BAMBARA_GROUNDNUT": "Pois Bambara",
"BANANA": "Banane",
"BARLEY": "Orge",
- "BEANS": "Fèves",
+ "BEANS": "Fèves / haricots",
"BEANS_DRY_EDIBLE_FOR_GRAINS": "Fèves comestibles, secs, pour les céréales",
"BEANS_HARVESTED_GREEN": "Haricot verts",
"BEET": "Betterave",
@@ -31,12 +31,12 @@
"BLACK_PEPPER": "Poivre Noir",
"BLACK_WATTLE": "Acacia Noir",
"BLUEBERRY": "Bleuet",
- "BRAZIL_NUT": "Bois-Brésil, Pernambouc",
+ "BRAZIL_NUT": "Noix du Brésil",
"BREADFRUIT": "Arbre à Pain",
- "BROAD_BEAN": "Fève",
- "BROAD_BEAN_DRY": "Fève sec, Gourgane",
+ "BROAD_BEAN": "Gourganes",
+ "BROAD_BEAN_DRY": "Gourganes, Gourgane",
"BROAD_BEAN_HARVESTED_GREEN": "Gourgane vertes",
- "BROCCOLI": "Brocoli"
+ "BROCCOLI": "Brocoli",
"BROOM_MILLET": "Millet Commun",
"BROOM_SORGHUM": "Sorgho Commun",
"BRUSSELS_SPROUTS": "Chou de Bruxelles",
@@ -57,12 +57,12 @@
"CASHEW_NUTS": "Cajou, Anacardier",
"CASSAVA_MANIOC": "Cassava (manioc)",
"CASTOR_BEAN": "Ricin",
- "CAULIFLOWER": "Choufleur",
+ "CAULIFLOWER": "Chou-fleur",
"CELERIAC": "Céleri Rave",
"CELERY": "Céleri",
"CHAYOTE": "Chayotte",
"CHERRY_ALL_VARIETIES": "Cerise (toutes variétées)",
- "CHESTNUT": "Marron",
+ "CHESTNUT": "Marron / châtaigne",
"CHICKPEA_GRAM_PEA": "Pois Chiches",
"CHICORY": "Chicorée",
"CHICORY_FOR_GREENS": "Chicorée",
@@ -152,7 +152,7 @@
"HYBRID_MAIZE": "Maïs hybride",
"INDIGO": "Indigotier",
"JASMINE": "Jasmin",
- "JERUSALEM_ARTICHOKE": "Artichaut Jerusalem",
+ "JERUSALEM_ARTICHOKE": "Artichaut de Jérusalem",
"JOWAR_SORGHUM": "Sorgo Jowar",
"JUTE": "Jute",
"KALE": "Chou Frisé",
@@ -165,12 +165,12 @@
"LEMON_GRASS": "Citronnelle",
"LENTIL": "Lentille",
"LESPEDEZA_ALL_VARIETIES": "Lespedeza (toutes variétées)",
- "LETTUCE": "Laitu",
+ "LETTUCE": "Laitue",
"LIME": "Lime",
"LIME_SOUR": "Citron vert, Lime",
"LIME_SWEET": "Citron doux, Limette",
"LINSEED_FLAX_FOR_OIL_SEED": "Lin pour graines oléagineuses (graines de lin)",
- "LIQUORICE": "Reglisse",
+ "LIQUORICE": "Réglisse",
"LITCHI": "Litchi",
"LOQUAT": "Bibace",
"LUPINE_ALL_VARIETIES": "Lupin (toutes variétées)",
@@ -234,13 +234,13 @@
"PEA": "Pois",
"PEACH": "Pêche",
"PEANUT_GROUNDNUT": "Cacahuète (arachide)",
- "PEAR": "Poire",
+ "PEAR": "Poire / poirier",
"PEA_EDIBLE_DRY_FOR_GRAIN": "Pois, comestible sec, pour graines",
"PEA_HARVESTED_GREEN": "Pois Verts",
"PECAN_NUT": "Noix de pécan",
"PEPPER_BLACK": "Poivre, noir",
"PEPPER_DRY": "Poivre, sec",
- "PERSIMMON": "Kaki",
+ "PERSIMMON": "Plaqueminier",
"PERSIMMON_KAKI": "Kaki",
"PIGEON_PEA": "Pois d'Angole",
"PINEAPPLE": "Ananas",
@@ -282,7 +282,7 @@
"SAINFOIN": "Sainfoin",
"SALSIFY": "Salsifis",
"SAPODILLA": "Sapotille",
- "SATSUMA_MANDARIN/TANGERINE": "Satsuma (mandarine/tangerine)",
+ "SATSUMA_MANDARIN/TANGERINE": "Satsuma (mandarine / tangerine)",
"SCORZONERA_BLACK_SALSIFY": "Scorsonère salsifis noir",
"SESAME": "Sésame",
"SHEA_BUTTER_NUT": "Noix de Karité",
@@ -314,7 +314,7 @@
"SWEDE_FOR_FODDER": "Rutabaga Fourragère",
"SWEET_CORN": "Maïs Sucré (légume)",
"SWEET_LIME": "Citron vert, Lime",
- "SWEET_PEPPER": "Poivron",
+ "SWEET_PEPPER": "Piment doux",
"SWEET_POTATO": "Patate Douce",
"SWEET_SORGHUM": "Sorgo Commun",
"TANGERINE": "Tangerine",
@@ -341,11 +341,11 @@
"YAM": "Igname",
"YERBA_MATE": "Yerba Maté",
"ABIU": "Abiu",
- "ACAI_PALM": "Palmier Pinot/Açai",
+ "ACAI_PALM": "Palmier Pinot / Açai",
"ACHACHA": "Achacha",
"ALFALFA_SPROUTS": "Germes de Luzerne",
"ALLSPICE": "Piment de la Jamaïque",
- "ALOE_VERA": "Aloe Vera, Aloè",
+ "ALOE_VERA": "Aloe Vera, Aloès",
"AMARANTH": "Amarante",
"ANGICO_VERMELHO": "Parapiptadenia",
"APPLE_BANANA": "Banane Tundan",
@@ -455,7 +455,7 @@
"ROCOTO_PEPPER": "Poivre Rocoto",
"ROSE_APPLE": "Giroflier",
"ROSE_GUM_EUCALYPTUS_EUCALIPTO_GRANDIS": "Gommier Rose (Eucalipto grandis)",
- "ROSELLE": "Oseille de Guinée",
+ "ROSELLE": "Oseille de Guinée / roselle",
"ROSEMARY": "Romarin",
"SABA_NUT_CASTANHA_DO_MARANHÃO": "Marce (Castanha do maranhão)",
"SAFFRON": "Saffran",
@@ -464,7 +464,7 @@
"SCHOTT_MANGARITO": "Macabo, Chou Caraïbe",
"SESSILE_JOYWEED": "Magloire",
"SHEA_TREE": "Arbre de Karité",
- "SOAPBERRY_SABONETEIRA": "Shépherdie du Canada",
+ "SOAPBERRY_SABONETEIRA": "Savonnier / Shépherdie du Canada",
"SORREL": "Oseille",
"SOURSOP": "Corrosol",
"SOUTHERN_BLUE_GUM_EUCALIPTO_GLÓBULUS": "Gommier bleu (Eucalyptus globulus)",
diff --git a/packages/webapp/public/locales/fr/crop_nutrients.json b/packages/webapp/public/locales/fr/crop_nutrients.json
index e074ea53d9..95433e1350 100644
--- a/packages/webapp/public/locales/fr/crop_nutrients.json
+++ b/packages/webapp/public/locales/fr/crop_nutrients.json
@@ -1,6 +1,6 @@
{
"INIT_KC": "Kc Initial",
- "MID_KC":"Kc de Moyen Terme",
+ "MID_KC": "Kc de Moyen Terme",
"END_KC": "Kc Terminal",
"MAX_HEIGHT": "Taille Maximale",
"PROTEIN": "Protéine",
@@ -8,21 +8,21 @@
"ENERGY": "Énergie",
"CALCIUM": "Calcium",
"IRON": "Fer",
- "MAGNESIUM":"Magnésium",
- "PH": "PH",
- "K":"K",
+ "MAGNESIUM": "Magnésium",
+ "PH": "pH",
+ "K": "K",
"NA": "NA",
- "ZINC":"Zinc",
+ "ZINC": "Zinc",
"COPPER": "Cuivre",
"MANGANESE": "Manganèse",
"VITA_RAE": "Vitamine A",
"VITAMIN_C": "Vitamine C",
"THIAMIN": "Thiamine",
- "RIBOFLAVIN":"Riboflavine",
+ "RIBOFLAVIN": "Riboflavine",
"NIACIN": "Niacine",
- "VITAMIN_B6":"Vitamine B6",
+ "VITAMIN_B6": "Vitamine B6",
"FOLATE": "Folate",
- "VITAMIN_B12":"Vitamine B12",
+ "VITAMIN_B12": "Vitamine B12",
"MAX_ROOTING": "Enracinement Maximal",
"NUTRIENT_CREDITS": "Crédits de Nutriments"
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/fr/disease.json b/packages/webapp/public/locales/fr/disease.json
index 1b1a190381..6f32d81f81 100644
--- a/packages/webapp/public/locales/fr/disease.json
+++ b/packages/webapp/public/locales/fr/disease.json
@@ -287,7 +287,6 @@
"EUROPEAN_CORN_BORER": "pyrale du maïs",
"CORN_EARWORM": "Ver de l'épi du maïs",
"JASSIDS_ON_PEANUT": "Jassids sur Peanut",
- "Mealybug": "Cochenille",
"COTTONY_CUSHION_SCALE": "Échelle de coussin en coton",
"MANGO_FRUIT_FLY": "Mouche des fruits de la mangue",
"FLEA_BEETLE" : "altise",
diff --git a/packages/webapp/public/locales/fr/expense.json b/packages/webapp/public/locales/fr/expense.json
index c84554ea68..3a01485599 100644
--- a/packages/webapp/public/locales/fr/expense.json
+++ b/packages/webapp/public/locales/fr/expense.json
@@ -6,5 +6,6 @@
"FUEL": "Carburant",
"LAND": "Terrain",
"SEEDS": "Graines",
- "OTHER": "Autre"
+ "OTHER": "Autre",
+ "SOIL_AMENDMENT": "Amendement de sol"
}
diff --git a/packages/webapp/public/locales/fr/filter.json b/packages/webapp/public/locales/fr/filter.json
index a7db7c8f41..59dc7a1db7 100644
--- a/packages/webapp/public/locales/fr/filter.json
+++ b/packages/webapp/public/locales/fr/filter.json
@@ -13,11 +13,29 @@
"CLEANING_PRODUCT": "Produit Nettoyant",
"CROP_COMPLIANCE": "Conformité de Récolte",
"FERTILIZING_PRODUCT": "Produits Fertilisants",
+ "INVOICES": "Factures",
"OTHER": "Autre",
"PEST_CONTROL_PRODUCT": "Produits Antiparasitaires",
+ "RECEIPTS": "Recettes",
"SOIL_AMENDMENT": "Amendement de Sol",
- "SOIL_SAMPLE_RESULTS": "MISSING",
- "WATER_SAMPLE_RESULTS": "MISSING",
+ "SOIL_SAMPLE_RESULTS": "Résultat de l'échantillon de sol",
+ "WATER_SAMPLE_RESULTS": "Résultat de l'échantillon d'eau",
"UNCATEGORIZED": "Non Classé"
+ },
+ "TASKS": {
+ "LOCATION": "Lieu",
+ "ABANDONED": "Abandonné",
+ "COMPLETED": "Terminé",
+ "FOR_REVIEW": "Pour évaluer",
+ "LATE": "Tard",
+ "PLANNED": "Planifié",
+ "STATUS": "Statut",
+ "SUPPLIERS": "Fournisseurs",
+ "ACTIVE": "Actif"
+ },
+ "FILTER": {
+ "VALID_ON": "Valable le",
+ "FROM_DATE": "De",
+ "TO_DATE": "À"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/fr/message.json b/packages/webapp/public/locales/fr/message.json
index 225bc405fd..9d9f67b58c 100644
--- a/packages/webapp/public/locales/fr/message.json
+++ b/packages/webapp/public/locales/fr/message.json
@@ -1,191 +1,193 @@
{
"ASSIGN_TASK": {
- "ERROR": "MISSING",
- "SUCCESS": "MISSING"
+ "ERROR": "N'a pas réussi à attribuer les tâches",
+ "SUCCESS": "Tâches attribuées avec succès"
},
"ATTACHMENTS": {
"ERROR": {
- "CREATE": "MISSING",
- "FAILED_ARCHIVE": "MISSING",
- "FAILED_UPLOAD": "MISSING",
- "UPDATE": "MISSING"
+ "CREATE": "N'a pas réussi à créer un document",
+ "FAILED_ARCHIVE": "Impossible d'archiver le document",
+ "FAILED_UNARCHIVE": "N'a pas réussi à désarchiver le document",
+ "FAILED_UPLOAD": "Le téléchargement des pièces jointes a échoué",
+ "UPDATE": "La mise à jour a échouée"
},
"SUCCESS": {
- "ARCHIVE": "MISSING",
- "CREATE": "MISSING",
- "UPDATE": "MISSING"
+ "ARCHIVE": "Document archivé avec succès",
+ "CREATE": "Document créé avec succès",
+ "UNARCHIVE": "Document désarchivé avec succès",
+ "UPDATE": "Document mis à jour avec succès"
}
},
- "CROP_VARIETY": {
+ "CROP": {
"ERROR": {
- "ADD": "MISSING",
- "ADD_ALREADY_EXISTS": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "DELETE": "N'a pas réussi à supprimer la grande culture"
},
"SUCCESS": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "DELETE": "Culture supprimée avec succès"
}
},
- "CROP": {
+ "CROP_VARIETY": {
"ERROR": {
- "DELETE": "MISSING"
+ "ADD": "Erreur : échec de l'ajout de la variété à la base de données",
+ "ADD_ALREADY_EXISTS": "Erreur : la variété existe déjà",
+ "DELETE": "Échec de la suppression de la variété de culture",
+ "UPDATE": "Échec de la mise à jour de la variété de culture"
},
"SUCCESS": {
- "DELETE": "MISSING"
+ "ADD": "Variété de culture sauvegardée avec succès !",
+ "DELETE": "Variété de culture supprimée",
+ "UPDATE": "Variété de culture mise à jour avec succès"
}
},
"EXPENSE": {
"ERROR": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Impossible d'ajouter de nouvelles dépenses",
+ "DELETE": "Impossible de supprimer les dépenses",
+ "UPDATE": "Impossible de mettre à jour les dépenses"
},
"SUCCESS": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Nouvelles dépenses ajoutées avec succès !",
+ "DELETE": "Dépenses supprimées avec succès !",
+ "UPDATE": "Dépenses mises à jour avec succès !"
}
},
"FARM": {
"ERROR": {
- "ADD": "MISSING",
- "FETCH": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Impossible d'ajouter une ferme. Veuillez contacter LiteFarm pour obtenir de l'aide",
+ "FETCH": "Impossible de récupérer la ferme à partir de la base de données",
+ "UPDATE": "Impossible de mettre à jour les informations de la ferme"
},
"SUCCESS": {
- "UPDATE": "MISSING"
+ "UPDATE": "Informations sur la ferme mises à jour !"
}
},
"LOG_HARVEST": {
"ERROR": {
- "ADD_USE_TYPE": "Failed to add custom harvest use type",
- "AMOUNT_TOTAL": "MISSING",
- "GET_TYPES": "MISSING"
+ "ADD_USE_TYPE": "Impossible d'ajouter un type d'utilisation de récolte personnalisé",
+ "AMOUNT_TOTAL": "Le total n'est pas égal au montant à allouer",
+ "GET_TYPES": "Impossible de récupérer les types d'utilisation de récolte"
},
"SUCCESS": {
- "ADD_USE_TYPE": "Successfully added custom harvest use type"
+ "ADD_USE_TYPE": "Type d'utilisation de récolte personnalisé ajouté avec succès"
}
},
"LOGIN": {
"ERROR": {
- "LOGIN_FAIL": "MISSING"
+ "LOGIN_FAIL": "Impossible de se connecter aux informations de l'utilisateur"
}
},
"MANAGEMENT_PLAN": {
"ERROR": {
- "ABANDON": "MISSING",
- "COMPLETE": "MISSING",
- "POST": "MISSING"
+ "ABANDON": "Le plan de culture n'est pas abandonné !",
+ "COMPLETE": "Impossible de terminer le plan de culture !",
+ "POST": "Le plan de culture n'est pas ajouté !"
},
"SUCCESS": {
- "ABANDON": "MISSING",
- "COMPLETE": "MISSING",
- "POST": "MISSING"
+ "ABANDON": "Plan de culture abandonné avec succès !",
+ "COMPLETE": "Plan de culture terminé avec succès !",
+ "POST": "Plan de culture ajouté avec succès !"
}
},
"MAP": {
- "FAIL_PATCH": "MISSING",
- "FAIL_POST": "MISSING",
- "SUCCESS_DELETE": "MISSING",
- "SUCCESS_PATCH": "MISSING",
- "SUCCESS_POST": "MISSING"
+ "FAIL_PATCH": "Impossible de mettre à jour",
+ "FAIL_POST": "Impossible d'ajouter",
+ "SUCCESS_DELETE": "Supprimé avec succès",
+ "SUCCESS_PATCH": "Mise à jour réussie",
+ "SUCCESS_POST": "Enregistré avec succès"
},
"ORGANIC_CERTIFIER_SURVEY": {
"ERROR": {
- "CREATE": "MISSING",
- "UPDATE": "MISSING"
+ "CREATE": "Impossible de créer la certification",
+ "UPDATE": "Impossible de mettre à jour la certification"
}
},
"PLAN": {
"ERROR": {
- "EDIT": "MISSING"
+ "EDIT": "Impossible de mettre à jour le plan de culture"
},
"SUCCESS": {
- "EDIT": "MISSING"
+ "EDIT": "Plan de culture mis à jour avec succès"
}
},
"REVENUE": {
"ERROR": {
- "EDIT": "MISSING"
+ "EDIT": "Impossible de mettre à jour le chiffre d'affaires"
},
"SUCCESS": {
- "EDIT": "MISSING"
+ "EDIT": "Chiffre d'affaires mis à jour avec succès"
}
},
"SALE": {
"ERROR": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Impossible d'ajouter la vente",
+ "DELETE": "Impossible de supprimer la vente",
+ "UPDATE": "Impossible de mettre à jour la vente"
},
"SUCCESS": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Vente ajoutée avec succès",
+ "DELETE": "Vente supprimée avec succès",
+ "UPDATE": "Vente mise à jour avec succès"
}
},
"SHIFT": {
"ERROR": {
- "ADD": "MISSING",
- "CROP_FIELDS_EACH": "MISSING",
- "DELETE": "MISSING",
- "DURATION_FOR_CROPS": "MISSING",
- "ONLY_INTEGERS_DURATIONS": "MISSING",
- "REQUIRED_TASK": "MISSING",
- "SUBMIT_SHIFT": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Incapable d'ajouter un nouveau quart de travail",
+ "CROP_FIELDS_EACH": "Veuillez attribuer des cultures ou des champs pour chaque tâche",
+ "DELETE": "Impossible de supprimer le quart de travail",
+ "DURATION_FOR_CROPS": "Veuillez attribuer une durée pour chaque culture",
+ "ONLY_INTEGERS_DURATIONS": "Veuillez n'attribuer des numéros qu'aux durées",
+ "REQUIRED_TASK": "Un nom de tâche est requis",
+ "SUBMIT_SHIFT": "La soumission du quart de travail a échoué; c'est le problème de LiteFarm.",
+ "UPDATE": "Le quart de travail n'est pas mis à jour"
},
"SUCCESS": {
- "ADD": "MISSING",
- "DELETE": "MISSING",
- "UPDATE": "MISSING"
- }
- },
- "TASK_TYPE": {
- "CREATE": {
- "FAILED": "MISSING",
- "SUCCESS": "MISSING"
- },
- "DELETE": {
- "FAILED": "MISSING",
- "SUCCESS": "MISSING"
+ "ADD": "Quart de travail ajouté avec succès !",
+ "DELETE": "Quart de travail supprimé avec succès !",
+ "UPDATE": "Quart de travail mis à jour avec succès "
}
},
"TASK": {
"ABANDON": {
- "FAILED": "MISSING",
- "SUCCESS": "MISSING"
+ "FAILED": "Impossible d'abandonner une tâche",
+ "SUCCESS": "Tâche abandonnée avec succès"
},
"COMPLETE": {
- "FAILED": "MISSING",
- "SUCCESS": "MISSING"
+ "FAILED": "Impossible de compléter une tâche",
+ "SUCCESS": "Tâche complétée avec succès "
},
"CREATE": {
- "FAILED": "MISSING",
- "SUCCESS": "MISSING"
+ "FAILED": "Impossible de créer une tâche",
+ "SUCCESS": "Tâche créée avec succès"
+ }
+ },
+ "TASK_TYPE": {
+ "CREATE": {
+ "FAILED": "Impossible de créer une tâche personnalisée",
+ "SUCCESS": "Tâche personnalisée créée avec succès"
+ },
+ "DELETE": {
+ "FAILED": "Impossible de supprimer une tâche personnalisée",
+ "SUCCESS": "Tâche personnalisée supprimée avec succès"
}
},
"USER": {
"ERROR": {
- "ADD": "MISSING",
- "AGREEMENT": "MISSING",
- "EXISTS": "MISSING",
- "INVITE": "MISSING",
- "NOTHING_CHANGED": "MISSING",
- "RESET_PASSWORD": "MISSING",
- "RESTORE": "MISSING",
- "REVOKE": "MISSING",
- "SIGNUP_UNKNOWN": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "Impossible d'ajouter l'utilisateur",
+ "AGREEMENT": "Impossible de mettre à jour le contrat d'utilisation",
+ "EXISTS": "L'utilisateur existe déjà dans le réseau LiteFarm",
+ "INVITE": "Erreur lors de la création du compte utilisateur; veuillez contacter LiteFarm pour obtenir de l'aide",
+ "NOTHING_CHANGED": "Aucune donnée n'a changé",
+ "RESET_PASSWORD": "Il y a un problème avec la réinitialisation du mot de passe par courriel; veuillez contacter LiteFarm pour obtenir de l'aide.",
+ "RESTORE": "Une erreur s'est produite lors de la restauration de l'accès",
+ "REVOKE": "Une erreur s'est produite lors de la révocation de l'accès",
+ "SIGNUP_UNKNOWN": "Problème inconnu ! Réessayez plus tard.",
+ "UPDATE": "Impossible de mettre à jour les informations utilisateur"
},
"SUCCESS": {
- "ADD": "MISSING",
- "RESTORE": "MISSING",
- "REVOKE": "MISSING",
- "UPDATE": "MISSING"
+ "ADD": "L'utilisateur a bien été ajouté à la ferme !",
+ "RESTORE": "Accès utilisateur restauré",
+ "REVOKE": "Accès utilisateur révoqué",
+ "UPDATE": "Informations de l'utilisateur mises à jour avec succès !"
}
}
}
diff --git a/packages/webapp/public/locales/fr/translation.json b/packages/webapp/public/locales/fr/translation.json
index 74243d2187..dd1bc8c185 100644
--- a/packages/webapp/public/locales/fr/translation.json
+++ b/packages/webapp/public/locales/fr/translation.json
@@ -1,14 +1,15 @@
{
"ADD_FARM": {
"ADDRESS_IS_REQUIRED": "Address civique est requise",
- "DISABLE_GEO_LOCATION": "MISSING",
+ "DISABLE_GEO_LOCATION": "Les services de localisation doivent être activés pour trouver votre position actuelle",
"ENTER_A_VALID_ADDRESS": "Veuillez enregistrer une adresse valide ou coordonée",
"ENTER_LOCATION_PLACEHOLDER": "Entrer votre region",
"FARM_IS_REQUIRED": "Nom de la ferme est requise",
"FARM_LOCATION": "Endroit de la ferme",
"FARM_LOCATION_INPUT_INFO": "Address civique ou latitude et longitude séparées par des virgules (e.g. 49.250945, -123.238492)",
"FARM_NAME": "Nom de la ferme",
- "INVALID_FARM_LOCATION": "Endroit de la ferme invalide",
+ "FARM_NAME_ERROR": "Limite de caractères dépassée pour le nom de la ferme",
+ "INVALID_FARM_LOCATION": "Aucun pays pour cet emplacement",
"LOCATING": "Localisation...",
"NO_ADDRESS": "Emplacement entré n'a pas été trouvé! Veuillez essayer d'entrer la longitude et la latitude",
"TELL_US_ABOUT_YOUR_FARM": "Parlez-nous de votre ferme"
@@ -23,15 +24,16 @@
"ADD_A_CUSTOM_TASK": "Ajouter une tâche personnalisée",
"ADD_A_TASK": "Ajouter une tâche",
"ADD_CUSTOM_TASK": "Ajouter une tâche personnalisée",
- "AFFECT_PLANS": "Cette tâche affectera-t-elle les plans ?",
+ "AFFECT_PLANS": "Cette tâche affectera-t-elle les plans\u00a0?",
"ASSIGN_ALL_TO_PERSON": "Attribuez toutes les tâches non assignées à cette date à cette personne",
+ "ASSIGN_DATE": "Attribuer une date d'échéance",
"ASSIGN_TASK": "Attribuer une tâche",
- "ASSIGNEE": "Destinataire",
+ "ASSIGNEE": "Personne responsable",
"CANCEL": "création de tâches",
"CLEANING_VIEW": {
"ESTIMATED_WATER": "Consommation d'eau estimée",
"IS_PERMITTED": "Le produit de nettoyage est-il dans la liste des substances autorisées ?",
- "WHAT_NEEDS_TO_BE": "Que faut-il nettoyer ?",
+ "WHAT_NEEDS_TO_BE": "Que faut-il nettoyer\u00a0?",
"WILL_CLEANER_BE_USED": "Un agent nettoyant ou désinfectant sera-t-il utilisé ?"
},
"CLEAR_ALL": "Tout effacer",
@@ -40,179 +42,179 @@
"CUSTOM_TASK_CHAR_LIMIT": "Le nom du type de tâche personnalisée ne peut pas dépasser 25 caractères",
"CUSTOM_TASK_NAME": "Nom de la tâche personnalisée",
"CUSTOM_TASK_TYPE": "Type de tâche personnalisée",
- "DO_YOU_NEED_TO_OVERRIDE": "Avez-vous besoin de remplacer le salaire des employés pour cette tâche ?",
- "DO_YOU_WANT_TO_ASSIGN": "Souhaitez-vous affecter la tâche maintenant ?",
+ "DO_YOU_NEED_TO_OVERRIDE": "Avez-vous besoin de changer le salaire des employés pour cette tâche\u00a0?",
+ "DO_YOU_WANT_TO_ASSIGN": "Souhaitez-vous affecter la tâche maintenant\u00a0?",
"EDIT_CUSTOM_TASK": "Modifier la tâche personnalisée",
"FIELD_WORK_VIEW": {
"OTHER_TYPE_OF_FIELD_WORK": "Décrivez le type de travail sur le terrain",
- "TYPE_OF_FIELD_WORK": "Type de travail sur le terrain",
"TYPE": {
"COVERING_SOIL": "Terre de couverture",
"FENCING": "Cloturation",
"OTHER": "Autre",
- "PREPARING_BEDS_OR_ROWS": "Preparage des lits ou rangs",
+ "PREPARING_BEDS_OR_ROWS": "Preparage des plates-bandes ou rangs",
"PRUNING": "Émondage",
"SHADE_CLOTH": "Toile à ombrer",
"TERMINATION": "Terminage",
"TILLAGE": "Labourage",
"WEEDING": "Désherbage"
- }
+ },
+ "TYPE_OF_FIELD_WORK": "Type de travail sur le terrain"
},
"GO_TO_CATALOGUE": "Aller au catalogue de cultures",
- "HARVEST_EVERYTHING": "Récoltez tout ce qui est prêt",
+ "HARVEST_EVERYTHING": "Récolter tout ce qui est prêt",
"HARVESTING_INFO": "Chaque plan générera une tâche de récolte individuelle",
"HOW_MUCH_IS_HARVESTED": "Combien est récolté ?",
"HR": "/h",
"MANAGE_CUSTOM_TASKS": "Gérer les tâches personnalisées",
- "NEED_MANAGEMENT_PLAN": "MISSING",
- "NO_MANAGEMENT_PLAN": "MISSING",
+ "NEED_MANAGEMENT_PLAN": "Vous aurez besoin d'un plan de culture actif ou planifié avant de pouvoir programmer une tâche de récolte ou une tâche de transplantation. Accédez au catalogue de cultures pour créer un plan maintenant.",
+ "NO_MANAGEMENT_PLAN": "Aucun plan de culture éligible",
"PEST_CONTROL_VIEW": {
"BIOLOGICAL_CONTROL": "Contrôle biologique",
"FLAME_WEEDING": "Sarclage à la flamme",
"FOLIAR_SPRAY": "Spray foliaire",
"HAND_WEEDING": "Sarclage à la main",
"HEAT_TREATMENT": "Taille",
- "IS_PERMITTED": "L'agent nuisible est-il dans la liste des substances autorisées ?",
- "OTHER": "MISSING",
+ "IS_PERMITTED": "L'agent nuisible est-il dans la liste des substances autorisées\u00a0?",
+ "OTHER": "Autre",
"OTHER_PEST": "Autre méthode",
"PEST_CONTROL_METHOD": "Méthode de lutte antiparasitaire",
"SOIL_FUMIGATION": "Fumigation du sol",
"SYSTEMIC_SPRAY": "Pulvérisation systémique",
"WHAT_PESTS": "Quels parasites essayez-vous de contrôler"
},
- "PLANTING_FROM": "MISSING",
+ "PLANTING_FROM": "Planter à partir de",
"PLANTING_METHOD": "Méthode de plantation",
- "PLANTING_STOCK": "MISSING",
+ "PLANTING_STOCK": "Matériel de plantation",
"PLANTING_TASK": "Tâche de plantation",
"PLANTING_TASK_MODAL": "Démarrer une nouvelle tâche de plantation crée un nouveau plan de gestion. Accédez au catalogue des cultures pour sélectionner la culture que vous souhaitez planter.",
- "QUANTITY": "MISSING",
- "RETIRE_CUSTOM_TASK": "Retirer la tâche personnalisée ?",
- "RETIRE_CUSTOM_TASK_CONTENT": "Voulez-vous vraiment supprimer cette tâche personnalisée ?",
- "SEED": "MISSING",
+ "QUANTITY": "Quantité",
+ "RETIRE_CUSTOM_TASK": "Retirer la tâche personnalisée\u00a0?",
+ "RETIRE_CUSTOM_TASK_CONTENT": "Voulez-vous vraiment supprimer cette tâche personnalisée\u00a0?",
+ "SEED": "Semer",
"SELECT_ALL": "Tout sélectionner",
"SELECT_ALL_PLANS": "Sélectionner tous les forfaits",
"SELECT_TASK_TYPE": "Sélectionnez le type de tâche",
"SOIL_AMENDMENT_VIEW": {
- "IS_PERMITTED": "L'amendement du sol est-il dans la liste des substances autorisées ?",
+ "IS_PERMITTED": "L'amendement du sol est-il dans la liste des substances autorisées\u00a0?",
"MOISTURE_RETENTION": "Rétention d'humidité",
"NUTRIENT_AVAILABILITY": "Disponibilité des nutriments",
- "OTHER": "MISSING",
+ "OTHER": "Autre",
"OTHER_PURPOSE": "Décrivez le but",
"PH": "pH",
"PURPOSE": "Objectif",
"STRUCTURE": "Structure"
},
- "TASK": "tache",
+ "TASK": "tâche",
"TASK_NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
"TELL_US_ABOUT_YOUR_TASK_TYPE_ONE": "Parlez-nous de",
"TRANSPLANT_METHOD": "Méthode de transplantation",
"WAGE_OVERRIDE": "Dérogation de salaire",
- "WHAT_PLANTING_METHOD": "Quelle est la méthode de repiquage ?",
- "WILD_CROP": "MISSING"
+ "WHAT_PLANTING_METHOD": "Quelle est la méthode de repiquage\u00a0?",
+ "WILD_CROP": "Cultures sauvages"
},
"BED_PLAN": {
- "LENGTH_OF_BED": "Longueur des lits",
- "NUMBER_0F_BEDS": "# de lits",
- "NUMBER_OF_ROWS": "# de lignes dans le lit",
+ "LENGTH_OF_BED": "Longueur des plates-bandes",
+ "NUMBER_0F_BEDS": "# de plates-bandes",
+ "NUMBER_OF_ROWS": "# de lignes dans le plate-bande",
"PLANT_SPACING": "Espacement des plantes",
"PLANTING_DETAILS": "Veuillez spécifier les détails de la plantation"
},
"BROADCAST_PLAN": {
"AREA_USED": "Zone utilisée",
- "HISTORICAL_PERCENTAGE_LOCATION": "Quel pourcentage de l'emplacement a été planté ?",
+ "HISTORICAL_PERCENTAGE_LOCATION": "Quel pourcentage de l'emplacement a été planté\u00a0?",
"LOCATION_SIZE": "Taille de l'emplacement",
"PERCENTAGE_LABEL": "% de l'emplacement",
- "PERCENTAGE_LOCATION": "Quel pourcentage de l'emplacement plantez-vous ?",
+ "PERCENTAGE_LOCATION": "Quel pourcentage de l'emplacement plantez-vous\u00a0?",
"PLANTING_NOTES": "Notes de plantation",
"SEEDING_RATE": "Taux de semis"
},
"CANCEL_FLOW_MODAL": {
- "BODY": "Toutes les informations que vous avez saisies seront supprimées. Voulez-vous continuer ?",
- "TITLE": "Annuler votre {{flow}} ?"
+ "BODY": "Toutes les informations que vous avez saisies seront supprimées. Voulez-vous continuer\u00a0?",
+ "TITLE": "Annuler votre {{flow}}\u00a0?"
},
"CERTIFICATION": {
"CERTIFICATION_EXPORT": {
- "ADD": "MISSING",
+ "ADD": "Ajouter",
"CHANGE_CERTIFICATION_PREFERENCE": "modifier vos préférences de certification",
"CHANGE_CERTIFICATION_PREFERENCE_CAPITAL": "Modifier vos préférences de certification",
"NO_CERTIFICATIONS": "Vous ne poursuivez actuellement aucune certification.",
- "NO_LONGER_WORKING": "Vous ne poursuivez plus cette certification ou ne travaillez plus avec ce certificateur ? Pas de problème !",
- "SUPPORTED_CERTIFICATION_ONE": "Vous poursuivez ",
- "SUPPORTED_CERTIFICATION_TWO": " certification de :",
+ "NO_LONGER_WORKING": "Vous n'essayez plus d'obtenir cette certification, ou ne travailles plus avec cette organization\u00a0? Pas de problème\u00a0!",
+ "SUPPORTED_CERTIFICATION_ONE": "Vous êtes en train d'obtenir votre certification",
+ "SUPPORTED_CERTIFICATION_TWO": "de\u00a0:",
"UNSUPPORTED_CERTIFICATION_MESSAGE_ONE": "LiteFarm ne génère actuellement pas de documents pour ce certificateur. Cependant, nous pouvons exporter des formulaires génériques utiles pour la plupart des certificateurs. Vous pouvez sélectionner Exporter pour créer ces formulaires ou",
- "UNSUPPORTED_CERTIFICATION_MESSAGE_TWO": "pour voir s'il y a de nouveaux certificateurs disponibles dans votre région.",
+ "UNSUPPORTED_CERTIFICATION_MESSAGE_TWO": "tour voir s'il y a de nouveaux certificateurs disponibles dans votre région.",
"UNSUPPORTED_CERTIFICATION_REQUEST_ONE": "Vous avez demandé",
- "UNSUPPORTED_CERTIFICATION_REQUEST_TWO": "certification de",
+ "UNSUPPORTED_CERTIFICATION_REQUEST_TWO": "Certification de",
"UPDATE_SUCCESS": "Préférences de certification enregistrées"
},
"CERTIFICATION_SELECTION": {
"REQUEST_CERTIFICATION": "Demander un autre type de certification",
- "SUBTITLE_ONE": "Voici une liste de",
+ "SUBTITLE_ONE": "Voici une liste de certificateurs",
"SUBTITLE_TWO": "les certificateurs avec lesquels nous travaillons dans votre pays.",
- "TITLE": "Quel type de certification ?",
+ "TITLE": "Quel type de certification\u00a0?",
"TOOLTIP": "Vous ne voyez pas votre certification ? LiteFarm se consacre au soutien de l'agriculture durable et les certifications en sont une grande partie. Demandez une autre certification ici et nous ferons de notre mieux pour l'intégrer dans l'application."
},
"CERTIFIER_SELECTION": {
- "INFO": "Cela signifie probablement que LiteFarm ne fonctionne pas actuellement avec votre certificateur - désolé! Pourtant, LiteFarm produit des formulaires génériques qui sont utiles dans la plupart des cas.",
- "NOT_FOUND": "Vous ne voyez pas votre certificateur ?",
+ "INFO": "Cela signifie probablement que LiteFarm ne fonctionne pas actuellement avec votre certificateur - désolé! Cependant, LiteFarm peut générer un formulaire générique qui est utile pour la certification dans la plupart des cas.",
+ "NOT_FOUND": "Vous ne voyez pas votre certificateur\u00a0?",
"REQUEST_CERTIFIER": "Demander un certificateur",
- "TITLE": "Qui est votre certificateur ?"
+ "TITLE": "De quelle organization obtenez-vous votre certification\u00a0?"
},
"INPUT_PLACEHOLDER": "Tapez pour rechercher",
"INTERESTED_IN_CERTIFICATION": {
- "PARAGRAPH": "Prévoyez-vous de poursuivre ou de renouveler une certification cette saison ?",
- "TITLE": "Intéressé par les certifications ?",
+ "PARAGRAPH": "Prévoyez-vous obtenir ou renouveler votre certification pour la saison\u00a0?",
+ "TITLE": "Préférences de certification",
"WHY_ANSWER": "LiteFarm génère les documents requis pour la certification biologique. Certaines informations seront obligatoires."
},
"REQUEST_CERTIFIER": {
"LABEL": "Certificateur demandé",
"REQUEST": "Quel certificateur souhaitez-vous demander ?",
"SORRY_ONE": "Nous sommes désolés - nous ne travaillons actuellement avec aucun certificateur",
- "SORRY_THREE": "certificateurs dans votre pays. Désirez-vous ajouter une certification ?",
- "SORRY_TWO": "certificateurs. Désirez-vous ajouter une certification ?",
+ "SORRY_THREE": "certificateurs dans votre pays. Désirez-vous ajouter une certification\u00a0?",
+ "SORRY_TWO": "certificateurs. Désirez-vous ajouter une certification\u00a0?",
"TITLE": "Demander l'addition d'un certificateur"
},
"SUMMARY": {
"BAD_NEWS": "LiteFarm ne collecte actuellement pas les informations dont vous avez besoin pour générer vos documents de certification - désolé!",
- "BAD_NEWS_INFO": "Cependant, nous pouvons créer des formulaires génériques qui sont utiles pour la plupart des certificateurs. Nous indiquerons ces informations dans toute l'application avec une icône de la feuille.",
+ "BAD_NEWS_INFO": "Cependant, nous pouvons créer des formulaires génériques qui sont utiles pour la plupart des certificateurs. Nous indiquerons ces informations tout au long avec une icône de feuille.",
"CERTIFICATION": "certification",
- "GOOD_NEWS": "Bonne nouvelle ! LiteFarm peut rassembler les informations dont vous avez besoin pour générer vos documents de certification !",
- "INFORMATION": "Nous indiquerons ces informations dans toute l'application avec une icône de la feuille.",
+ "GOOD_NEWS": "Bonne nouvelle\u00a0! LiteFarm peut rassembler les informations dont vous avez besoin pour générer vos documents de certification\u00a0!",
+ "INFORMATION": "Nous indiquerons ces informations tout au long avec une icône de feuille.",
"TITLE": "Vous êtes intéressé à postuler pour:",
"YOUR_CERTIFICATION": "Votre certification"
}
},
+ "CERTIFICATIONS": {
+ "COULD_NOT_CONTACT_CERTIFIER": "Il semble que LiteFarm n'exporte pas actuellement au format de votre certificateur. Vous pouvez toujours exporter vos documents mais votre certificateur peut avoir besoin d'informations supplémentaires. Nous vous les enverrons à\u00a0:",
+ "EMAIL": "Adresse courriel",
+ "EMAIL_ERROR": "Adresse courriel valide requis",
+ "EXPORT": "Exporter",
+ "EXPORT_DOCS": "Exporter les documents de certification",
+ "EXPORT_DOWNLOADING_MESSAGE": "Téléchargement de vos dossiers de certification biologique ...",
+ "EXPORT_FILE_TITLE": "Certification biologique",
+ "FILES_ARE_READY": "Vos fichiers de certification sont maintenant prêts à être exportés. Nous vous les enverrons à\u00a0:",
+ "FLOW_TITLE": "export des documents de certification",
+ "GOOD_NEWS": "Bonne nouvelle\u00a0!",
+ "HAVE_ALL_INFO": "Il semble que LiteFarm dispose de toutes les informations dont nous avons besoin pour traiter vos documents de certification. Nous vous les enverrons à\u00a0:",
+ "NEXT_WE_WILL_CHECK": "Nous vérifierons ensuite si votre certificateur a besoin d'informations supplémentaires pour traiter votre soumission de certification.",
+ "NOTE_CANNOT_RESUBMIT": "Remarque\u00a0: Une fois l'enquête envoyée, vous ne pourrez plus modifier vos réponses. Pour les modifier après l'envoi, commencez une nouvelle exportation.",
+ "ORGANIC_CERTIFICATION_FROM": "Certification biologique de",
+ "SELECT_REPORTING_PERIOD": "Sélectionnez votre période de rapport",
+ "UH_OH": "Oups !",
+ "WHERE_TO_SEND_DOCS": "Où voulez-vous que vos documents soient envoyés ?",
+ "WOULD_LIKE_ANSWERS": "Votre certificateur aimerait que vous répondiez à quelques questions supplémentaires avant que nous puissions exporter vos documents."
+ },
"CERTIFICATIONS_MODAL": {
"MAYBE_LATER": "Peut-être plus tard",
"STEP_ONE": {
- "DESCRIPTION": "Nous avons ajouté des outils d'assistance pour les certifications et les certificateurs ! Voulez-vouz voir ce qui est disponible dans votre région ?",
+ "DESCRIPTION": "Nous avons ajouté des outils d'assistance pour les certifications et les certificateurs\u00a0! Voulez-vouz voir ce qui est disponible dans votre région\u00a0?",
"TITLE": "Nouvelle fonctionnalité!"
},
"STEP_TWO": {
- "DESCRIPTION": "Pas de problème ! Vous pouvez ajouter les certifications et les certificateurs plus tard sous la section « Ma Ferme ».",
+ "DESCRIPTION": "Pas de problème ! Vous pouvez ajouter les certifications et les certificateurs plus tard sous la section «\u00a0Ma Ferme\u00a0».",
"TITLE": "Affichage des certifications"
}
},
- "CERTIFICATIONS": {
- "COULD_NOT_CONTACT_CERTIFIER": "Il semble que LiteFarm n'exporte pas actuellement au format de votre certificateur. Vous pouvez toujours exporter vos documents mais votre certificateur peut avoir besoin d'informations supplémentaires. Nous vous les enverrons à :",
- "EXPORT": "MISSING",
- "EXPORT_DOCS": "Exporter les documents de certification",
- "EXPORT_DOWNLOADING_MESSAGE": "MISSING",
- "EXPORT_FILE_TITLE": "MISSING",
- "FILES_ARE_READY": "Vos fichiers de certification sont maintenant prêts à être exportés. Nous vous les enverrons à :",
- "FLOW_TITLE": "export des documents de certification",
- "GOOD_NEWS": "Bonne nouvelle !",
- "HAVE_ALL_INFO": "Il semble que LiteFarm dispose de toutes les informations dont nous avons besoin pour traiter vos documents de certification. Nous vous les enverrons à :",
- "NEXT_WE_WILL_CHECK": "Nous vérifierons ensuite si votre certificateur a besoin d'informations supplémentaires pour traiter votre soumission de certification.",
- "NOTE_CANNOT_RESUBMIT": "Remarque : Une fois l'enquête envoyée, vous ne pourrez plus modifier vos réponses. Pour les modifier après l'envoi, commencez une nouvelle exportation.",
- "ORGANIC_CERTIFICATION_FROM": "Certification biologique de",
- "SELECT_REPORTING_PERIOD": "Sélectionnez votre période de rapport",
- "UH_OH": "Oups !",
- "WOULD_LIKE_ANSWERS": "Votre certificateur aimerait que vous répondiez à quelques questions supplémentaires avant que nous puissions exporter vos documents.",
- "EMAIL": "MISSING",
- "EMAIL_ERROR": "MISSING",
- "WHERE_TO_SEND_DOCS": "MISSING"
- },
"CHOOSE_FARM": {
"ADD_NEW": "Ajouter une nouvelle ferme",
"CHOOSE_TITLE": "Choisissez votre ferme",
@@ -221,14 +223,14 @@
},
"COMMON_ERRORS": {
"UNIT": {
- "NON_NEGATIVE": "MISSING",
- "REQUIRED": "MISSING",
- "TWO_DECIMALS": "MISSING"
+ "NON_NEGATIVE": "Doit être un nombre non négatif",
+ "REQUIRED": "Réponse requise",
+ "TWO_DECIMALS": "La quantité doit être jusqu'à 2 décimales"
}
},
"CONSENT": {
"DATA_POLICY": "Notre politique de données",
- "LABEL": "Je suis d'accord"
+ "LABEL": "Accepter"
},
"CREATE_USER": {
"BIRTH_YEAR": "Année de naissance",
@@ -237,59 +239,82 @@
"CREATE_BUTTON": "Créer un compte",
"EMAIL": "Addresse courriel",
"FULL_NAME": "Nom complet",
- "GENDER": "MISSING",
+ "GENDER": "Genre",
"GENDER_TOOLTIP": "Les informations sur le genre sont collectées à des fins de recherche uniquement et ne seront partagées qu'avec les informations d'identification personnelle supprimées",
- "PASSWORD": "MISSING",
+ "PASSWORD": "Mot de passe",
"TITLE": "Créer un nouveau compte utilisateur"
},
+ "CROP": {
+ "ADD_COMPLIANCE_FILE": "Lien vers un dossier de conformité",
+ "ADD_CROP": "Ajouter une culture",
+ "ADD_IMAGE": "Ajouter une image personnalisée",
+ "ANNUAL": "Annuelle",
+ "ANNUAL_OR_PERENNIAL": "La culture est-elle annuelle ou vivace\u00a0?",
+ "EDIT_CROP": "Modifier la culture",
+ "EDIT_MODAL": {
+ "BODY": "La modification de cette culture ne modifiera aucun plan de gestion des cultures existant. Seuls les plans de gestion créés après vos modifications seront impactés. Procéder à la modification\u00a0?",
+ "TITLE": "Modifier la culture\u00a0?"
+ },
+ "IS_GENETICALLY_ENGINEERED": "La culture est-elle génétiquement modifiée\u00a0?",
+ "IS_ORGANIC": "La semence ou la culture est-elle certifiée biologique ?",
+ "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Votre certificateur peut demander des documents à l'appui de votre affirmation que cette culture n'est pas génétiquement modifiée.",
+ "NEED_DOCUMENT_PERFORM_SEARCH": "Votre certificateur peut demander des documents à l'appui de votre recherche.",
+ "NEED_DOCUMENT_TREATED": "Votre certificateur peut demander des documents décrivant les traitements.",
+ "NUTRIENTS_IN_EDIBLE_PORTION": "Nutriments dans la portion comestible (pour 100g)",
+ "PERENNIAL": "Vivace",
+ "PERFORM_SEARCH": "Avez-vous effectué une recherche de disponibilité commerciale\u00a0?",
+ "PHYSIOLOGY_AND_ANATOMY": "Physiologie et anatomie",
+ "TREATED": "Les semences de cette culture ont-elles été traitées ?",
+ "UPLOAD_LATER": "Vous pouvez également télécharger des fichiers plus tard"
+ },
"CROP_CATALOGUE": {
- "ADD_CROP": "Ajoutez un nouveau recadrage",
- "ADD_CROPS_T0_YOUR_FARM": "Ajoutez des cultures à votre ferme",
+ "ADD_CROP": "Ajoutez une nouvelle culture",
+ "ADD_CROPS_T0_YOUR_FARM": "Ajouter des cultures à votre ferme",
"ADD_TO_YOUR_FARM": "Ajouter à votre ferme",
"CAN_NOT_FIND": "Vous ne trouvez pas ce que vous cherchez ?",
- "COVER_CROP": "Est-ce que cela peut être cultivé comme plante de couverture ?",
+ "COVER_CROP": "Est-ce que cela peut être cultivé comme plante de couverture\u00a0?",
"CREATE_MANAGEMENT_PLANS": "Créer des plans de gestion",
"CROP_CATALOGUE": "Catalogue des cultures",
"CROP_GROUP": "Recadrer le groupe",
- "CROP_GROUP_TOOL_TIP": "La sélection d’un groupe de cultures permet à LiteFarm de précompléter de nombreuses informations sur cette culture, telles que la saison de croissance, les valeurs nutritionnelles et le rendement estimé. Ne vous inquiétez pas: vous pouvez modifier ces valeurs ci-dessous une fois que vous avez sélectionné un groupe de cultures.",
- "DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Document des informations nécessaires pour la production biologique",
+ "CROP_GROUP_TOOL_TIP": "La sélection d'un groupe de cultures permet à LiteFarm de précompléter de nombreuses informations sur cette culture, telles que la saison de croissance, les valeurs nutritionnelles et le rendement estimé. Ne vous inquiétez pas: vous pouvez modifier ces valeurs ci-dessous une fois que vous avez sélectionné un groupe de cultures.",
+ "CROP_STATUS": "État de la culture sur :",
+ "DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Documenter des informations nécessaires pour la production biologique",
"FILTER": {
- "LOCATION": "MISSING",
- "STATUS": "MISSING",
- "SUPPLIERS": "MISSING",
+ "LOCATION": "Emplacement",
+ "STATUS": "Status",
+ "SUPPLIERS": "Fournisseur",
"TITLE": "Filtre de catalogue de cultures"
},
- "HERE_YOU_CAN": "Ici, vous pouvez :",
+ "FILTER_TITLE": "Recadrer le filtre du catalogue",
+ "HERE_YOU_CAN": "Ici, vous pouvez\u00a0:",
"LETS_BEGIN": "Commencer",
- "NEW_CROP_NAME": "MISSING",
+ "NEW_CROP_NAME": "Nouveau nom de culture",
"NO_RESULTS_FOUND": "Aucun résultat trouvé. Veuillez modifier vos filtres.",
"ON_YOUR_FARM": "Sur votre ferme",
- "SELECT_A_CROP": "Sélectionnez une culture pour l'ajouter à votre ferme. Utilisez la recherche et les filtres pour trouver les récoltes plus rapidement.",
- "CROP_STATUS": "MISSING",
- "FILTER_TITLE": "Recadrer le filtre du catalogue"
+ "SELECT_A_CROP": "Sélectionnez une culture pour l'ajouter à votre ferme. Utilisez la recherche et les filtres pour trouver les récoltes plus rapidement."
},
"CROP_DETAIL": {
"ADD_PLAN": "Ajouter un plan",
- "ANNUAL": "MISSING",
- "ANNUAL_PERENNIAL": "La culture est-elle annuelle ou pérenne ?",
- "COMMERCIAL_AVAILABILITY": "Avez-vous effectué une recherche de disponibilité commerciale ?",
+ "ANNUAL": "Annuel",
+ "ANNUAL_PERENNIAL": "La culture est-elle annuelle ou pérenne\u00a0?",
+ "COMMERCIAL_AVAILABILITY": "Avez-vous effectué une recherche de disponibilité commerciale\u00a0?",
"DETAIL_TAB": "Détails",
"EDIT_CROP_DETAIL": "Modifier les détails de la culture",
- "GENETICALLY_ENGINEERED": "Cette culture est-elle génétiquement modifiée ?",
- "HS_CODE": "MISSING",
+ "GENETICALLY_ENGINEERED": "Cette culture est-elle génétiquement modifiée\u00a0?",
+ "HS_CODE": "Code SH",
"MANAGEMENT_PLANS": "Plans de gestion",
"MANAGEMENT_TAB": "Gestion",
"ORGANIC": "La semence ou la culture est-elle certifiée biologique ?",
+ "ORGANIC_COMPLIANCE": "Conformité organique",
"PERENNIAL": "vivace",
- "TREATED": "MISSING",
- "ORGANIC_COMPLIANCE": "Conformité organique"
+ "TREATED": "Les semences de cette culture ont-elles été traitées?"
},
"CROP_MANAGEMENT": {
- "GERMINATE": "MISSING",
- "HARVEST": "MISSING",
- "PLANT": "MISSING",
- "SEED": "MISSING",
- "TERMINATE": "MISSING",
+ "GERMINATE": "Germer",
+ "HARVEST": "Récolte",
+ "PLANT": "Planter",
+ "SEED": "Semer",
+ "TERMINATE": "Terminer",
"TRANSPLANT": "Transplanter"
},
"CROP_VARIETIES": {
@@ -297,48 +322,27 @@
"CROP_VARIETIES": "variété",
"NEEDS_PLAN": "Planning requis",
"RETIRE": {
- "CONFIRMATION": "Retirer cette culture la supprimera ainsi que tous ses plans de gestion de votre catalogue de cultures. Voulez-vous continuer ?",
- "RETIRE_CROP_TITLE": "Retirer la récolte ?",
+ "CONFIRMATION": "Retirer cette culture la supprimera ainsi que tous ses plans de gestion de votre catalogue de cultures. Voulez-vous continuer\u00a0?",
+ "RETIRE_CROP_TITLE": "Retirer la récolte\u00a0?",
"UNABLE_TO_RETIRE": "Vous ne pouvez retirer que des cultures qui n'ont aucun plan de gestion actif ou futur. Vous devrez terminer ou abandonner ces plans pour retirer cette culture",
"UNABLE_TO_RETIRE_TITLE": "Impossible de prendre sa retraite"
},
- "SUPPLIER": "MISSING"
- },
- "CROP": {
- "ADD_CROP": "Ajouter un recadrage",
- "ADD_IMAGE": "Ajouter une image personnalisée",
- "ANNUAL": "MISSING",
- "ANNUAL_OR_PERENNIAL": "La culture est-elle annuelle ou pérenne ?",
- "EDIT_CROP": "Modifier le recadrage",
- "EDIT_MODAL": {
- "BODY": "La modification de cette culture ne modifiera aucun plan de gestion des cultures existant. Seuls les plans de gestion créés après vos modifications seront impactés. Procéder à la modification ?",
- "TITLE": "Modifier le recadrage ?"
- },
- "IS_GENETICALLY_ENGINEERED": "La culture est-elle génétiquement modifiée ?",
- "IS_ORGANIC": "La semence ou la culture est-elle certifiée biologique ?",
- "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Votre certificateur peut demander des documents à l'appui de votre affirmation que cette culture n'est pas génétiquement modifiée.",
- "NEED_DOCUMENT_PERFORM_SEARCH": "Votre certificateur peut demander des documents à l'appui de votre recherche.",
- "NEED_DOCUMENT_TREATED": "Votre certificateur peut demander des documents décrivant les traitements.",
- "NUTRIENTS_IN_EDIBLE_PORTION": "Nutriments dans la portion comestible (pour 100g)",
- "PERENNIAL": "vivace",
- "PERFORM_SEARCH": "Avez-vous effectué une recherche de disponibilité commerciale ?",
- "PHYSIOLOGY_AND_ANATOMY": "Physiologie et anatomie",
- "TREATED": "MISSING",
- "ADD_COMPLIANCE_FILE": "MISSING",
- "UPLOAD_LATER": "MISSING"
- },
- "DATE_RANGE_PICKER": {
- "FROM": "MISSING",
- "TO": "MISSING",
- "TO_MUST_BE_AFTER_FROM": "MISSING"
+ "SUPPLIER": "Fournisseur"
},
"DATE_RANGE": {
"HELP_BODY": "Sélectionnez la plage de dates pour créer un rapport financier pour votre ferme pour une fenêtre de temps donnée.",
"HELP_TITLE": "Aide sur la plage de dates",
- "TITLE": "Filtrer le rapport par date"
+ "TITLE": "Filtrer le rapport par date",
+ "INVALID_RANGE_MESSAGE": "La date 'De' doit précéder la date 'À' pour retourner des résultats"
+ },
+ "DATE_RANGE_PICKER": {
+ "FROM": "De",
+ "TO": "À",
+ "TO_MUST_BE_AFTER_FROM": "La date 'De' doit précéder la date 'À'",
+ "REVENUE_HELP_TITLE": "Aide sur la plage de dates",
+ "REVENUE_HELP_BODY": "Seuls les plans pour lesquels une tâche est prévue ou terminée dans la plage de dates indiquée s'afficheront."
},
"DOCUMENTS": {
- "ADD_DOCUMENT": "Ajouter un nouveau document",
"ADD": {
"ADD_MORE_PAGES": "Ajouter plus de pages",
"DOCUMENT_NAME": "Nom du document",
@@ -347,11 +351,12 @@
"TYPE": "Type",
"VALID_UNTIL": "Valable jusqu'au"
},
- "ARCHIVE": "Archive",
- "ARCHIVE_DOCUMENT": "Document d'archive ?",
- "ARCHIVE_DOCUMENT_TEXT": "L'archivage de ce document le déplacera vers la section archivée de vos documents, mais ne le supprimera pas. Les documents archivés ne seront pas exportés pour vos certifications. Voulez-vous continuer ?",
- "ARCHIVED": "MISSING",
- "CANCEL": "MISSING",
+ "ADD_DOCUMENT": "Ajouter un nouveau document",
+ "ARCHIVE": "Archiver",
+ "ARCHIVE_DOCUMENT": "Document d'archive\u00a0?",
+ "ARCHIVE_DOCUMENT_TEXT": "L'archivage de ce document le déplacera vers la section archivée de vos documents, mais ne le supprimera pas. Les documents archivés ne seront pas exportés pour vos certifications. Voulez-vous continuer\u00a0?",
+ "ARCHIVED": "Archivé",
+ "CANCEL": "Annuler",
"COMPLIANCE_DOCUMENTS_AND_CERTIFICATION": "Documents de conformité et votre certification",
"DOCUMENTS": "Documents",
"EDIT_DOCUMENT": "Modifier le document",
@@ -363,7 +368,7 @@
"NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
"SPOTLIGHT": {
"CDC": "Lorsque viendra le temps de générer votre exportation de certification, LiteFarm exportera automatiquement tous les documents de conformité qui sont valides à la date d'exportation que vous spécifiez. Les documents de conformité seront automatiquement archivés à leur expiration.",
- "HERE_YOU_CAN": "Ici, vous pouvez :",
+ "HERE_YOU_CAN": "Ici, vous pouvez\u00a0:",
"YOU_CAN_ONE": "Téléchargez les documents que vous souhaitez inclure dans votre exportation de certification",
"YOU_CAN_THREE": "Archiver les documents inutiles",
"YOU_CAN_TWO": "Classer et garder un œil sur les dates d'expiration de votre document"
@@ -372,17 +377,23 @@
"CLEANING_PRODUCT": "Produit de nettoyage",
"CROP_COMPLIANCE": "Conformité des cultures",
"FERTILIZING_PRODUCT": "Produit fertilisant",
- "OTHER": "MISSING",
+ "INVOICES": "Factures",
+ "OTHER": "Autre",
"PEST_CONTROL_PRODUCT": "Produit antiparasitaire",
+ "RECEIPTS": "Recettes",
"SOIL_AMENDMENT": "Amendement du sol",
- "SOIL_SAMPLE_RESULTS": "MISSING",
- "WATER_SAMPLE_RESULTS": "MISSING"
+ "SOIL_SAMPLE_RESULTS": "Résultats des échantillons de sol",
+ "WATER_SAMPLE_RESULTS": "Résultats des échantillons d'eau"
},
- "VALID": "MISSING"
+ "UNARCHIVE": "Désarchivé",
+ "UNARCHIVE_DOCUMENT": "Désarchiver le document?",
+ "UNARCHIVE_DOCUMENT_TEXT": "L'annulation de l'archivage de ce document ramènera celui-ci à votre liste de documents valides. Les documents valides seront exportés pour vos certifications. Voulez-vous continuer\u00a0?",
+ "UNARCHIVED": "Désarchivés",
+ "VALID": "Valide"
},
"ENTER_PASSWORD": {
- "FORGOT": "Mot de passe oublié ?",
- "HINT": "MISSING",
+ "FORGOT": "Mot de passe oublié\u00a0?",
+ "HINT": "Indice",
"LABEL": "Mot de passe",
"ONE_NUMBER": "au moins un numéro",
"ONE_SPECIAL_CHARACTER": "au moins un caractère spécial",
@@ -391,12 +402,13 @@
},
"EXPENSE": {
"ADD_EXPENSE": {
+ "ALL_FIELDS_REQUIRED": "Tous les champs sont requis",
"MIN_ERROR": "Veuillez saisir une valeur supérieure à ",
"REQUIRED_ERROR": "Une dépense est requise",
"TITLE_1": "Nouvelle dépense (1 sur 2)",
"TITLE_2": "Nouvelle dépense (2 sur 2)"
},
- "ADD_MORE_ITEMS": "Ajouter plus d'éléments",
+ "ADD_MORE_ITEMS": "Ajouter d'autres articles",
"DETAILED_HISTORY": "Historique détaillé",
"EDIT_EXPENSE": {
"DATE_PLACEHOLDER": "Choisissez une date",
@@ -405,8 +417,8 @@
"TITLE_1": "Modifier les dépenses (1 sur 2)",
"TITLE_2": "Modifier la dépense (2 sur 2)"
},
- "ITEM": "MISSING",
- "NAME": "nom",
+ "ITEM": "Nom",
+ "NAME": "de l'article",
"NO_EXPENSE": "Aucune dépense trouvée",
"NO_EXPENSE_YEAR": "Vous n'avez enregistré aucune dépense pour cette année",
"OTHER_EXPENSES_TITLE": "Autres dépenses",
@@ -417,18 +429,19 @@
"RESET_PASSWORD_LINK": "Envoyer un nouveau lien de mot de passe."
},
"FARM_MAP": {
+ "TUTORIALS": "Vidéos d'instructions",
"AREA_DETAILS": {
"NETWORK": "Problèmes de connectivité réseau.",
"PERIMETER": "Périmètre",
"TOTAL_AREA": "Superficie totale"
},
"BARN": {
- "ANIMALS": "Cette zone est-elle utilisée pour loger des animaux ?",
- "COLD_STORAGE": "Cette grange a-t-elle une chambre froide ?",
+ "ANIMALS": "Cette zone est-elle utilisée pour loger des animaux\u00a0?",
+ "COLD_STORAGE": "Cette grange a-t-elle une chambre froide\u00a0?",
"EDIT_TITLE": "Modifier la grange",
"NAME": "Nom de la grange",
"TITLE": "Ajouter une grange",
- "WASH_PACK": "Cette grange a-t-elle une station de lavage et d'emballage ?"
+ "WASH_PACK": "Cette grange a-t-elle une station de lavage et d'emballage\u00a0?"
},
"BUFFER_ZONE": {
"EDIT_TITLE": "Modifier la zone tampon",
@@ -443,18 +456,19 @@
},
"CONFIRM_RETIRE": {
"BODY": "Retirer cet emplacement le supprimera de la carte de la ferme.",
- "TITLE": "Retirer l'emplacement ?"
+ "TITLE": "Retirer l'emplacement\u00a0?"
},
"DRAWING_MANAGER": {
"REDRAW": "Redessiner",
"ZERO_AREA_DETECTED": "Champ sans zone détectée. Veuillez ajouter plus de points au dessin actuel ou dessiner à nouveau."
},
"EXPORT_MODAL": {
- "BODY": "Comment voulez-vous exporter votre carte de ferme ?",
+ "BODY": "Comment voulez-vous exporter la carte de votre ferme\u00a0?",
"DOWNLOAD": "Télécharger",
"EMAIL_TO_ME": "Envoyez-moi une courriel",
"EMAILING": "Envoi en cours",
- "TITLE": "Exportez votre carte de ferme"
+ "TITLE": "Exportez la carte de votre ferme",
+ "LOADING": "Chargement..."
},
"FARM_SITE_BOUNDARY": {
"EDIT_TITLE": "Modifier les limites du site de la ferme",
@@ -465,13 +479,13 @@
"EDIT_TITLE": "Modifier la clôture",
"LENGTH": "Longueur totale",
"NAME": "Nom de la clôture",
- "PRESSURE_TREATED": "Cette clôture est-elle traitée sous pression ?",
+ "PRESSURE_TREATED": "Cette clôture est-elle traitée sous pression\u00a0?",
"TITLE": "Ajouter une clôture"
},
"FIELD": {
"DATE": "Date de transition admissible",
"EDIT_TITLE": "Modifier le champ",
- "FIELD_TYPE": "De quel type de champ s'agit-il ?",
+ "FIELD_TYPE": "De quel type de champ s'agit-il\u00a0?",
"NAME": "Nom du champ",
"NON_ORGANIC": "Non-bio",
"ORGANIC": "Biologique",
@@ -481,7 +495,7 @@
"GARDEN": {
"DATE": "Date de transition admissible",
"EDIT_TITLE": "Modifier le jardin",
- "GARDEN_TYPE": "Quel type de jardin est-ce ?",
+ "GARDEN_TYPE": "Quel type de jardin est-ce\u00a0?",
"NAME": "Nom du jardin",
"NON_ORGANIC": "Non-bio",
"ORGANIC": "Biologique",
@@ -497,21 +511,21 @@
"CO2_ENRICHMENT": "Y a-t-il un enrichissement en CO₂ ?",
"DATE": "Date de transition admissible",
"EDIT_TITLE": "Modifier la serre",
- "GREENHOUSE_HEATED": "La serre est-elle chauffée ?",
- "GREENHOUSE_TYPE": "De quel type de serre s'agit-il ?",
+ "GREENHOUSE_HEATED": "La serre est-elle chauffée\u00a0?",
+ "GREENHOUSE_TYPE": "De quel type de serre s'agit-il\u00a0?",
"NAME": "Nom de la serre",
"NON_ORGANIC": "Non-bio",
"ORGANIC": "Biologique",
- "SUPPLEMENTAL_LIGHTING": "Y a-t-il un éclairage supplémentaire ?",
+ "SUPPLEMENTAL_LIGHTING": "Y a-t-il un éclairage supplémentaire\u00a0?",
"TITLE": "Ajouter une serre",
"TRANSITIONING": "Transition"
},
"LINE_DETAILS": {
- "BUFFER_TITLE": "Quelle est la largeur ?",
+ "BUFFER_TITLE": "Quelle est la largeur\u00a0?",
"BUFFER_ZONE_WIDTH": "Largeur de la zone tampon",
"RIPARIAN_BUFFER": "Tampon riverain",
"WATERCOURSE": "Flux d'eau",
- "WATERCOURSE_TITLE": "Quelles sont les largeurs suivantes ?"
+ "WATERCOURSE_TITLE": "Quelles sont les largeurs suivantes\u00a0?"
},
"LOCATION_CREATION_FLOW": "création d'emplacement",
"MAP_FILTER": {
@@ -520,7 +534,7 @@
"BARN": "Granges",
"BZ": "Zone tampon",
"CA": "Espace de cérémonie",
- "FENCE": "Cloture",
+ "FENCE": "Clôture",
"FIELD": "Champ",
"FSB": "Limite du site agricole",
"GARDEN": "Jardin",
@@ -529,11 +543,11 @@
"HIDE_ALL": "Cacher tout",
"LABEL": "Étiquettes",
"LINES": "Lignes",
- "NA": "Zones naturel",
+ "NA": "Espace naturel",
"POINTS": "Points",
"RESIDENCE": "Résidence",
"SATELLITE": "Image satellite",
- "SHOW_ALL": "Aficher tout",
+ "SHOW_ALL": "Afficher tout",
"SURFACE_WATER": "Eaux de surface",
"TITLE": "Filtrer votre carte",
"WATERCOURSE": "Flux d'eau",
@@ -557,7 +571,7 @@
"EXPORT_TITLE": "Exportez votre carte",
"FILTER": "Modifier les emplacements que vous voyez sur votre carte",
"FILTER_TITLE": "Filtrez votre carte",
- "HERE_YOU_CAN": "Ici, vous pouvez :"
+ "HERE_YOU_CAN": "Ici, vous pouvez\u00a0:"
},
"SURFACE_WATER": {
"EDIT_TITLE": "Modifier l'eau de surface",
@@ -567,7 +581,8 @@
},
"TAB": {
"CROPS": "Récoltes",
- "DETAILS": "Détails"
+ "DETAILS": "Détails",
+ "TASKS": "Tâches"
},
"TITLE": "Carte de la ferme",
"TUTORIAL": {
@@ -632,19 +647,19 @@
},
"FINANCES": {
"ACTUAL_REVENUE": {
- "ADD_REVENUE": "MISSING",
- "TITLE": "MISSING"
+ "ADD_REVENUE": "Ajouter des revenus",
+ "TITLE": "Chiffre d'affaires réel"
},
- "DATE": "MISSING",
+ "DATE": "Date",
"ESTIMATED_REVENUE": {
- "ESTIMATED_ANNUAL_REVENUE": "MISSING",
- "ESTIMATED_ANNUAL_YIELD": "MISSING",
- "ESTIMATED_PRICE_PER_UNIT": "MISSING",
- "TITLE": "MISSING"
+ "ESTIMATED_ANNUAL_REVENUE": "Revenu annuel estimé",
+ "ESTIMATED_ANNUAL_YIELD": "Récolte annuelle estimée",
+ "ESTIMATED_PRICE_PER_UNIT": "Estimation du prix unitaire",
+ "TITLE": "Chiffre d'affaires estimé"
},
- "REVENUE": "MISSING",
- "VIEW_WITHIN_DATE_RANGE": "MISSING",
- "WHOLE_FARM_REVENUE": "MISSING"
+ "REVENUE": "Revenu",
+ "VIEW_WITHIN_DATE_RANGE": "Voir les revenus dans cette plage de dates",
+ "WHOLE_FARM_REVENUE": "Revenu total de la ferme"
},
"HELP": {
"ATTACHMENT_LABEL": "Télécharger une capture d'écran ou un fichier",
@@ -653,13 +668,13 @@
"OPTIONS": {
"OTHER": "Autre",
"REPORT_BUG": "Signaler un bogue",
- "REQUEST_FEATURE": "Demander une fonctionnalité",
+ "REQUEST_FEATURE": "Suggérer une nouvelle fonctionnalité",
"REQUEST_INFO": "Demander des informations"
},
"PREFERRED_CONTACT": "Méthode de contact préférée",
"REQUIRED_LABEL": "Champ obligatoire",
"TITLE": "Demander de l'aide",
- "TYPE_SUPPORT_LABEL": "Type de prise en charge",
+ "TYPE_SUPPORT_LABEL": "Type de support",
"TYPE_SUPPORT_PLACEHOLDER": "Choisissez le type de support",
"WHATSAPP": "Whatsapp",
"WHATSAPP_NUMBER_LABEL": "Numéro Whatsapp"
@@ -671,32 +686,49 @@
"BIODIVERSITY": {
"AMPHIBIANS": "Amphibiens",
"BIRDS": "Oiseaux",
- "CROP_VARIETIES": "MISSING",
+ "CROP_VARIETIES": "Variété de la culture",
+ "ERROR": {
+ "BODY": "LiteFarm génère des données sur la biodiversité à partir de plusieurs sources et est incapable de le faire en ce moment. Veuillez réessayer dans {{minutes}} minutes.",
+ "PREVIEW": "Indisponible",
+ "TITLE": "Il y a eu un problème."
+ },
"HEADER": "Nombre d'espèces",
"INFO": "La biodiversité est excellente pour les gens et la planète. Nous comptons la richesse en espèces de tous les enregistrements connus de la biodiversité sur votre ferme à partir des limites de vos champs. Vous pouvez augmenter le nombre de votre biodiversité sur votre ferme en utilisant le https:// www.inaturalist.org/app.",
"INSECTS": "Insectes",
+ "LOADING": {
+ "BODY": "Nous générons les dernières données sur la biodiversité de votre ferme. Cela peut prendre jusqu’à 60 secondes.",
+ "PREVIEW": "En course de chargement...",
+ "TITLE": "Nous générons les données de biodiversité les plus récents..."
+ },
+ "MAMMALS": "Mammifères",
"PLANTS": "Plantes",
"SPECIES_COUNT": "{{count}} espèces",
+ "SPECIES_COUNT_one": "{{count}} espèce",
+ "SPECIES_COUNT_many": "{{count}} espèces",
+ "SPECIES_COUNT_other": "{{count}} espèces",
"SPECIES_COUNT_plural": "{{count}} espèces",
"TITLE": "Biodiversité"
},
"CURRENT": "Courant",
- "INFO": "Les insights fournit des informations supplémentaires sur ce qui se passe sur votre ferme. Plus vous fournissez de données dans l'application, plus vous pouvez générer d'informations. Veuillez explorer les informations individuelles pour plus d'informations.",
+ "INFO": "Ces mesures fournissent de l’information supplémentaire sur ce qui se passe sur votre ferme. Plus vous entrez de données dans l’application, plus d’information est générée. Veuillez explorer les différentes mesures pour plus de détails.",
"LABOUR_HAPPINESS": {
"HEADER": "Tâches",
- "INFO": "Nous estimons l'impact de différentes tâches sur le bonheur au travail en utilisant les scores de satisfaction et les heures de travail consacrées à chaque tâche à partir des quarts de travail.",
- "TITLE": "Bonheur au travail"
+ "INFO": "Nous estimons l'impact de différentes tâches sur le satisfaction au travail en utilisant les scores de satisfaction et les heures de travail consacrées à chaque tâche à partir des quarts de travail.",
+ "TITLE": "Satisfaction au travail"
},
"NITROGEN_BALANCE": {
"ABANDON": "Abandonner l'horaire",
"CHOOSE_A_FREQUENCY": "Choisissez une fréquence",
"CHOOSE_FREQUENCY": "Choisir la fréquence...",
"COUNT_MONTHS": "{{count}} mois",
+ "COUNT_MONTHS_one": "{{count}} mois",
+ "COUNT_MONTHS_many": "{{count}} mois",
+ "COUNT_MONTHS_other": "{{count}} mois",
"COUNT_MONTHS_plural": "{{count}} mois",
- "CYCLE_INDICATOR": "Votre balance d'azote est sur un cycle de {{fréquence}} mois et les données s'afficheront le : {{refreshDate}}",
- "FIRST_TIME": "On dirait que c'est la première fois que vous utilisez cela ! Veuillez sélectionner une fréquence pour calculer votre bilan d'azote.",
+ "CYCLE_INDICATOR": "Votre balance d'azote est sur un cycle de {{fréquence}} mois et les données s'afficheront le\u00a0: {{refreshDate}}",
+ "FIRST_TIME": "On dirait que c'est la première fois que vous utilisez cela\u00a0! Veuillez sélectionner une fréquence pour calculer votre bilan d'azote.",
"GO_BACK": "Retour",
- "HEADER": "Tous les {{fréquence}} mois : {{refreshDate}}",
+ "HEADER": "Tous les {{fréquence}} mois\u00a0: {{refreshDate}}",
"INFO_1": "Le bilan d'azote vous indique si vous avez appliqué trop ou trop peu d'engrais. Il repose sur vos journaux de récolte, les crédits d'azote des légumineuses et les journaux de fertilisation. Vous pouvez exécuter le bilan sur l'intervalle de temps souhaité.",
"INFO_2": "Cliquez sur le bouton Supprimer pour réinitialiser votre emploi du temps.",
"SELECT_FREQUENCY": "Sélectionner la fréquence",
@@ -708,35 +740,41 @@
"HEADER": "Nombre de repas",
"INFO": "Nous estimons le nombre de repas potentiels fournis par votre ferme sur la base des données de soldes et des bases de données sur la composition des cultures. Nous supposons que les besoins quotidiens sont répartis également sur trois repas par jour.",
"MEAL_COUNT": "{{count}} repas",
+ "MEAL_COUNT_one": "{{count}} repas",
+ "MEAL_COUNT_many": "{{count}} repas",
+ "MEAL_COUNT_other": "{{count}} repas",
"MEAL_COUNT_plural": "{{count}} repas",
"MEALS": "repas",
"PROTEIN": "Protéine",
- "TITLE": "People Fed",
+ "TITLE": "Personnes nourries",
"VITAMIN_A": "Vitamine A",
"VITAMIN_C": "Vitamine C"
},
"PRICES": {
- "INFO": "Nous vous montrons la trajectoire de vos prix de vente par rapport aux prix de vente des mêmes produits à une distance donnée de vous, collectés sur le réseau LiteFarm.",
- "NEARBY_FARMS": "Le prix du réseau est basé sur {{count}} fermes dans votre région",
- "NEARBY_FARMS_plural": "Le prix du réseau est basé sur {{count}} fermes dans votre région",
- "NETWORK_PRICE": "Prix du réseau",
+ "INFO": "Nous vous montrons la tendance de vos prix de vente pour chacun de vos produits, et la comparons aux prix de ventes des mêmes produits rapportés par d’autres fermes proches de vous qui font partie du réseau LiteFarm.",
+ "NEARBY_FARMS": "Le prix moyen du réseau est basé sur les prix de {{count}} autres fermes dans votre région",
+ "NEARBY_FARMS_one": "Le prix moyen du réseau est basé sur le prix de {{count}} autre ferme dans votre région",
+ "NEARBY_FARMS_many": "Le prix moyen du réseau est basé sur les prix de {{count}} autres fermes dans votre région",
+ "NEARBY_FARMS_other": "Le prix moyen du réseau est basé sur les prix de {{count}} autres fermes dans votre région",
+ "NEARBY_FARMS_plural": "Le prix moyen du réseau est basé sur les prix de {{count}} autres fermes dans votre région",
+ "NETWORK_PRICE": "Prix moyen du réseau",
"NO_ADDRESS": "Vous n'avez actuellement pas d'adresse à LiteFarm. Veuillez la mettre à jour dans votre profil pour obtenir des informations sur les prix à proximité!",
- "OWN_PRICE": "Prix propre",
+ "OWN_PRICE": "Votre propre prix",
"PERCENT_OF_MARKET": "{{percentage}} % du marché",
- "SALES_FROM_DISTANCE_AWAY": "Ventes à partir de {{distance}} {{unit}} loin",
+ "SALES_FROM_DISTANCE_AWAY": "Ventes sur un partir d'un rayon de {{distance}} {{unit}}",
"TITLE": "Prix",
- "Y_TITLE": "Prix ({{devise}}/{{masse}})"
+ "Y_TITLE": "Prix ({{currency}}/{{mass}})"
},
"SOIL_OM": {
- "ALTERNATE_TITLE": "Teneur en Matière Organique du Sol",
- "HEADER": "Matière Organique du Sol",
- "INFO": "Matière organique du sol est requise pour maintenir un environement sain de sol pour votre récolte. Nous remplissons ces données à partir de vos journaux d'analyse de sol les plus récents. Si vous n'avez pas de données, nous prédisons la matière organique potentielle du sol pour votre emplacement dans le monde.",
- "TITLE": "MO du Sol"
+ "ALTERNATE_TITLE": "Teneur en matière organique du sol",
+ "HEADER": "Matière organique du sol",
+ "INFO": "La matière organique du sol est essentielle pour maintenir un sol sain pour vos récoltes. La teneur en matière organique est calculée à partir de vos journaux d’analyse de sol les plus récents. Si vous n’avez pas de données sur votre sol, nous estimons la matière organique potentielle de votre sol en fonction de votre emplacement dans le monde.",
+ "TITLE": "Matière organique du Sol"
},
- "TITLE": "Aperçus",
+ "TITLE": "Mesures additionnelles",
"UNAVAILABLE": "Indisponible",
"WATER_BALANCE": {
- "FIRST_TIME": "On dirait que c'est la première fois que vous exécutez cela ! Pour plus d'informations sur ce que cela fait, veuillez cliquer sur le bouton d'information pour voir.",
+ "FIRST_TIME": "On dirait que c'est la première fois que vous exécutez cela\u00a0! Pour plus d'informations sur ce que cela fait, veuillez cliquer sur le bouton d'information pour voir.",
"INFO_1": "Le bilan hydrique vous indique si vos cultures ont trop ou pas assez d'eau. Il s'appuie sur les données météorologiques, et il est mis à jour par vos données d'irrigation et de texture du sol à partir de vos journaux d'analyse de sol.",
"INFO_2": "Cette fonctionnalité n'a pas été largement testée dans les fermes avec une faible densité de stations météorologiques environnantes, donc utilisez-la avec prudence. Nous apprécions les commentaires sur ses performances pour votre ferme.",
"NO_SCHEDULE_RUN": "Votre bilan hydrique programmé n'a pas encore été exécuté, veuillez vérifier dans deux jours et vous assurer d'avoir au moins une analyse de sol qui enregistre la texture du sol pour un champ pour voir les données de bilan hydrique pour les cultures dans ce champ. Si le le problème persiste, veuillez contacter LiteFarm.",
@@ -754,7 +792,7 @@
"BIRTH_YEAR_TOOLTIP": "Les informations sur l'âge sont collectées à des fins de recherche uniquement et ne seront partagées qu'avec les informations d'identification personnelle supprimées",
"CREATE_ACCOUNT": "Créer un nouveau compte",
"CREATE_NEW_ACCOUNT": "Créer un nouveau compte",
- "EMAIL": "Email",
+ "EMAIL": "Adresse courriel",
"FULL_NAME": "Prénom et nom",
"GENDER": "Genre",
"GENDER_TOOLTIP": "Les informations sur le genre sont collectées à des fins de recherche uniquement et ne seront partagées qu'avec tous les informations d'identification personnelle supprimées",
@@ -764,7 +802,7 @@
"INVITE_SIGN_UP": {
"ERROR0": "Vous aurez besoin de l'utilisateur",
"ERROR1": "pour accepter cette invitation à la ferme.",
- "HOW_TO_CREATE": "Comment voulez-vous créer votre nouveau compte ?",
+ "HOW_TO_CREATE": "Comment voulez-vous créer votre nouveau compte\u00a0?",
"LITEFARM_ACCOUNT": "Créer un compte LiteFarm",
"SIGN_IN_WITH": "Connectez-vous avec",
"TITLE": "Créez votre compte"
@@ -774,27 +812,30 @@
"BIRTH_YEAR_ERROR": "L'année de naissance doit être comprise entre 1900 et",
"BIRTH_YEAR_TOOLTIP": "Les informations sur l'âge sont collectées à des fins de recherche uniquement et ne seront partagées qu'avec les informations d'identification personnelle supprimées",
"CHOOSE_ROLE": "Choisir un rôle",
- "EMAIL": "Email",
- "EMAIL_INFO": "Les utilisateurs sans email ne pourront pas se connecter",
+ "DEFAULT_LANGUAGE": "Français",
+ "DEFAULT_LANGUAGE_VALUE": "fr",
+ "EMAIL": "Adresse courriel",
+ "EMAIL_INFO": "Les utilisateurs sans courriel ne pourront pas se connecter",
"FULL_NAME": "Nom complet",
"GENDER": "Genre",
"GENDER_TOOLTIP": "Les informations sur le genre sont collectées à des fins de recherche uniquement et ne seront partagées qu'avec les informations d'identification personnelle supprimées",
- "INVALID_EMAIL_ERROR": "Veuillez saisir une adresse e-mail valide",
+ "INVALID_EMAIL_ERROR": "Veuillez saisir une adresse courriel valide",
"INVITE": "Inviter",
+ "LANGUAGE_OF_INVITE": "Langue d'invitation",
"PHONE": "Téléphone",
"PHONE_ERROR": "Veuillez entrer un numéro de téléphone valide",
"ROLE": "Rôle",
"TITLE": "Inviter un utilisateur",
- "WAGE": "MISSING",
+ "WAGE": "Salaire",
"WAGE_ERROR": "Le salaire doit être un nombre décimal valide et non négatif"
},
"JOIN_FARM_SUCCESS": {
- "IMPORTANT_THINGS": "Laissez-nous vous montrer quelques choses importantes !",
+ "IMPORTANT_THINGS": "Laissez-nous vous montrer quelques choses importantes\u00a0!",
"SUCCESSFULLY_JOINED": "Vous avez rejoint avec succès"
},
"LOCATION_CROPS": {
"ACTIVE_CROPS": "Cultures actives",
- "ADD_NEW": "Ajouter un recadrage",
+ "ADD_NEW": "Ajouter une nouvelle culture",
"INPUT_PLACEHOLDER": "Tapez pour rechercher",
"PAST_CROPS": "Cultures passées",
"PLANNED_CROPS": "Cultures planifiées"
@@ -804,7 +845,7 @@
"ALL_CROPS": "Toutes les cultures",
"ALL_LOCATIONS": "Tous les emplacements",
"CROP": "Crop",
- "DELETE_CONFIRMATION": "Voulez-vous vraiment supprimer ce journal ?",
+ "DELETE_CONFIRMATION": "Voulez-vous vraiment supprimer ce journal\u00a0?",
"EDIT_A_LOG": "Modifier un journal",
"FROM": "De",
"LOCATION": "Emplacement",
@@ -834,20 +875,20 @@
"LOG_HARVEST": {
"ADD_CUSTOM_HARVEST_USE": "Ajouter une utilisation de récolte personnalisée",
"CROP": "Crop",
- "CROP_PLACEHOLDER": "Sélectionnez un recadrage",
+ "CROP_PLACEHOLDER": "Sélectionnez une culture",
"CUSTOM_HARVEST_USE": "Utilisations de récolte personnalisées",
"DISEASE": "Maladie",
"HARVEST": "Récolte",
- "HARVEST_ALLOCATION_SUBTITLE": "Environ quelle quantité de la récolte sera utilisée pour chaque objectif ?",
- "HARVEST_USE_TYPE_SUBTITLE": "Comment la récolte sera-t-elle utilisée ?",
- "OTHER": "MISSING",
+ "HARVEST_ALLOCATION_SUBTITLE": "Environ quelle quantité de la récolte sera utilisée pour chaque objectif\u00a0?",
+ "HARVEST_ALLOCATION_SUBTITLE_TWO": "Montant à allouer",
+ "HARVEST_QUANTITY": "Quantité de récolte",
+ "HARVEST_USE": "Utilisation de la récolte",
+ "HARVEST_USE_TYPE_SUBTITLE": "Comment la récolte sera-t-elle utilisée\u00a0?",
+ "OTHER": "Autre",
"PEST": "Organismes nuisibles",
"QUANTITY_ERROR": "La quantité doit comporter jusqu'à 2 décimales",
"TITLE": "Journal de récolte",
- "WEED": "Weed",
- "HARVEST_QUANTITY": "Quantité de récolte",
- "HARVEST_USE": "Utilisation de la récolte",
- "HARVEST_ALLOCATION_SUBTITLE_TWO": "Montant à allouer"
+ "WEED": "Weed"
},
"LOG_IRRIGATION": {
"DRIP": "Goutte",
@@ -858,21 +899,24 @@
"MANAGEMENT_DETAIL": {
"ABANDON_PLAN": "Abandonner ce plan de gestion",
"ADD_A_TASK": "Ajouter une tâche",
- "DETAILS": "MISSING",
- "FAILED_CROP": "Echec du recadrage ?",
- "TASKS": "MISSING"
+ "DETAILS": "Détails",
+ "FAILED_CROP": "Echec de la culture\u00a0?",
+ "TASKS": "Tâches"
},
"MANAGEMENT_PLAN": {
"ABANDON_MANAGEMENT_PLAN_CONTENT": "Abandonner ce plan de gestion abandonnera toutes les tâches incomplètes qui lui sont associées et le supprimera de votre carte de ferme.",
- "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandonner le plan de gestion ?",
+ "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandonner le plan de gestion\u00a0?",
"ADD_MANAGEMENT_PLAN": "Ajouter un plan de gestion",
"AGE": "Âge",
"AS_COVER_CROP": "Cultures de couverture",
- "BEDS": "Lits",
+ "BEDS": "Plates-bandes",
"BROADCAST": "Diffusion ou exercice",
"COMPLETE_PLAN": {
+ "ABANDON_DATE": "Date d'abandon",
+ "ABANDON_NOTES": "Notes d'abandon",
"ABANDON_PLAN": "Abandonner le plan",
"ABANDON_REASON": "Raison de l'abandon",
+ "COMPLETE_DATE": "Date de fin",
"COMPLETE_PLAN": "Plan complet",
"DATE_OF_CHANGE": "Date de changement de statut",
"NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
@@ -888,38 +932,39 @@
},
"WHAT_HAPPENED": "Quest-ce qui est arrivé ?"
},
+ "COMPLETION_NOTES": "Notes d'achèvement",
"CONTAINER": "Conteneur",
- "CONTAINER_OR_IN_GROUND": "Plantez-vous dans un conteneur ou en pleine terre ?",
+ "CONTAINER_OR_IN_GROUND": "Plantez-vous dans un conteneur ou en pleine terre\u00a0?",
"CONTAINER_TYPE": "Type de conteneur",
"COVER_INFO": "Sélectionner une culture de couverture créera une tâche de travail sur le terrain pour terminer la culture de couverture à la fin de la saison. Sélectionner pour la récolte créera une tâche de récolte à la place.",
- "COVER_OR_HARVEST": "Est-ce que cela est cultivé comme culture de couverture ou pour la récolte ?",
- "DAYS_FROM_PLANTING": "Jours entre la plantation et :",
- "DAYS_FROM_SEEDING": "Jours entre le départ et :",
- "DAYS_TO_HARVEST": "Jours entre le repiquage et la prochaine récolte :",
- "DAYS_TO_TERMINATION": "Jours entre la greffe et la résiliation :",
- "DETAIL_SPOTLIGHT_CONTENTS": "MISSING",
+ "COVER_OR_HARVEST": "Est-ce que cela est cultivé comme culture de couverture ou pour la récolte\u00a0?",
+ "DAYS_FROM_PLANTING": "Jours entre la plantation et\u00a0:",
+ "DAYS_FROM_SEEDING": "Jours entre la semance et\u00a0:",
+ "DAYS_TO_HARVEST": "Jours entre le repiquage et la prochaine récolte\u00a0:",
+ "DAYS_TO_TERMINATION": "Jours entre la greffe et la résiliation\u00a0:",
+ "DETAIL_SPOTLIGHT_CONTENTS": "Ici, vous pouvez modifier les détails de votre culture.",
"DETAIL_SPOTLIGHT_TITLE": "Détails",
- "DO_YOU_WANT_TO_ABANDON_CONTENT": "Voulez-vous abandonner ce plan ?",
+ "DO_YOU_WANT_TO_ABANDON_CONTENT": "Voulez-vous abandonner ce plan\u00a0?",
"DROP_PIN": "Lâcher la broche",
"DURATION_TOOLTIP": "Ce sont des valeurs suggérées. Veuillez les ajuster en fonction de vos conditions locales.",
- "EDITING_PLAN_WILL_NOT_MODIFY": "MISSING",
+ "EDITING_PLAN_WILL_NOT_MODIFY": "La modification de ce plan ne modifiera pas les tâches qui lui sont assignées.",
"ESTIMATED_SEED": "Semence estimée requise",
- "ESTIMATED_YIELD": "Rendement estimé",
+ "ESTIMATED_YIELD": "Récolte annuelle estimée",
"FIRST_MP_SPOTLIGHT": {
- "BODY_PART1": "MISSING",
- "BODY_PART2": "MISSING",
- "TITLE": "Félicitations ! Vous avez établi votre premier plan de gestion !"
+ "BODY_PART1": "LiteFarm a généré quelques tâches basées sur votre plan. Vous pouvez ajouter d'autres tâches ou les attribuer sur cet écran.",
+ "BODY_PART2": "Votre plan deviendra actif une fois que vous aurez terminé une tâche.",
+ "TITLE": "Félicitations\u00a0! Vous avez établi votre premier plan de gestion\u00a0!"
},
"FOR_HARVEST": "Pour la récolte",
"GERMINATION": "Germination",
"HARVEST": "Récolte initiale",
- "HARVEST_DATE": "Quand prévoyez-vous votre prochaine récolte ?",
- "HISTORICAL_CONTAINER_OR_IN_GROUND": "A-t-il été planté dans un conteneur ou dans le sol ?",
- "IN_GROUND": "Au sol",
+ "HARVEST_DATE": "Quand prévoyez-vous votre prochaine récolte\u00a0?",
+ "HISTORICAL_CONTAINER_OR_IN_GROUND": "A-t-il été planté dans un conteneur ou dans le sol\u00a0?",
+ "IN_GROUND": "Déjà en terre",
"INCOMPLETE_TASK_CONTENT": "Ce plan comporte des tâches qui ne sont pas encore terminées. Vous devrez marquer les tâches comme terminées afin de terminer ce plan de gestion des cultures.",
"INCOMPLETE_TASK_TITLE": "Vous avez des tâches incomplètes",
"INDIVIDUAL_CONTAINER": "Individuel ou conteneur",
- "IS_TRANSPLANT": "Cette culture sera-t-elle repiquée ?",
+ "IS_TRANSPLANT": "Cette culture sera-t-elle repiquée\u00a0?",
"KNOW_HOW_IS_CROP_PLANTED": "Savez-vous comment la culture a été plantée?",
"LOCATION_SUBTEXT": "Seuls les emplacements pouvant faire pousser des cultures sont affichés.",
"MANAGEMENT_PLAN_FLOW": "création du plan de gestion",
@@ -927,7 +972,7 @@
"MANAGEMENT_SPOTLIGHT_2": "Afficher et modifier les plans pour cette culture",
"MANAGEMENT_SPOTLIGHT_3": "Créer et attribuer des tâches",
"MANAGEMENT_SPOTLIGHT_TITLE": "Gestion",
- "NEXT_HARVEST": "Quand prévoyez-vous votre prochaine récolte ?",
+ "NEXT_HARVEST": "Quand prévoyez-vous votre prochaine récolte\u00a0?",
"NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
"NUMBER_OF_CONTAINER": "# de conteneurs",
"PENDING_TASK": "Tâches en attente",
@@ -935,44 +980,52 @@
"PLAN_NAME": "Nom du plan de gestion",
"PLAN_NOTES": "Notes de plan",
"PLANT_SPACING": "Espacement des plantes",
- "PLANTED_ALREADY": "Planterez-vous cette culture ou est-elle déjà en terre ?",
- "PLANTING": "MISSING",
- "PLANTING_DATE": "Quelle est votre date de plantation ?",
- "PLANTING_DATE_INFO": "Date de semis basée sur l'âge de la culture : {{seed_date}}",
+ "PLANTED_ALREADY": "Planterez-vous cette culture ou est-elle déjà en terre\u00a0?",
+ "PLANTING": "Plantation",
+ "PLANTING_DATE": "Quelle est votre date de plantation\u00a0?",
+ "PLANTING_DATE_INFO": "Date de semis basée sur l'âge de la culture\u00a0: {{seed_date}}",
"PLANTING_DATE_LABEL": "Date de plantation",
"PLANTING_DEPTH": "Profondeur de plantation",
- "PLANTING_METHOD": "Quelle est votre méthode de plantation ?",
+ "PLANTING_METHOD": "Quelle est votre méthode de plantation\u00a0?",
"PLANTING_METHOD_TOOLTIP": "Sélectionner la bonne méthode de plantation aidera LiteFarm à estimer plus précisément la quantité de graines nécessaires, le rendement et d'autres informations utiles.",
"PLANTING_NOTE": "Notes de plantation",
"PLANTING_SOIL": "Terre de plantation à utiliser",
"PLANTS_PER_CONTAINER": "# de plantes/conteneur",
+ "RATE_THIS_MANAGEMENT_PLAN": "Notation du plan",
"REMOVE_PIN": "Supprimer l'épingle",
"ROW_METHOD": {
- "HISTORICAL_SAME_LENGTH": "Les lignes étaient-elles toutes de la même longueur ?",
+ "HISTORICAL_SAME_LENGTH": "Les lignes étaient-elles toutes de la même longueur\u00a0?",
"LENGTH_OF_ROW": "Longueur de la ligne",
"NUMBER_OF_ROWS": "# de lignes",
- "SAME_LENGTH": "Vos lignes sont-elles toutes de la même longueur ?",
+ "SAME_LENGTH": "Vos lignes sont-elles toutes de la même longueur\u00a0?",
"TOTAL_LENGTH": "Longueur totale des lignes"
},
- "ROWS": "MISSING",
- "SEED_DATE": "Quelle est votre date de semis ?",
- "SEED_OR_SEEDLING": "Comment allez-vous planter cette culture ?",
+ "ROWS": "Rangées",
+ "SEED_DATE": "Quelle est votre date de semis\u00a0?",
+ "SEED_OR_SEEDLING": "Comment allez-vous planter cette culture\u00a0?",
"SEEDING_DATE": "Date de semis",
"SEEDLING": "Plant ou matériel de plantation",
- "SEEDLING_AGE": "Quel âge a le plant ou le matériel de plantation ?",
+ "SEEDLING_AGE": "Quel âge a le plant ou le matériel de plantation\u00a0?",
"SEEDLING_AGE_INFO": "L'âge approximatif aidera LiteFarm à estimer les dates de récolte des semis. Vous pouvez ignorer cette question pour d'autres types de matériel de plantation.",
"SELECT_A_PLANTING_LOCATION": "Sélectionnez un emplacement de plantation",
"SELECT_A_SEEDING_LOCATION": "Sélectionnez un emplacement d'ensemencement",
"SELECT_CURRENT_LOCATION": "Sélectionnez l'emplacement actuel de la culture",
"SELECTED_STARTING_LOCATION": "Sélectionnez toujours ceci comme emplacement de départ pour les cultures qui seront transplantées",
- "SPOTLIGHT_HERE_YOU_CAN": "Ici, vous pouvez :",
+ "SPOTLIGHT_HERE_YOU_CAN": "Ici, vous pouvez\u00a0:",
"STARTED": "Commencé",
+ "STATUS": {
+ "ABANDONED": "Abandonné",
+ "ACTIVE": "Actif",
+ "COMPLETED": "Completé",
+ "PLANNED": "Plannifié"
+ },
"SUPPLIER": "Fournisseur",
- "TERMINATION": "Termination",
+ "TERMINATION": "Terminaison",
"TERMINATION_DATE": "Quand voulez vous terminer cette récolte ?",
"TOTAL_PLANTS": "# de plantes",
"TRANSPLANT": "Transplanter",
"TRANSPLANT_DATE": "C'est quoi la date de transplantation ?",
+ "TRANSPLANT_LOCATION": "Où allez-vous transplanter\u00a0?",
"TRANSPLANT_SPOTLIGHT": {
"BODY": {
"PLANTED": "planté",
@@ -986,128 +1039,156 @@
}
},
"VARIETY": "Variété",
- "WHAT_IS_AGE": "Quel est l'âge de la récolte ?",
+ "WHAT_IS_AGE": "Quel est l'âge de la récolte\u00a0?",
"WHAT_WAS_PLANTING_METHOD": "Quelle était la méthode de plantation?",
- "WHERE_START_LOCATION": "Où est votre position de départ ?",
- "WHERE_TRANSPLANT_LOCATION": "Où allez-vous transplanter?",
- "WILD_CROP": "Récoltez-vous une culture sauvage ?",
- "STATUS": {
- "ABANDONED": "Abandonné",
- "ACTIVE": "Actif",
- "COMPLETED": "Completé",
- "PLANNED": "Plannifié"
- },
"WHAT_WAS_PLANTING_METHOD_INFO": "Sélectionner la bonne méthode de plantation aidera LiteFarm à estimer plus précisément la quantité de graines nécessaires, le rendement et d'autres informations utiles.",
- "TRANSPLANT_LOCATION": "Où allez-vous transplanter ?"
+ "WHERE_START_LOCATION": "Où est votre position de départ\u00a0?",
+ "WHERE_TRANSPLANT_LOCATION": "Où allez-vous transplanter?",
+ "WILD_CROP": "Récoltez-vous une culture sauvage\u00a0?"
},
"MY_FARM": {
"CERTIFICATIONS": "Certifications",
"FARM_INFO": "Informations sur la ferme",
"FARM_MAP": "Carte de la ferme",
- "PEOPLE": "Personel"
+ "PEOPLE": "Personnes"
},
"NAVIGATION": {
"SPOTLIGHT": {
+ "COORDINATE_ACTIVITIES": "Coordonner les activités de la ferme",
+ "EDIT_FARM_SETTING": "Modifier les paramètres de votre ferme",
"FARM": "Ici vous pouvez :, • Modifier les paramètres de votre ferme, • Cartographier votre ferme, • Gérer vos employés",
"FARM_TITLE": "Ceci est votre profil de ferme",
- "NOTIFICATION": "Ici vous pouvez:, • Gérer vos tâches, • Voir les mises à jour importantes, • Coordonner les activités de la ferme",
+ "INFO": "Vos informations",
+ "LOG_OUT": "Le bouton de déconnexion",
+ "MANAGE_EMPLOYEE": "Gérer vos employés",
+ "MANAGE_TASK": "Gérer vos tâches",
+ "MAP_FARM": "Cartographier votre ferme",
+ "SEE_UPDATES": "Voir les mises à jour importantes",
+ "NOTIFICATION": "Ici vous pouvez:, • Voir les mises à jour importantes, • Gérez vos tâches, • Coordonner les activités de la ferme",
"NOTIFICATION_TITLE": "Ceci est votre centre de notification",
"PROFILE": "Vous trouverez ici :, • Vos informations, • Des conseils utiles, • Le bouton de déconnexion",
- "PROFILE_TITLE": "Ceci est votre profil"
+ "PROFILE_TITLE": "Ceci est votre profil",
+ "SEE_TASK": "Voir les mises à jour importantes",
+ "TASK_TITLE": "Ceci est votre centre de notification",
+ "TIPS": "Des conseils utiles",
+ "YOU_CAN": "Ici vous pouvez:",
+ "YOU_WILL_FIND": "Vous trouverez ici:"
}
},
"NOTIFICATION": {
- "NOTIFICATION_TEASER": "MISSING"
+ "DAILY_TASKS_DUE_TODAY": {
+ "BODY": "Vous avez des tâches à accomplir aujourd'hui.",
+ "TITLE": "Tâches à accomplir aujourd'hui"
+ },
+ "NONE_TO_DISPLAY": "Il n'y a aucune notification à afficher.",
+ "NOTIFICATION_TEASER": "Bientôt disponible!",
+ "PAGE_TITLE": "Notifications",
+ "TAKE_ME_THERE": "Allons-y!",
+ "TASK_ABANDONED": {
+ "BODY": "Une tâche de {{taskType}} qui vous était assignée a été abandonnée par {{abandoner}}.",
+ "TITLE": "Tâche abandonnée"
+ },
+ "TASK_ASSIGNED": {
+ "BODY": "Une tâche de {{taskType}} a été assignée à {{assignee}}.",
+ "TITLE": "Tâche assignée"
+ },
+ "TASK_COMPLETED_BY_OTHER_USER": {
+ "BODY": "Une tâche de {{taskType}} qui vous était assignée a été marquée comme complétée par {{assigner}}.",
+ "TITLE": "Tâche accomplie"
+ },
+ "TASK_REASSIGNED": {
+ "BODY": "Une tâche de {{taskType}} qui vous était assignée a été attribuée à quelqu'un d'autre par {{assigner}}.",
+ "TITLE": "Tâche réattribuée"
+ },
+ "WEEKLY_UNASSIGNED_TASKS": {
+ "BODY": "Vous avez des tâches non attribuées à accomplir cette semaine.",
+ "TITLE": "Tâches non attribuées"
+ }
},
"OUTRO": {
- "ALL_DONE": "Super ! Vous avez terminé. Prêt à vous salir les mains ?",
- "IMPORTANT_THINGS": "Et enfin, laissez-nous vous montrer quelques choses importantes !"
- },
- "PASSWORD_RESET_SUCCESS_MODAL": {
- "BUTTON": "Super!",
- "DESCRIPTION": "Votre mot de passe a été mis à jour. Vous redirigeant vers vos fermes en 10 secondes...",
- "TITLE": "Succès!"
+ "ALL_DONE": "Super\u00a0! Vous avez terminé. Prêt à vous salir les mains\u00a0?",
+ "IMPORTANT_THINGS": "Et enfin, laissez-nous vous montrer quelques choses importantes\u00a0!"
},
"PASSWORD_RESET": {
"BUTTON": "Renvoyer le lien",
"BUTTON_SENDING": "Envoi...",
- "DESCRIPTION_BOTTOM": "Veuillez vérifier votre courrier électronique.",
+ "DESCRIPTION_BOTTOM": "Veuillez vérifier votre courriel.",
"DESCRIPTION_TOP": "Un lien a été envoyé.",
+ "LABEL_EMAIL": "Adresse courriel",
+ "LABEL_NEW_PASSWORD": "Nouveau mot de passe",
"NEW_ACCOUNT_BUTTON": "Mettre à jour",
"NEW_ACCOUNT_TITLE": "Définir votre nouveau mot de passe",
"TITLE": "Lien envoyé"
},
+ "PASSWORD_RESET_SUCCESS_MODAL": {
+ "BUTTON": "Super!",
+ "DESCRIPTION": "Votre mot de passe a été mis à jour. Vous redirigeant vers vos fermes en 10 secondes...",
+ "TITLE": "Succès!"
+ },
"PLAN_GUIDANCE": {
- "ADDITIONAL_GUIDANCE": "Voulez-vous fournir des conseils supplémentaires pour cette tâche d'ensemensement ??",
- "BED": "Lit",
- "BEDS": "lits",
+ "ADDITIONAL_GUIDANCE": "Voulez-vous fournir des conseils supplémentaires pour cette tâche d'ensemensement\u00a0?",
+ "BED": "Plate-bande",
+ "BEDS": "plate-bandes",
"NOTES": "Notes de plantation",
"PLANTING_DEPTH": "Profondeur de plantation",
- "ROW": "Rang",
- "ROWS": "rangs",
+ "ROW": "Rangée",
+ "ROWS": "rangées",
"SPACE_BETWEEN": "Espace entre {{types}}",
"SPECIFY": "Specifier {{types}}",
"SPECIFY_PLACEHOLDER": "E.g. {{types}} 1 - 4",
"TOOLTIP": "Les 40 premiers caractères de ce champ s'afficheront partout où votre plan de gestion est visible.",
- "WIDTH": "MISSING",
+ "WIDTH": "Largeur {{type}}",
"WORD_LIMIT": "Only {{limit}} characters can be displayed"
},
"PREPARING_EXPORT": {
- "MESSAGE": "LiteFarm rassemble vos documents de certification en arrière-plan et vous recevrez un e-mail lorsque nous aurons terminé - cela peut prendre quelques minutes... Vous pouvez cliquer en dehors de cette case pour continuer à utiliser LiteFarm sans interrompre le processus.",
+ "MESSAGE": "LiteFarm rassemble vos documents de certification en arrière-plan et vous recevrez un courriel lorsque nous aurons terminé - cela peut prendre quelques minutes... Vous pouvez cliquer en dehors de cette case pour continuer à utiliser LiteFarm sans interrompre le processus.",
"TITLE": "Votre export est en préparation"
},
- "PROFILE_FLOATER": {
- "HELP": "À l'aide",
- "INFO": "Mes infos",
- "LOG_OUT": "Déconnexion",
- "SWITCH": "Changer de ferme",
- "TUTORIALS": "MISSING"
- },
"PROFILE": {
- "ACCOUNT_TAB": "Compte",
"ACCOUNT": {
"CONVERT_TO_HAVE_ACCOUNT": "Convertir ce travailleur en utilisateur avec compte",
- "EDIT_USER": "MISSING",
- "EMAIL": "Email",
+ "EDIT_USER": "Modifier l'utilisateur",
+ "EMAIL": "Adresse courriel",
"ENGLISH": "anglais",
"FIRST_NAME": "Prénom",
- "FRENCH": "MISSING",
- "LANGUAGE": "MISSING",
+ "FRENCH": "français",
+ "LANGUAGE": "Langue",
"LAST_NAME": "Nom de famille",
"PERSONAL_INFORMATION": "Mes informations",
"PHONE_NUMBER": "Numéro de téléphone",
- "PORTUGUESE": "MISSING",
- "SPANISH": "MISSING",
+ "PORTUGUESE": "portugais",
+ "SPANISH": "espagnol",
"USER_ADDRESS": "Adresse de l'utilisateur"
},
- "FARM_TAB": "Ferme",
+ "ACCOUNT_TAB": "Compte",
"FARM": {
- "ADDRESS": "adresse",
- "CURRENCY": "MISSING",
+ "ADDRESS": "Adresse",
+ "CURRENCY": "Devise",
"FARM_NAME": "Nom de la ferme",
- "IMPERIAL": "MISSING",
- "METRIC": "Metric",
+ "IMPERIAL": "Impériale",
+ "METRIC": "Métrique",
"PHONE_NUMBER": "Numéro de téléphone",
"UNITS": "Unités"
},
- "PEOPLE_TAB": "People",
+ "FARM_TAB": "Ferme",
"PEOPLE": {
- "DO_YOU_WANT_TO_REMOVE": "MISSING",
+ "DO_YOU_WANT_TO_REMOVE": "Voulez-vous enlever cet utilisateur de votre ferme ?",
"EO": "Officier de vulgarisation",
"FARM_MANAGER": "Gestionnaire de ferme",
"FARM_OWNER": "Propriétaire de la ferme",
"FARM_WORKER": "Ouvrier agricole",
"HOURLY": "horaire",
"INVITE_USER": "Inviter un utilisateur",
- "PAY": "MISSING",
+ "PAY": "Payer",
"RESTORE_ACCESS": "Restaurer l'accès utilisateur",
"REVOKE_ACCESS": "Révoquer l'accès utilisateur",
"ROLE": "Rôle",
"ROLE_CHANGE_ALERT": "Le changement de rôle prendra pleinement effet lors de la prochaine connexion. Les travailleurs ne peuvent pas se définir comme administrateurs.",
"SEARCH": "Chercher",
- "THIS_WILL_REMOVE": "MISSING",
+ "THIS_WILL_REMOVE": "Cette action enlèvera l'utilisateur de votre ferme.",
"USERS_FOUND": "Utilisateurs trouvés"
},
+ "PEOPLE_TAB": "Personnes",
"TABLE": {
"HEADER_EMAIL": "Courriel",
"HEADER_NAME": "Nom",
@@ -1115,6 +1196,13 @@
"HEADER_STATUS": "Statut"
}
},
+ "PROFILE_FLOATER": {
+ "HELP": "Support",
+ "INFO": "Mes infos",
+ "LOG_OUT": "Déconnexion",
+ "SWITCH": "Changer de ferme",
+ "TUTORIALS": "Tutoriels"
+ },
"REACT_SELECT": {
"CLEAR": "Supprimer",
"CLEAR_ALL": "Supprimer tout"
@@ -1128,21 +1216,21 @@
"FARM_EO": "Agent de vulgarisation",
"FARM_MANAGER": "Gestionnaire de ferme",
"FARM_OWNER": "Propriétaire de la ferme",
- "IS_OWNER_OPERATED": "Ce propriétaire de la ferme est-il exploité ?",
- "TITLE": "Quel est votre rôle à la ferme ?"
+ "IS_OWNER_OPERATED": "Ce propriétaire de la ferme est-il exploité\u00a0?",
+ "TITLE": "Quel est votre rôle à la ferme\u00a0?"
},
"SALE": {
"ADD_SALE": {
"CROP_PLACEHOLDER": "Selectionner une récolte",
- "CROP_REQUIRED": "Requie",
- "CROP_VARIETY": "MISSING",
- "CUSTOMER_NAME": "Nom de Client",
- "CUSTOMER_NAME_REQUIRED": "Requi",
+ "CROP_REQUIRED": "Réponse requise",
+ "CROP_VARIETY": "Variété de la culture",
+ "CUSTOMER_NAME": "Nom du Client",
+ "CUSTOMER_NAME_REQUIRED": "Réponse requise",
"DATE": "Date",
"TABLE_HEADERS": {
- "CROP_VARIETIES": "MISSING",
+ "CROP_VARIETIES": "Variété de la culture",
"QUANTITY": "Quantité",
- "TOTAL": "Totale"
+ "TOTAL": "Total"
},
"TITLE": "Ajouter nouvelle vente"
},
@@ -1163,7 +1251,7 @@
"ESTIMATED_REVENUE": {
"CALCULATION": "Calcul",
"CALCULATION_DESCRIPTION": "Nous calculons les revenus estimés à l'aide de la date de fin des cultures estimée dans le module Champs. Pour inclure une culture dans le calcul de vos revenus estimés, assurez-vous de saisir sa date de fin dans la date de fin de votre rapport financier.",
- "TITLE": "MISSING"
+ "TITLE": "Chiffre d'affaires estimé"
},
"EXPENSE_DETAIL": {
"ACTION": "Action",
@@ -1180,11 +1268,11 @@
"ADD_NEW_EXPENSE": "Ajouter une nouvelle dépense",
"ADD_NEW_SALE": "Ajouter une nouvelle vente",
"BALANCE": "Solde",
- "BALANCE_EXPLANATION": "Nous calculons un solde en temps réel (« coût de production ») pour chaque culture de votre ferme. Il s'agit d'une simple équation des dépenses moins les revenus. Les dépenses pour chaque culture sont calculées à partir de deux parties, une partie est le les dépenses de main-d'œuvre provenant des heures enregistrées pour les activités agricoles, l'autre partie provient des autres dépenses enregistrées pour l'ensemble de la ferme. Lorsque les dépenses sont enregistrées pour l'ensemble de la ferme, nous les répartissons également entre les cultures de la ferme. Non alloué signifie qu'un ou plusieurs quarts de travail a été soumis pour un champ alors qu'il n'y a pas encore de culture sur ce champ. Ce ou ces quarts de travail seront attribués aux cultures au fur et à mesure qu'elles sont ajoutées à ce champ dans la fenêtre de temps de rapport financier. ",
+ "BALANCE_EXPLANATION": "Nous calculons un solde en temps réel («\u00a0coût de production\u00a0») pour chaque culture de votre ferme. Il s'agit d'une simple équation des dépenses moins les revenus. Les dépenses pour chaque culture sont calculées à partir de deux parties, une partie est le les dépenses de main-d'œuvre provenant des heures enregistrées pour les activités agricoles, l'autre partie provient des autres dépenses enregistrées pour l'ensemble de la ferme. Lorsque les dépenses sont enregistrées pour l'ensemble de la ferme, nous les répartissons également entre les cultures de la ferme. Non alloué signifie qu'un ou plusieurs quarts de travail a été soumis pour un champ alors qu'il n'y a pas encore de culture sur ce champ. Ce ou ces quarts de travail seront attribués aux cultures au fur et à mesure qu'elles sont ajoutées à ce champ dans la fenêtre de temps de rapport financier. ",
"BALANCE_FOR_FARM": "Solde (Toute la ferme)",
"EXPENSES": "Dépenses",
"FINANCE_HELP": "Aide Financière",
- "LABOUR_LABEL": "Labeur",
+ "LABOUR_LABEL": "Coûts de main-d'œuvre",
"OTHER_EXPENSES_LABEL": "Autres dépenses",
"REVENUE": "Revenu",
"TITLE": "Finances",
@@ -1193,14 +1281,14 @@
},
"LABOUR": {
"BY": "Par",
- "CROPS": "Recoltes",
- "EMPLOYEES": "Personels",
+ "CROPS": "Récoltes",
+ "EMPLOYEES": "Personnels",
"TABLE": {
"AMOUNT": "Quantité",
- "CROP": "Recolte",
+ "CROP": "Récolte",
"DATE": "Date",
- "EMPLOYEE": "Personels",
- "EST_REVENUE": "Revenu extimé",
+ "EMPLOYEE": "Personnels",
+ "EST_REVENUE": "Revenu estimé",
"LABOUR_COST": "Coût de travail",
"TASK": "Tâche",
"TIME": "Temps",
@@ -1217,7 +1305,7 @@
"SUBTOTAL": "Soutotal",
"SUMMARY": "Résumé",
"TITLE": "Ventes",
- "TOTAL": "Totale",
+ "TOTAL": "Total",
"TYPE": "Type",
"VALUE": "Valeur"
}
@@ -1250,7 +1338,7 @@
"SELECT_FIELDS": "Sélectionner les emplacements",
"VERY_HAPPY": "Très heureux",
"VERY_SAD": "Très triste",
- "WHAT_TASKS_YOU_DID": "Quelles tâches avez-vous effectuées aujourd'hui ?",
+ "WHAT_TASKS_YOU_DID": "Quelles tâches avez-vous effectuées aujourd'hui\u00a0?",
"WORKER": "Travailleur",
"WORKER_MOOD": "Comment se sentait cet travailleur pendant qu'il travaillait ?"
},
@@ -1274,26 +1362,28 @@
"TITLE": "Postes"
},
"SIGNUP": {
- "CHANGES": "MISSING",
+ "CHANGES": "En savoir plus sur les changements",
"EMAIL_INVALID": "Courriel non-valide",
- "ENTER_EMAIL": "Saiser votre addresse courriel",
- "EXPIRED_ERROR": "Nous avons mis notre infrastructure à jour vous devrez réinitialiser votre mot de passe. Vérifiez votre boîte de courriels pour continuer.",
+ "ENTER_EMAIL": "Entrez votre adresse courriel",
+ "EXPIRED_ERROR": "Nous avons mis à jour notre infrastructure et vous devriez réinitialiser votre mot de passe. Vérifiez votre boîte de courriels pour continuer.",
+ "EXPIRED_INVITATION_LINK_ERROR": "Invitation invalide ou expirée",
"GOOGLE_BUTTON": "CONTINUER AVEC GOOGLE",
- "INVITED_ERROR": "Nous avons mis notre infrastructure à jour vous devrez réinitialiser votre mot de passe. Vérifiez votre boîte de courriels pour une invitation de ferme pour continuer.",
- "LITEFARM_UPDATED": "MISSING",
+ "INVITED_ERROR": "Nous avons mis notre infrastructure à jour vous devriez réinitialiser votre mot de passe. Vérifiez votre boîte de courriels pour une invitation de ferme pour continuer.",
+ "LITEFARM_UPDATED": "Nous avons mis à jour LiteFarm !",
"PASSWORD_ERROR": "Mot de passe incorrect",
"SIGN_IN": "Se Connecter",
"SSO_ERROR": "Veuillez connecter par cliquer le bouton Google au-dessus",
- "WELCOME_BACK": "Re-bonjour!",
+ "USED_INVITATION_LINK_ERROR": "Cette invitation a déjà été utilisée, veuillez vous connecter pour accéder à cette ferme",
+ "WELCOME_BACK": "Content de te revoir!",
"WRONG_BROWSER": "LiteFarm n'est pas optimisé pour cette navigateur de Web.",
"WRONG_BROWSER_BOTTOM": "Veuillez reconnecter avec Chrome."
},
"SLIDE_MENU": {
- "CROPS": "Recoltes",
+ "CROPS": "Récoltes",
"DOCUMENTS": "Documents",
"FINANCES": "Finances",
- "INSIGHTS": "Intuitions",
- "MANAGE": "Gérer",
+ "MANAGE": "Gestion",
+ "INSIGHTS": "Mesures additionnelles",
"TASKS": "Tâches"
},
"STATUS": {
@@ -1302,9 +1392,9 @@
"INVITED": "Invité"
},
"SURVEY_STACK": {
- "PRODUCED": "MISSING",
- "SURVEY_ADDENDUM": "MISSING",
- "TITLE": "MISSING"
+ "PRODUCED": "Produit le",
+ "SURVEY_ADDENDUM": "Addenda au sondage",
+ "TITLE": "{{certification}} certification de {{certifier}}"
},
"SWITCH_OUTRO": {
"BUTTON": "Allons-y !",
@@ -1315,21 +1405,19 @@
"TABLE": {
"LOADING_TEXT": "Chargement en cours...",
"NEXT_TEXT": "Suivant",
- "NO_DATA_TEXT": "Rangs non-trouvés",
+ "NO_DATA_TEXT": "Aucune rangée trouvée",
"OF_TEXT": "de",
"PAGE_TEXT": "Page",
"PREVIOUS_TEXT": "Précédent",
- "ROWS_TEXT": "rangs"
+ "ROWS_TEXT": "ligne"
},
"TASK": {
- "ABANDON_TASK": "Laisser cette tâche",
- "ABANDON_TASK_DURATION": "MISSING",
"ABANDON": {
- "ABANDON": "Abandon",
+ "ABANDON": "Abandonner",
+ "DATE": "Date d'abandon",
"INFO": "Abandonner cette tâche changera son statut à Abandonné et la supprimera de tous utilisateurs sure les listes 'À faire' et 'non-assigné'.",
"NOTES": "Notes d'abandon de tâche",
"NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
- "REASON_FOR_ABANDONMENT": "Raison de l'abandon",
"REASON": {
"CROP_FAILURE": "Échec de la récolte",
"LABOUR_ISSUE": "Problème du travail",
@@ -1339,10 +1427,14 @@
"SCHEDULING_ISSUE": "Problème de planification",
"WEATHER": "Météo"
},
+ "REASON_FOR_ABANDONMENT": "Raison de l'abandon",
"TITLE": "Abandonner la tâche",
- "WHAT_HAPPENED": "Que s'est-il passé ?"
+ "WHAT_HAPPENED": "Que s'est-il passé\u00a0?",
+ "WHEN": "Quand la tâche a-t-elle été abandonnée ?"
},
- "ABANDONMENT_DETAILS": "MISSING",
+ "ABANDON_TASK": "Laisser cette tâche",
+ "ABANDON_TASK_DURATION": "Des travaux ont-ils été réalisés pour cette tâche ?",
+ "ABANDONMENT_DETAILS": "Détails de l'abandon de tâche",
"ADD_CUSTOM_HARVEST_USE": "Créer une utilisation de récolte personnalisée",
"ADD_HARVEST_USE": "Ajouter une autre utilisation de récolte",
"ADD_TASK": "Créer une tâche",
@@ -1353,50 +1445,74 @@
"MULTIPLE_CROPS": "Plusieurs cultures",
"MULTIPLE_LOCATIONS": "Plusieurs emplacements"
},
- "COMPLETE_HARVEST_QUANTITY": "Combien a été récolté ?",
+ "COMPLETE": {
+ "DATE": "Date d'achèvement",
+ "WHEN": "Quand la tâche a-t-elle été terminée ?"
+ },
+ "COMPLETE_HARVEST_QUANTITY": "Combien a été récolté\u00a0?",
"COMPLETE_TASK": "Terminer la tâche",
- "COMPLETE_TASK_CHANGES": "Avez-vous dû apporter des modifications à cette tâche ?",
- "COMPLETE_TASK_DURATION": "Combien de temps la tâche a-t-elle pris pour se terminer ?",
+ "COMPLETE_TASK_CHANGES": "Avez-vous dû apporter des modifications à cette tâche\u00a0?",
+ "COMPLETE_TASK_DURATION": "Combien de temps la tâche a-t-elle pris pour se terminer\u00a0?",
"COMPLETE_TASK_FLOW": "achèvement de la tâche",
- "COMPLETION_DETAILS": "MISSING",
- "COMPLETION_NOTES": "Notes de fin de tâche",
+ "COMPLETION_DETAILS": "Détails de la tâche",
+ "COMPLETION_NOTES": "Notes sur la tâche",
"COMPLETION_NOTES_CHAR_LIMIT": "Les notes doivent comporter moins de 10 000 caractères",
- "CREATE_CUSTOM_HARVEST_USE": "MISSING",
- "CURRENT": "MISSING",
- "DESCRIBE_HARVEST_USE": "MISSING",
+ "CREATE_CUSTOM_HARVEST_USE": "Créer une utilisation de récolte personnalisée",
+ "CURRENT": "Courant",
+ "DESCRIBE_HARVEST_USE": "Décrivez l'utilisation de la récolte",
"DETAILS": "Détails",
- "DID_YOU_ENJOY": "Avez-vous apprécié cette tâche ?",
+ "DID_YOU_ENJOY": "Avez-vous apprécié cette tâche\u00a0?",
"DUE_DATE": "Date d'échéance",
"DURATION": "Durée",
+ "FILTER": {
+ "ASCENDING": "du plus ancien",
+ "ASSIGNEE": "Cessionnaire",
+ "CROP": "Culture",
+ "DATE_RANGE": "Filtrer par plage de dates",
+ "DESCENDING": "du plus récent",
+ "FROM": "De",
+ "LOCATION": "Emplacement",
+ "MY_TASK": "Mes tâches",
+ "SORT_BY": "Trier par",
+ "STATUS": "Status",
+ "TITLE": "Filtre de tâches",
+ "TO": "De",
+ "TYPE": "Type",
+ "UNASSIGNED": "Non attribué",
+ "VIEW": "Regarder"
+ },
"HARVEST_USE": "Utilisation de la récolte",
- "HARVEST_USE_ALREADY_EXISTS": "MISSING",
- "HOW_WILL_HARVEST_BE_USED": "Comment la récolte sera-t-elle utilisée ?",
+ "HARVEST_USE_ALREADY_EXISTS": "L'utilisation de la récolteexiste déjà",
+ "HOW_WILL_HARVEST_BE_USED": "Comment la récolte sera-t-elle utilisée\u00a0?",
"LOCATIONS": "Emplacement(s)",
"NO_TASKS_TO_DISPLAY": "Il n'y a aucune tâche à afficher.",
"NO_WORK_DONE": "Aucun travail n'a été terminé",
"PAGE_TITLE": "Tâches",
"PREFER_NOT_TO_SAY": "Je préfère ne pas dire",
"PROVIDE_RATING": "Fournir une note",
- "QUANTITY_CANNOT_EXCEED": "MISSING",
- "RATE_THIS_TASK": "MISSING",
+ "QUANTITY_CANNOT_EXCEED": "La quantité de récolte utilisée ne peut pas dépasser la quantité à allouer",
+ "RATE_THIS_TASK": "Évaluez cette tâche",
"REMOVE_HARVEST_USE": "Supprimer",
"SELECT_DATE": "Sélectionnez la date de la tâche",
"SELECT_TASK_LOCATIONS": "Sélectionnez le(s) emplacement(s) de la tâche",
- "SELECT_WILD_CROP": "MISSING",
- "TASK": "tâche",
- "TASKS_COUNT": "{{count}} tâche",
- "TASKS_COUNT_plural": "{{count}} tâches",
- "TODO": "À faire",
- "TRANSPLANT": "MISSING",
- "TRANSPLANT_LOCATIONS": "Sélectionnez un lieu de transplantation",
- "UNASSIGNED": "Non affecté",
+ "SELECT_WILD_CROP": "Cette tâche cible une culture sauvage",
"STATUS": {
"ABANDONED": "Abandonné",
"COMPLETED": "Terminé",
"FOR_REVIEW": "Pour évaluer",
"LATE": "Tard",
"PLANNED": "Planifié"
- }
+ },
+ "TASK": "tâche",
+ "TASKS_COUNT": "{{count}} tâche",
+ "TASKS_COUNT_one": "{{count}} tâche",
+ "TASKS_COUNT_many": "{{count}} tâches",
+ "TASKS_COUNT_other": "{{count}} tâches",
+ "TASKS_COUNT_plural": "{{count}} tâches",
+ "TODO": "À faire",
+ "TRANSPLANT": "Transplantation",
+ "TRANSPLANT_LOCATIONS": "Sélectionnez un lieu de transplantation",
+ "UNASSIGNED": "Non attribué"
},
"UNIT": {
"TIME": {
@@ -1415,6 +1531,6 @@
"BUTTON": "Commençons par la première étape"
},
"YEAR_SELECTOR": {
- "TITLE": "Selectionnez année"
+ "TITLE": "Selectionnez une année"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/pt/common.json b/packages/webapp/public/locales/pt/common.json
index 6ee00cd90f..f2865c5d8e 100644
--- a/packages/webapp/public/locales/pt/common.json
+++ b/packages/webapp/public/locales/pt/common.json
@@ -14,6 +14,7 @@
"DELETE": "Excluir",
"DO_NOT_SHOW": "Não mostrar esta mensagem novamente",
"EDIT": "Editar",
+ "EDIT_DATE": "Editar data",
"EXPORT": "Exportar",
"FINISH": "Finalizar",
"FROM": "de",
@@ -23,15 +24,17 @@
"HOURS": "Horas",
"LOADING": "Carregando...",
"MARK_ABANDON": "Abandonar",
- "MARK_COMPLETE": "Tarefa concluída",
- "MARK_COMPLETED": "Tarefa concluída",
+ "MARK_COMPLETE": "Plano completo",
+ "MARK_COMPLETED": "Plano concluído",
"MAX_ERROR": "Insira um valor menor que {{value}}",
"MIN_ERROR": "Insira um valor maior que {{value}}",
"NAME": "Nome",
+ "NEEDS_PLAN": "É necessário um plano",
"NEXT": "Próximo",
"NO": "Não",
"NOT_SURE": "Não tem certeza",
"NOTES": "Notas",
+ "OK": "Ok",
"OPTIONAL": "(Opcional)",
"OTHER": "Outro",
"PAST": "Passado",
@@ -44,11 +47,13 @@
"SAVE_CHANGES": "Salvar mudanças",
"SEARCH": "Buscar",
"SELECT": "Selecionar",
+ "CREATE": "Adicionar",
+ "SKIP": "Pular",
"SORRY": "Desculpa",
"SUBMIT": "Enviar",
"SUBMITTING": "Enviando...",
"UPDATE": "Atualizar",
"WORD_LIMIT_ERROR": "Somente {{value}} caractéres podem ser exibidos",
- "YES": "Sim",
- "EDIT_DATE": "Editar data"
+ "YEAR": "Ano",
+ "YES": "Sim"
}
diff --git a/packages/webapp/public/locales/pt/crop.json b/packages/webapp/public/locales/pt/crop.json
index 5302ecec7e..bbc3a50894 100644
--- a/packages/webapp/public/locales/pt/crop.json
+++ b/packages/webapp/public/locales/pt/crop.json
@@ -70,7 +70,7 @@
"CHILI_DRY_ALL_VARIETIES": "Pimenta, seca (todas as variedades)",
"CHILI_FRESH_ALL_VARIETIES": "Pimenta, fresca (todas as variedades)",
"CINNAMON": "Canela",
- "CITRON": "Citron (Citrus medica)",
+ "CITRON": "Cidra (Citrus medica)",
"CITRONELLA": "Citronela",
"CLEMENTINE": "Clementina",
"CLOVE": "Cravo-da-índia",
@@ -99,7 +99,7 @@
"CUSTARD_APPLE": "Fruta-do-conde",
"DASHEEN": "Taioba",
"DATES": "Tâmara",
- "DRUMSTICK_TREE": "Moringa",
+ "DRUMSTICK_TREE": "Marang/Marangue",
"DURRA_SORGHUM": "Sorgo",
"DURUM_WHEAT": "Trigo durum (semolina)",
"EARTH_PEA": "Amendoim",
@@ -360,7 +360,7 @@
"BELL_PEPPER": "Pimentão",
"BERGAMOT_ORANGE": "Bergamota",
"BIG_LEAF_MAHOGANY_MOGNO_BRASILEIRO": "Mogno",
- "BILIMBI": "Piripiri",
+ "BILIMBI": "Biribiri",
"BLACK_OATS": "Aveia negra",
"BRAZILIAN_GRAPE_TREE": "Jabuticaba",
"BRAZILWOOD_TREE": "Pau-brasil",
@@ -376,7 +376,7 @@
"CHIA": "Chia",
"CHICHÁ_DO_CERRADO": "Chichá do Cerrado",
"CHIVE": "Cebolinha",
- "CHUPA_CHUPA": "Chupa-chupa",
+ "CHUPA_CHUPA": "Sapota-do-Solimões",
"CILANTRO": "Coentro",
"COCHINEAL_CACTUS_PALMA_NOPAL": "Nopal",
"COCOYAM_NEW_COCOYAM_XANTHOSOMA_SPP": "Taro",
@@ -420,7 +420,7 @@
"MAIZE_FOR_SILAGE": "Milho para silagem",
"MANGOSTEEN": "Mangostão",
"MANGOSTEEN_FALSE_FALSE_MANGOSTEEN": "Falso Mangostão",
- "MARANG": "Moringa",
+ "MARANG": "Marang/Marangue",
"MARCELA": "Macela",
"MARJORAM": "Manjerona",
"MIGNONETTE_VINE": "Trepadeira da madeira",
@@ -480,7 +480,7 @@
"TREE_SPINACH": "Espinafre de árvore",
"TRITICALE": "Triticale",
"TROPICAL_ALMOND_TREE_AMENDOEIRA_DA_PRAIA_SETE_COPAS": "Amendoeira da Praia (Sete Copas)",
- "TURMERIC": "Turmeric",
+ "TURMERIC": "Cúrcuma/Açafrão-da-terra",
"UVAIA": "Uvaia",
"VELVET_BEAN": "Mucuna",
"WEST_INDIAN_GHERKIN": "Maxixe",
diff --git a/packages/webapp/public/locales/pt/disease.json b/packages/webapp/public/locales/pt/disease.json
index 2c40e0a124..3d5b05999d 100644
--- a/packages/webapp/public/locales/pt/disease.json
+++ b/packages/webapp/public/locales/pt/disease.json
@@ -287,7 +287,6 @@
"EUROPEAN_CORN_BORER": "Ostrinia nubilalis",
"CORN_EARWORM": "Lagarta-da-espiga",
"JASSIDS_ON_PEANUT": "Cigarrinhas no Amendoim",
- "MEALYBUG": "Colchonilha-farinhenta",
"COTTONY_CUSHION_SCALE": "Pulgão Branco",
"MANGO_FRUIT_FLY": "Mosca-da-fruta da Manga",
"FLEA_BEETLE": "Besouro Saltador",
diff --git a/packages/webapp/public/locales/pt/filter.json b/packages/webapp/public/locales/pt/filter.json
index b7b9ee1791..cf8889b338 100644
--- a/packages/webapp/public/locales/pt/filter.json
+++ b/packages/webapp/public/locales/pt/filter.json
@@ -18,6 +18,24 @@
"SOIL_AMENDMENT": "Correção de solo",
"SOIL_SAMPLE_RESULTS": "Resultados da amostra de solo",
"WATER_SAMPLE_RESULTS": "Resultados da amostra de água",
- "UNCATEGORIZED": "Não categorizado"
+ "UNCATEGORIZED": "Não categorizado",
+ "RECEIPTS": "Recibos",
+ "INVOICES": "Faturas"
+ },
+ "TASKS": {
+ "ABANDONED": "Abandonada",
+ "ACTIVE": "Ativa",
+ "COMPLETED": "Completa",
+ "FOR REVIEW": "Para revisão",
+ "LATE": "Atrasada",
+ "LOCATION": "Localização",
+ "PLANNED": "Planejada",
+ "STATUS": "Situação",
+ "SUPPLIERS": "Fornecedores"
+ },
+ "FILTER": {
+ "VALID_ON": "Válido em",
+ "FROM_DATE": "De",
+ "TO_DATE": "Até"
}
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/public/locales/pt/message.json b/packages/webapp/public/locales/pt/message.json
index 7b51e630f5..adb59cd71d 100644
--- a/packages/webapp/public/locales/pt/message.json
+++ b/packages/webapp/public/locales/pt/message.json
@@ -7,15 +7,25 @@
"ERROR": {
"CREATE": "Falha ao criar documento",
"FAILED_ARCHIVE": "Falha ao arquivar o documento",
+ "FAILED_UNARCHIVE": "Falha ao desarquivar documento",
"FAILED_UPLOAD": "Anexos não carregados",
"UPDATE": "Falha ao atualizar o documento"
},
"SUCCESS": {
"ARCHIVE": "Documento arquivado com sucesso",
"CREATE": "Documento criado com sucesso",
+ "UNARCHIVE": "Documento desarquivado com sucesso",
"UPDATE": "Documento atualizado com sucesso"
}
},
+ "CROP": {
+ "ERROR": {
+ "DELETE": "Falha na exclusão do cultivo de campo"
+ },
+ "SUCCESS": {
+ "DELETE": "Cultivo excluído com sucesso"
+ }
+ },
"CROP_VARIETY": {
"ERROR": {
"ADD": "Erro: falha ao adicionar variedade ao banco de dados",
@@ -24,19 +34,11 @@
"UPDATE": "Falha ao atualizar variedade de cultivo"
},
"SUCCESS": {
- "ADD": "Variedade salvo com sucesso!",
+ "ADD": "Variedade salva com sucesso!",
"DELETE": "Variedade de cultivo deletado",
"UPDATE": "Variedade de cultivo atualizada com sucesso"
}
},
- "CROP": {
- "ERROR": {
- "DELETE": "Falha na exclusão do cultivo de campo"
- },
- "SUCCESS": {
- "DELETE": "Cultivo excluído com sucesso"
- }
- },
"EXPENSE": {
"ERROR": {
"ADD": "Falha de adicionar novas despesas",
@@ -76,22 +78,22 @@
},
"MANAGEMENT_PLAN": {
"ERROR": {
- "ABANDON": "Erro em abandonar o plano de manejo!",
- "COMPLETE": "Erro ao completar o plano de manejo!",
- "POST": "Erro ao adicionar plano de gestão!"
+ "ABANDON": "Erro em abandonar o plano de cultivo!",
+ "COMPLETE": "Erro ao completar o plano de cultivo!",
+ "POST": "Erro ao adicionar plano de cultivo!"
},
"SUCCESS": {
- "ABANDON": "Plano de manejo abandonado com sucesso!",
- "COMPLETE": "Plano de manejo concluído com sucesso! ",
- "POST": "Plano de gestão adicionado com sucesso!"
+ "ABANDON": "Plano de cultivo abandonado com sucesso!",
+ "COMPLETE": "Plano de cultivo concluído com sucesso! ",
+ "POST": "Plano de cultivo adicionado com sucesso!"
}
},
"MAP": {
"FAIL_PATCH": "Falha ao atualizar",
- "FAIL_POST": "Falha ao adicionar novo",
- "SUCCESS_DELETE": " retirado com sucesso",
- "SUCCESS_PATCH": " atualizado com sucesso",
- "SUCCESS_POST": " salvo com sucesso"
+ "FAIL_POST": "Falha ao adicionar novo/a",
+ "SUCCESS_DELETE": " retirado/a com sucesso",
+ "SUCCESS_PATCH": " atualizado/a com sucesso",
+ "SUCCESS_POST": " salvo/a com sucesso"
},
"ORGANIC_CERTIFIER_SURVEY": {
"ERROR": {
@@ -101,10 +103,10 @@
},
"PLAN": {
"ERROR": {
- "EDIT": "Falha ao atualizar o plano de manejo"
+ "EDIT": "Falha ao atualizar o plano de cultivo"
},
"SUCCESS": {
- "EDIT": "Plano de manejo atualizado com sucesso"
+ "EDIT": "Plano de cultivo atualizado com sucesso"
}
},
"REVENUE": {
@@ -144,16 +146,6 @@
"UPDATE": "Turno atualizado com sucesso!"
}
},
- "TASK_TYPE": {
- "CREATE": {
- "FAILED": "Erro ao criar tarefa personalizada",
- "SUCCESS": "Tarefa personalizada criada com sucesso"
- },
- "DELETE": {
- "FAILED": "Erro ao deletar tarefa personalizada",
- "SUCCESS": "Tarefa personalizada deletada com sucesso"
- }
- },
"TASK": {
"ABANDON": {
"FAILED": "Erro ao completar tarefa",
@@ -168,6 +160,16 @@
"SUCCESS": "Tarefa concluída com sucesso"
}
},
+ "TASK_TYPE": {
+ "CREATE": {
+ "FAILED": "Erro ao criar tarefa personalizada",
+ "SUCCESS": "Tarefa personalizada criada com sucesso"
+ },
+ "DELETE": {
+ "FAILED": "Erro ao deletar tarefa personalizada",
+ "SUCCESS": "Tarefa personalizada deletada com sucesso"
+ }
+ },
"USER": {
"ERROR": {
"ADD": "Falha de adicionar usuário",
diff --git a/packages/webapp/public/locales/pt/translation.json b/packages/webapp/public/locales/pt/translation.json
index c140370377..187717bead 100644
--- a/packages/webapp/public/locales/pt/translation.json
+++ b/packages/webapp/public/locales/pt/translation.json
@@ -8,7 +8,8 @@
"FARM_LOCATION": "Localização do sítio/fazenda",
"FARM_LOCATION_INPUT_INFO": "Endereço ou latitude e longitude separados por vírgula (ex.: 49.250945, -123.238492)",
"FARM_NAME": "Nome do sítio/fazenda",
- "INVALID_FARM_LOCATION": "Localização do sítio/fazenda inválida",
+ "FARM_NAME_ERROR": "Limite de caracteres do nome do farm excedido",
+ "INVALID_FARM_LOCATION": "Nenhum país para esta localização",
"LOCATING": "Localizando...",
"NO_ADDRESS": "Localização não encontrada. Tente inserir latitue e longitude",
"TELL_US_ABOUT_YOUR_FARM": "Conte-nos sobre seu sítio/fazenda"
@@ -25,6 +26,7 @@
"ADD_CUSTOM_TASK": "Adicionar tarefa personalizada",
"AFFECT_PLANS": "Esta tarefa influenciará em algum plano",
"ASSIGN_ALL_TO_PERSON": "Atribuir todas as tarefas não atribuídas nesta data a esta pessoa",
+ "ASSIGN_DATE": "Atribuir data de vencimento",
"ASSIGN_TASK": "Atribuir tarefa",
"ASSIGNEE": "Responsável",
"CANCEL": "criação de tarefa",
@@ -45,7 +47,6 @@
"EDIT_CUSTOM_TASK": "Editar tarefa personalizada",
"FIELD_WORK_VIEW": {
"OTHER_TYPE_OF_FIELD_WORK": "Descreva o tipo de trabalho de campo",
- "TYPE_OF_FIELD_WORK": "Tipo de trabalho de campo",
"TYPE": {
"COVERING_SOIL": "Cobertura de solo",
"FENCING": "Barreira",
@@ -56,7 +57,8 @@
"TERMINATION": "Conclusão",
"TILLAGE": "Preparo do solo/cultivo",
"WEEDING": "Capina"
- }
+ },
+ "TYPE_OF_FIELD_WORK": "Tipo de trabalho de campo"
},
"GO_TO_CATALOGUE": "Vá ao catálogo de cultivos",
"HARVEST_EVERYTHING": "Colher tudo que estiver pronto",
@@ -64,8 +66,8 @@
"HOW_MUCH_IS_HARVESTED": "Quanto está sendo colhido?",
"HR": "/hr",
"MANAGE_CUSTOM_TASKS": "Gerenciar tarefas personalizadas",
- "NEED_MANAGEMENT_PLAN": "Você precisará de um plano de manejo de cultura ativo ou planejado antes de poder agendar uma tarefa de colheita ou tarefa de transplante. Vá para o catálogo de safras para criar um plano agora.",
- "NO_MANAGEMENT_PLAN": "Não há plano de manejo de safra elegível",
+ "NEED_MANAGEMENT_PLAN": "Você precisará de um plano de cultivo ativo ou planejado antes de poder agendar uma tarefa de colheita ou tarefa de transplante. Vá para o catálogo de safras para criar um plano agora.",
+ "NO_MANAGEMENT_PLAN": "Não há plano de cultivo de safra elegível",
"PEST_CONTROL_VIEW": {
"BIOLOGICAL_CONTROL": "Controle biológico",
"FLAME_WEEDING": "Capina com fogo",
@@ -84,7 +86,7 @@
"PLANTING_METHOD": "Método de plantio",
"PLANTING_STOCK": "Muda",
"PLANTING_TASK": "Tarefa de plantio",
- "PLANTING_TASK_MODAL": "Quando se inicia uma nova tarefa, um novo plano de manejo é criado. Vá ao catálogo de cultivos para selecionar o cultivo que você gostaria de plantar.",
+ "PLANTING_TASK_MODAL": "Quando se inicia uma nova tarefa de plantio, um novo plano de cultivo é criado. Vá ao catálogo de cultivos para selecionar o cultivo que você gostaria de plantar.",
"QUANTITY": "Quantidade",
"RETIRE_CUSTOM_TASK": "Retirar tarefa personalizada?",
"RETIRE_CUSTOM_TASK_CONTENT": "Tem certeza que você quer deletar essa tarefa?",
@@ -147,16 +149,16 @@
},
"CERTIFICATION_SELECTION": {
"REQUEST_CERTIFICATION": "Solicite outro tipo de certificação",
- "SUBTITLE_ONE": "Aqui está uma lista de certificadores de",
+ "SUBTITLE_ONE": "Aqui está uma lista de certificadoras de",
"SUBTITLE_TWO": "com quem trabalhamos no seu país.",
"TITLE": "Qual tipo de certificação?",
"TOOLTIP": "Não vê a sua certificação? O LiteFarm é dedicado a apoiar a agricultura sustentável e certificações são uma grande parte disso. Solicite outro tipo de certificação aqui e faremos nosso melhor para incorporá-la ao aplicativo."
},
"CERTIFIER_SELECTION": {
- "INFO": "Isso provavelmente significa que o LiteFarm atualmente não trabalha com o seu certificador. O LiteFarm, porém, produz formulários genéricos que são úteis na maioria dos casos.",
- "NOT_FOUND": "Não vê o seu certificador?",
- "REQUEST_CERTIFIER": "Solicite um certificador",
- "TITLE": "Quem é seu certificador?"
+ "INFO": "Isso provavelmente significa que o LiteFarm atualmente não trabalha com o sua certificadora. O LiteFarm, porém, produz formulários genéricos que são úteis na maioria dos casos.",
+ "NOT_FOUND": "Não vê o sua certificadora?",
+ "REQUEST_CERTIFIER": "Solicite uma certificadora",
+ "TITLE": "Quem é sua certificadora?"
},
"INPUT_PLACEHOLDER": "Digite para buscar",
"INTERESTED_IN_CERTIFICATION": {
@@ -165,16 +167,16 @@
"WHY_ANSWER": "LiteFarm gera formulários necessários para certificação orgânica e/o agroecológica. Algumas informações serão obrigatórias."
},
"REQUEST_CERTIFIER": {
- "LABEL": "Certificador solicitado",
- "REQUEST": "Qual certificador gostaria de solicitar?",
- "SORRY_ONE": "Desculpe - atualmente não trabalhamos com nenhum certificador",
+ "LABEL": "Certificadora solicitado",
+ "REQUEST": "Qual certificadora gostaria de solicitar?",
+ "SORRY_ONE": "Desculpe - atualmente não trabalhamos com nenhuma certificadora",
"SORRY_THREE": "em seu país. Gostaria de solicitar um?",
"SORRY_TWO": "Gostaria de solicitar um?",
- "TITLE": "Solicite um certificador"
+ "TITLE": "Solicite uma certificadora"
},
"SUMMARY": {
"BAD_NEWS": "LiteFarm atualmente não coleta as informações que você precisa para gerar seus documentos de certificação.",
- "BAD_NEWS_INFO": "No entanto, podemos criar formulários genéricos que são úteis para a maioria dos certificadores. Nós vamos indicar estas informações através do aplicativo com um ícone de folha",
+ "BAD_NEWS_INFO": "No entanto, podemos criar formulários genéricos que são úteis para a maioria das certificadoras. Nós vamos indicar estas informações através do aplicativo com um ícone de folha",
"CERTIFICATION": "certificação",
"GOOD_NEWS": "Boas notícias! O LiteFarm pode documentar as informações que você precisa para gerar seus documentos de certificação!",
"INFORMATION": "Nós indicaremos estas informações no aplicativo com um ícone de folha.",
@@ -182,19 +184,10 @@
"YOUR_CERTIFICATION": "Sua certificação"
}
},
- "CERTIFICATIONS_MODAL": {
- "MAYBE_LATER": "Talvez mais tarde",
- "STEP_ONE": {
- "DESCRIPTION": "Adicionamos suporte para certificações e certificadores! Quer ver o que está disponível em sua área?",
- "TITLE": "Novo recurso!"
- },
- "STEP_TWO": {
- "DESCRIPTION": "Tudo bem! Você pode adicionar certificações e certificadores mais tarde, na opção “minha propriedade”.",
- "TITLE": "Ver certificações"
- }
- },
"CERTIFICATIONS": {
"COULD_NOT_CONTACT_CERTIFIER": "It looks like LiteFarm wasn’t able to contact your certifier. You can still export your documents but your certifier may require additional information.",
+ "EMAIL": "Email",
+ "EMAIL_ERROR": "É necessário um e-mail válido",
"EXPORT": "Exportar",
"EXPORT_DOCS": "Exportar documentos da certificação",
"EXPORT_DOWNLOADING_MESSAGE": "Baixando seus arquivos de certificação orgânica...",
@@ -208,10 +201,19 @@
"ORGANIC_CERTIFICATION_FROM": "Certificação orgânica de",
"SELECT_REPORTING_PERIOD": "Selecione o período do seu relatório",
"UH_OH": "Uh oh!",
- "WOULD_LIKE_ANSWERS": "A certificadora gostaria que você respondesse algumas perguntas extras antes de nós exportarmos seus documentos.",
- "EMAIL": "Email",
- "EMAIL_ERROR": "É necessário um e-mail válido",
- "WHERE_TO_SEND_DOCS": "Para onde você quer que os seus documentos sejam enviados?"
+ "WHERE_TO_SEND_DOCS": "Para onde você quer que os seus documentos sejam enviados?",
+ "WOULD_LIKE_ANSWERS": "A certificadora gostaria que você respondesse algumas perguntas extras antes de nós exportarmos seus documentos."
+ },
+ "CERTIFICATIONS_MODAL": {
+ "MAYBE_LATER": "Talvez mais tarde",
+ "STEP_ONE": {
+ "DESCRIPTION": "Adicionamos suporte para certificações e certificadoras! Quer ver o que está disponível em sua área?",
+ "TITLE": "Novo recurso!"
+ },
+ "STEP_TWO": {
+ "DESCRIPTION": "Tudo bem! Você pode adicionar certificações e certificadoras mais tarde, na opção “minha propriedade”.",
+ "TITLE": "Ver certificações"
+ }
},
"CHOOSE_FARM": {
"ADD_NEW": "Adicionar novo sítio/fazenda",
@@ -242,31 +244,54 @@
"PASSWORD": "Senha",
"TITLE": "Criar uma nova conta de usuário"
},
+ "CROP": {
+ "ADD_COMPLIANCE_FILE": "Link para um arquivo de conformidade",
+ "ADD_CROP": "Adicionar um cultivo",
+ "ADD_IMAGE": "Adicionar imagem personalizada",
+ "ANNUAL": "Anual",
+ "ANNUAL_OR_PERENNIAL": "O cultivo é anual ou perene?",
+ "EDIT_CROP": "Editar cultivo",
+ "EDIT_MODAL": {
+ "BODY": "A edição deste cultivo não modificará nenhum plano de cultivo de cultivo existente. Apenas os planos de cultivo criados após suas edições serão afetados. Continuar com a edição?",
+ "TITLE": "Editar cultivo?"
+ },
+ "IS_GENETICALLY_ENGINEERED": "Este cultivo é geneticamente modificada?",
+ "IS_ORGANIC": "A semente ou cultivo é orgânica certificada?",
+ "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Sua certificadora pode solicitar documentação que comprove sua afirmação de que este cultivo não foi geneticamente modificado.",
+ "NEED_DOCUMENT_PERFORM_SEARCH": "Sua certificadora pode solicitar documentação de suporte à sua busca.",
+ "NEED_DOCUMENT_TREATED": "Sua certificadora pode solicitar documentação descrevendo quaisquer tratamentos.",
+ "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrientes da parte ingerida (por 100g)",
+ "PERENNIAL": "Perene",
+ "PERFORM_SEARCH": "Você fez uma busca de disponibilidade comercial?",
+ "PHYSIOLOGY_AND_ANATOMY": "Fisiologia e Anatomia",
+ "TREATED": "As sementes desta cultivo foram tratadas?",
+ "UPLOAD_LATER": "Você também pode fazer upload de arquivos posteriormente"
+ },
"CROP_CATALOGUE": {
"ADD_CROP": "Adicionar um novo cultivo",
"ADD_CROPS_T0_YOUR_FARM": "Adicionar cultivos à sua fazenda",
"ADD_TO_YOUR_FARM": "Adicionar à sua fazenda",
"CAN_NOT_FIND": "Não consegue encontrar o que está procurando?",
"COVER_CROP": "Isso pode ser cultivado como uma cultivo de cobertura?",
- "CREATE_MANAGEMENT_PLANS": "Crie planos de cultivo",
+ "CREATE_MANAGEMENT_PLANS": "Criar um plano de cultivo",
"CROP_CATALOGUE": "Catálogo de cultivo",
"CROP_GROUP": "Grupo de cultivo",
"CROP_GROUP_TOOL_TIP": "A seleção de um grupo de cultivo permite que a LiteFarm preencha várias informações sobre este cultivo, como estação de crescimento, valores nutricionais e produtividade estimada. Não se preocupe, você pode alterar os valores abaixo depois de selecionar um grupo de cultivo.",
- "DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Documente as informações necessárias para a produção orgânica",
+ "CROP_STATUS": "Situação de cultivo ativo ",
+ "DOCUMENT_NECESSARY_INFO_FOR_ORGANIC_PRODUCTION": "Documentar as informações necessárias para a produção orgânica",
"FILTER": {
"LOCATION": "Localização",
- "STATUS": "Status",
+ "STATUS": "Situação",
"SUPPLIERS": "Fornecedores",
"TITLE": "Título"
},
+ "FILTER_TITLE": "Filtro de catálogo de cultivo",
"HERE_YOU_CAN": "Aqui você pode:",
"LETS_BEGIN": "Vamos começar!",
- "NEW_CROP_NAME": "Nome novo da cultura",
+ "NEW_CROP_NAME": "Nome do cultivo",
"NO_RESULTS_FOUND": "Nenhum resultado encontrado. Por favor, mude seus filtros.",
"ON_YOUR_FARM": "Em sua fazenda",
- "SELECT_A_CROP": "Selecione um cultivo para adicioná-lo à sua fazenda. Use a busca e os filtros para encontrar as culturas mais rapidamente.",
- "CROP_STATUS": "Status de cultivo ativo ",
- "FILTER_TITLE": "Filtro de catálogo de cultivo"
+ "SELECT_A_CROP": "Selecione um cultivo para adicioná-lo à sua fazenda. Use a busca e os filtros para encontrar os cultivos mais rapidamente."
},
"CROP_DETAIL": {
"ADD_PLAN": "Adicionar um plano",
@@ -281,7 +306,7 @@
"MANAGEMENT_TAB": "Manejo",
"ORGANIC": "A semente ou cultivo é orgânica certificada?",
"PERENNIAL": "Perene",
- "TREATED": "As sementes desta cultura foram tratadas?"
+ "TREATED": "As sementes deste cultivo foram tratadas?"
},
"CROP_MANAGEMENT": {
"GERMINATE": "Germinar",
@@ -296,48 +321,27 @@
"CROP_VARIETIES": "variedade",
"NEEDS_PLAN": "Precisa de um plano",
"RETIRE": {
- "CONFIRMATION": "Retirar este cultivo irá removê-la e todos os seus planos de cultivo de seu catálogo de cultivos. Você quer prosseguir?",
- "RETIRE_CROP_TITLE": "Retirar colheita?",
- "UNABLE_TO_RETIRE": "Você só pode retirar cultivos que não tenham planos de cultivo ativos ou futuros. Você precisará concluir ou abandonar esses planos para retirar este cultivo",
- "UNABLE_TO_RETIRE_TITLE": "Incapaz de se retirar"
+ "CONFIRMATION": "Retirar este cultivo irá removê-la e todos os planos de cultivo de seu catálogo de cultivos. Você quer prosseguir?",
+ "RETIRE_CROP_TITLE": "Retirar cultivo?",
+ "UNABLE_TO_RETIRE": "Você só pode retirar cultivos que não tenham um plano de cultivo ativos ou futuros. Você precisará concluir ou abandonar esses planos para retirar este cultivo",
+ "UNABLE_TO_RETIRE_TITLE": "Não foi possível retirar o cultivo"
},
"SUPPLIER": "Fornecedor"
},
- "CROP": {
- "ADD_CROP": "Adicionar um cultivo",
- "ADD_IMAGE": "Adicionar imagem personalizada",
- "ANNUAL": "Anual",
- "ANNUAL_OR_PERENNIAL": "O cultivo é anual ou perene?",
- "EDIT_CROP": "Editar cultivo",
- "EDIT_MODAL": {
- "BODY": "A edição deste cultivo não modificará nenhum plano de manejo de cultivo existente. Apenas os planos de gerenciamento criados após suas edições serão afetados. Continuar com a edição?",
- "TITLE": "Editar cultivo?"
- },
- "IS_GENETICALLY_ENGINEERED": "Este cultivo é geneticamente modificada?",
- "IS_ORGANIC": "A semente ou cultivo é orgânica certificada?",
- "NEED_DOCUMENT_GENETICALLY_ENGINEERED": "Seu certificador pode solicitar documentação que comprove sua afirmação de que este cultivo não foi geneticamente modificada.",
- "NEED_DOCUMENT_PERFORM_SEARCH": "Seu certificador pode solicitar documentação de suporte à sua busca.",
- "NEED_DOCUMENT_TREATED": "Seu certificador pode solicitar documentação descrevendo quaisquer tratamentos.",
- "NUTRIENTS_IN_EDIBLE_PORTION": "Nutrientes da parte ingerida (por 100g)",
- "PERENNIAL": "Perene",
- "PERFORM_SEARCH": "Você fez uma busca de disponibilidade comercial?",
- "PHYSIOLOGY_AND_ANATOMY": "Fisiologia e Anatomia",
- "TREATED": "As sementes desta cultivo foram tratadas?",
- "ADD_COMPLIANCE_FILE": "Link para um arquivo de conformidade",
- "UPLOAD_LATER": "Você também pode fazer upload de arquivos posteriormente"
+ "DATE_RANGE": {
+ "HELP_BODY": "Selecione as datas para criar um relatório financeiro para sua fazenda para um determinado intervalo de tempo.",
+ "HELP_TITLE": "Ajuda",
+ "TITLE": "Filtrar relatório por data",
+ "INVALID_RANGE_MESSAGE": "A data de término deve ser posterior à data de início para retornar resultados"
},
"DATE_RANGE_PICKER": {
"FROM": "De",
"TO": "Até",
- "TO_MUST_BE_AFTER_FROM": "A data 'Até' deve ser depois da data 'De'"
- },
- "DATE_RANGE": {
- "HELP_BODY": "Selecione as datas para criar um relatório financeiro para sua fazenda para um determinado intervalo de tempo.",
- "HELP_TITLE": "Ajuda",
- "TITLE": "Filtrar relatório por data"
+ "TO_MUST_BE_AFTER_FROM": "A data 'Até' deve ser depois da data 'De'",
+ "REVENUE_HELP_TITLE": "Ajuda",
+ "REVENUE_HELP_BODY": "Somente os planos que possuem uma tarefa de colheita planejada ou concluída dentro do intervalo de datas indicado serão mostrados."
},
"DOCUMENTS": {
- "ADD_DOCUMENT": "Adicionar um novo documento",
"ADD": {
"ADD_MORE_PAGES": "Adicionar mais páginas",
"DOCUMENT_NAME": "Nome do documento",
@@ -346,6 +350,7 @@
"TYPE": "Tipo",
"VALID_UNTIL": "Válido até"
},
+ "ADD_DOCUMENT": "Adicionar um novo documento",
"ARCHIVE": "Arquivar",
"ARCHIVE_DOCUMENT": "Arquivar documento?",
"ARCHIVE_DOCUMENT_TEXT": "Arquivar este documento o moverá para a seção arquivada de seus documentos, mas não o excluirá. Os documentos arquivados não serão exportados para suas certificações. Você quer prosseguir?",
@@ -371,12 +376,18 @@
"CLEANING_PRODUCT": "Produto de limpeza",
"CROP_COMPLIANCE": "Conformidade de cultivo",
"FERTILIZING_PRODUCT": "Produto fertilizante",
+ "INVOICES": "Faturas",
"OTHER": "Outro",
"PEST_CONTROL_PRODUCT": "Produto de controle de pragas",
+ "RECEIPTS": "Recibos",
"SOIL_AMENDMENT": "Adubação e correção do solo",
"SOIL_SAMPLE_RESULTS": "Resultados da amostra de solo",
"WATER_SAMPLE_RESULTS": "Resultados da amostra de água"
},
+ "UNARCHIVE": "Desarquivar",
+ "UNARCHIVE_DOCUMENT": "Documento desarquivado?",
+ "UNARCHIVE_DOCUMENT_TEXT": "Desarquivar este documento irá devolvê-lo à sua lista de documentos atualmente válidos. Os documentos válidos serão exportados para suas certificações. Você quer prosseguir?",
+ "UNARCHIVED": "Desarquivado",
"VALID": "Válido"
},
"ENTER_PASSWORD": {
@@ -390,6 +401,7 @@
},
"EXPENSE": {
"ADD_EXPENSE": {
+ "ALL_FIELDS_REQUIRED": "Todos os campos são obrigatórios",
"MIN_ERROR": "Insira um valor maior que ",
"REQUIRED_ERROR": "Expense is required",
"TITLE_1": "Despesa Nova (1 de 2)",
@@ -416,6 +428,7 @@
"RESET_PASSWORD_LINK": "Enviar novo link de senha/password"
},
"FARM_MAP": {
+ "TUTORIALS": "Tutoriais de mapas",
"AREA_DETAILS": {
"NETWORK": "Problemas de conexão com a rede",
"PERIMETER": "Perímetro",
@@ -453,7 +466,8 @@
"DOWNLOAD": "Download",
"EMAIL_TO_ME": "Enviar email para mim",
"EMAILING": "Enviando...",
- "TITLE": "Exporte o mapa do seu sítio/fazenda"
+ "TITLE": "Exporte o mapa do seu sítio/fazenda",
+ "LOADING": "Carregando..."
},
"FARM_SITE_BOUNDARY": {
"EDIT_TITLE": "Editar limites do sítio/fazenda",
@@ -514,7 +528,7 @@
},
"LOCATION_CREATION_FLOW": "criação de localização",
"MAP_FILTER": {
- "ADD_TITLE": "Adicionar to your map",
+ "ADD_TITLE": "Adicionar ao seu mapa",
"AREAS": "Áreas",
"BARN": "Galpão",
"BZ": "Zona de amortecimento/proteção",
@@ -552,7 +566,7 @@
"SPOTLIGHT": {
"ADD": "Adicionar locais ao seu mapa",
"ADD_TITLE": "Adicionar ao seu mapa",
- "EXPORT": "Baixe ou compartilhe seu mapa",
+ "EXPORT": "Baixar ou compartilhar seu mapa",
"EXPORT_TITLE": "Exportar o seu mapa",
"FILTER": "Mudar quais locais você vê no seu mapa",
"FILTER_TITLE": "Filtrar o seu mapa",
@@ -566,7 +580,8 @@
},
"TAB": {
"CROPS": "Cultivo",
- "DETAILS": "Detalhes"
+ "DETAILS": "Detalhes",
+ "TASKS": "Tarefas"
},
"TITLE": "Mapa do sítio/fazenda",
"TUTORIAL": {
@@ -582,7 +597,7 @@
"STEP_ONE": "Clique em qualquer lugar para começar a desenhar",
"STEP_THREE": "Clique-e-arraste pontos para ajustar a área",
"STEP_TWO": "Clique no ponto inicial para fechar a área",
- "TITLE": "Desenha uma área"
+ "TITLE": "Desenhe uma área"
},
"LINE": {
"STEP_FOUR": "(Para alguns tipos de linha) adicione uma largura",
@@ -593,7 +608,7 @@
}
},
"UNABLE_TO_RETIRE": {
- "BODY": "Você só pode retirar locais que não tenham culturas, tarefas ativas ou planejadas.",
+ "BODY": "Você só pode retirar locais que não tenham cultivos, tarefas ativas ou planejadas.",
"TITLE": "Não é possível retirar"
},
"WATER_VALVE": {
@@ -637,7 +652,7 @@
"DATE": "Data",
"ESTIMATED_REVENUE": {
"ESTIMATED_ANNUAL_REVENUE": "Receita anual estimada",
- "ESTIMATED_ANNUAL_YIELD": "Rendimento anual estimado",
+ "ESTIMATED_ANNUAL_YIELD": "Colheita anual estimada",
"ESTIMATED_PRICE_PER_UNIT": "Preço por unidade estimado",
"TITLE": "Receita Estimada"
},
@@ -671,11 +686,25 @@
"AMPHIBIANS": "Anfíbios",
"BIRDS": "Aves",
"CROP_VARIETIES": "Variedades de cultivos",
+ "ERROR": {
+ "BODY": "A LiteFarm gera insights de biodiversidade com base em várias fontes e não conseguiu fazê-lo no momento. Tente novamente após {{minutos}} minutos, por favor.",
+ "PREVIEW": "Indisponível",
+ "TITLE": "Tinha um problema"
+ },
"HEADER": "Número de espécies",
"INFO": "A biodiversidade é ótima para as pessoas e para o planeta. Contabilizamos a riqueza de espécies a partir de todos os registros conhecidos sobre a biodiversidade ao redor de sua fazenda. Você pode aumentar a contagem de espécies em sua fazenda utilizando o https://www.inaturalist.org/app.",
"INSECTS": "Insetos",
+ "LOADING": {
+ "BODY": "Estamos gerando as informações mais recentes sobre biodiversidade para sua fazenda. Isso pode levar até 60 segundos.",
+ "PREVIEW": "Carregando...",
+ "TITLE": "Gerando os mais recentes insights sobre biodiversidade..."
+ },
+ "MAMMALS": "Mamíferos",
"PLANTS": "Plantas",
- "SPECIES_COUNT": "{{count}} espécies",
+ "SPECIES_COUNT": "{{count}} espécie",
+ "SPECIES_COUNT_one": "{{count}} espécie",
+ "SPECIES_COUNT_many": "{{count}} espécies",
+ "SPECIES_COUNT_other": "{{count}} espécies",
"SPECIES_COUNT_plural": "{{count}} espécies",
"TITLE": "Biodiversidade"
},
@@ -691,6 +720,9 @@
"CHOOSE_A_FREQUENCY": "Escolha uma frequência",
"CHOOSE_FREQUENCY": "Escolha uma frequência...",
"COUNT_MONTHS": "{{count}} mês",
+ "COUNT_MONTHS_one": "{{count}} mês",
+ "COUNT_MONTHS_many": "{{count}} meses",
+ "COUNT_MONTHS_other": "{{count}} meses",
"COUNT_MONTHS_plural": "{{count}} meses",
"CYCLE_INDICATOR": "Your Nitrogen Balance is on a {{frequency}} months cycle and data will show on: {{refreshDate}}",
"FIRST_TIME": "Parece que esta é sua primeira vez executando isso! Por favor, selecione uma frequência para calcular o seu balanço de nitrogênio.",
@@ -706,7 +738,10 @@
"FAT": "Gordura",
"HEADER": "Número de refeições",
"INFO": "Nós estimamos o número de refeições potencialmente fornecidas por sua fazenda com base nos dados de vendas e na composição nutricional dos cultivos. Assumimos que as necessidades nutricionais diárias são divididas igualmente em três refeições por dia",
- "MEAL_COUNT": "{{count}} refeições",
+ "MEAL_COUNT": "{{count}} refeição",
+ "MEAL_COUNT_one": "{{count}} refeição",
+ "MEAL_COUNT_many": "{{count}} refeições",
+ "MEAL_COUNT_other": "{{count}} refeições",
"MEAL_COUNT_plural": "{{count}} refeições",
"MEALS": "refeições",
"PROTEIN": "Proteínas",
@@ -716,10 +751,13 @@
},
"PRICES": {
"INFO": "Mostramos a trajetória comparativa entre seus preços de venda em relação aos preços de venda dos mesmos produtos encontrados a uma determinada distância de você, utilizando dados coletados na rede LiteFarm.",
- "NEARBY_FARMS": "Vindo de {{count}} fazenda para dados de vendas",
- "NEARBY_FARMS_plural": "Vindo de {{count}} fazendas para dados de vendas",
- "NETWORK_PRICE": "Preço de rede",
- "NO_ADDRESS": "You currently do not have an address in LiteFarm. Please update it in your Profile to get nearby prices information!",
+ "NEARBY_FARMS": "O preço de mercado é baseado em {{count}} fazendas na sua região",
+ "NEARBY_FARMS_one": "O preço de mercado é baseado em {{count}} fazenda na sua região",
+ "NEARBY_FARMS_many": "O preço de mercado é baseado em {{count}} fazendas na sua região",
+ "NEARBY_FARMS_other": "O preço de mercado é baseado em {{count}} fazendas na sua região",
+ "NEARBY_FARMS_plural": "O preço de mercado é baseado em {{count}} fazendas na sua região",
+ "NETWORK_PRICE": "Preço de mercado",
+ "NO_ADDRESS": "Atualmente você não tem um endereço na LiteFarm. Atualize-o em seu perfil para obter informações de preços nas proximidades!",
"OWN_PRICE": "Preço próprio",
"PERCENT_OF_MARKET": "{{percentage}}% do mercado",
"SALES_FROM_DISTANCE_AWAY": "Preço a partir de {{distance}} {{unit}} de distância",
@@ -738,7 +776,7 @@
"FIRST_TIME": "Parece que esta é sua primeira vez executando isso! Para obter mais informações sobre o balanço hídrico, clique no botão de informações",
"INFO_1": "O balanço hídrico informa se seus cultivos têm pouca ou muita água. Ele se baseia em dados meteorológicos e é atualizado pelos dados de irrigação e textura do solo de seus registros de análise de solo.",
"INFO_2": "Este recurso não foi amplamente testado em fazendas com baixa densidade de estação meteorológica ao redor, portanto, use com cuidado. Agradecemos os comentários sobre o desempenho dele em sua fazenda.",
- "NO_SCHEDULE_RUN": "Your scheduled water balance hasn't run yet, please check back in two days and ensure you have at least one soil analysis that records soil texture for a field to see water balance data for crops in that field. If the problem persists please contact LiteFarm.",
+ "NO_SCHEDULE_RUN": "Seu balanço hídrico programado ainda não foi executado. Verifique novamente em dois dias e certifique-se de ter pelo menos uma análise de solo que registre a textura do solo para um campo para ver os dados do balanço hídrico para os cultivos naquele campo. Se o problema persistir, entre em contato com a LiteFarm.",
"REGISTER_FARM": "Registre Fazenda",
"TITLE": "Balanço hídrico"
}
@@ -773,6 +811,8 @@
"BIRTH_YEAR_ERROR": "Ano de nascimento precisa ser entre 1900 e",
"BIRTH_YEAR_TOOLTIP": "As informações de idade são coletadas apenas para fins de pesquisa e só serão utilizadas com as informações de identificação pessoal removidas",
"CHOOSE_ROLE": "Escolha sua função",
+ "DEFAULT_LANGUAGE": "Português",
+ "DEFAULT_LANGUAGE_VALUE": "pt",
"EMAIL": "Email",
"EMAIL_INFO": "Usuário sem um email não conseguirão entrar no aplicativo",
"FULL_NAME": "Nome completo",
@@ -780,6 +820,7 @@
"GENDER_TOOLTIP": "As informações de gênero são coletadas apenas para fins de pesquisa e só serão utilizadas com as informações de identificação pessoal removidas",
"INVALID_EMAIL_ERROR": "Por favor insira um email válido",
"INVITE": "Convidar",
+ "LANGUAGE_OF_INVITE": "Idioma do convite",
"PHONE": "Número de telefone",
"PHONE_ERROR": "Por favor entre um número de telefone válido",
"ROLE": "Função",
@@ -838,15 +879,15 @@
"DISEASE": "Doença",
"HARVEST": "Colheita",
"HARVEST_ALLOCATION_SUBTITLE": "Quanto da colheita será destinado para cada propósito?",
+ "HARVEST_ALLOCATION_SUBTITLE_TWO": "Quantidade para alocar",
+ "HARVEST_QUANTITY": "Quantidade de Colheita",
+ "HARVEST_USE": "Uso da colheita",
"HARVEST_USE_TYPE_SUBTITLE": "Como a colheita sera utilizada/destinada?",
"OTHER": "Outro",
"PEST": "Praga",
"QUANTITY_ERROR": "Quantity must be up to 2 decimal places",
"TITLE": "Registro de Colheita (passo 1 de 3)",
- "WEED": "Vegetação rasteira",
- "HARVEST_QUANTITY": "Quantidade de Colheita",
- "HARVEST_USE": "Uso da colheita",
- "HARVEST_ALLOCATION_SUBTITLE_TWO": "Quantidade para alocar"
+ "WEED": "Vegetação rasteira"
},
"LOG_IRRIGATION": {
"DRIP": "Gotejo",
@@ -855,27 +896,30 @@
"SUBSURFACE": "Subsuperfície"
},
"MANAGEMENT_DETAIL": {
- "ABANDON_PLAN": "Abandonar este plano de manejo",
+ "ABANDON_PLAN": "Abandonar este plano de cultivo",
"ADD_A_TASK": "Adicione uma tarefa",
"DETAILS": "Detalhes",
- "FAILED_CROP": "Colheita falhou?",
+ "FAILED_CROP": "O cultivo falhou?",
"TASKS": "Tarefas"
},
"MANAGEMENT_PLAN": {
- "ABANDON_MANAGEMENT_PLAN_CONTENT": "Abandonar este plano de manejo ira abandonar todas as tarefas incompletas associadas a ele e removê-lo do mapa de sua propriedade",
- "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandonar plano de manejo?",
- "ADD_MANAGEMENT_PLAN": "Adicionar um plano de manejo",
+ "ABANDON_MANAGEMENT_PLAN_CONTENT": "Abandonar este plano de cultivo ira abandonar todas as tarefas incompletas associadas a ele e removê-lo do mapa de sua propriedade",
+ "ABANDON_MANAGEMENT_PLAN_TITLE": "Abandonar plano de cultivo?",
+ "ADD_MANAGEMENT_PLAN": "Adicionar um plano de cultivo",
"AGE": "Época",
"AS_COVER_CROP": "Como cultivo de cobertura",
"BEDS": "Canteiros",
"BROADCAST": "Semeadura a lanço ou com máquina semeadora",
"COMPLETE_PLAN": {
+ "ABANDON_DATE": "Data de abandono",
+ "ABANDON_NOTES": "Notas de abandono",
"ABANDON_PLAN": "Abandonar plano",
"ABANDON_REASON": "Razão do abandono",
+ "COMPLETE_DATE": "Fecha completada",
"COMPLETE_PLAN": "Plano completo",
- "DATE_OF_CHANGE": "Data de mudança do status",
+ "DATE_OF_CHANGE": "Data de alteração da situação",
"NOTES_CHAR_LIMIT": "As observações não podem exceder 10.000 caractéres",
- "RATING": "Avaliar este plano de manejo",
+ "RATING": "Avaliar este plano de cultivo",
"REASON": {
"CROP_FAILURE": "Quebra de safra",
"LABOUR_ISSUE": "Problema de trabalho",
@@ -887,10 +931,11 @@
},
"WHAT_HAPPENED": "O que aconteceu?"
},
+ "COMPLETION_NOTES": "Notas de conclusão",
"CONTAINER": "Recipiente",
"CONTAINER_OR_IN_GROUND": "Você está plantando em um recipiente ou no solo?",
"CONTAINER_TYPE": "Tipo de recipiente",
- "COVER_INFO": "A seleção da cultura de cobertura criará uma tarefa de trabalho de campo para terminar o cultivo de cobertura no final da temporada. Selecionar para colheita criará uma tarefa de colheita em vez disso.",
+ "COVER_INFO": "A seleção da cultivo de cobertura criará uma tarefa de trabalho de campo para terminar o cultivo de cobertura no final da temporada. Selecionar para colheita criará uma tarefa de colheita em vez disso.",
"COVER_OR_HARVEST": "Isso está sendo cultivado como um cultivo de cobertura ou para a colheita?",
"DAYS_FROM_PLANTING": "Dias desde o plantio até:",
"DAYS_FROM_SEEDING": "Dias desde a semente até:",
@@ -902,12 +947,12 @@
"DROP_PIN": "Alfinetar",
"DURATION_TOOLTIP": "Esses são valores sugeridos. Ajuste de acordo com as condições locais.",
"EDITING_PLAN_WILL_NOT_MODIFY": "Editar este plano não irá modificar as tarefas atribuídas a ele.",
- "ESTIMATED_SEED": "Semente estimada necessária",
- "ESTIMATED_YIELD": "Rendimento estimado",
+ "ESTIMATED_SEED": "Estimativa de sementes necessárias",
+ "ESTIMATED_YIELD": "Colheita anual estimada",
"FIRST_MP_SPOTLIGHT": {
"BODY_PART1": "LiteFarm gerou algumas tarefas com base em seu plano. Você pode adicionar mais tarefas ou atribuí-las nesta tela.",
"BODY_PART2": "Seu plano será ativado assim que você concluir uma tarefa.",
- "TITLE": "Parabéns! Você realizou o seu primeiro plano de manejo!"
+ "TITLE": "Parabéns! Você realizou o seu primeiro plano de cultivo!"
},
"FOR_HARVEST": "Para a colheita",
"GERMINATION": "Germinação",
@@ -915,15 +960,15 @@
"HARVEST_DATE": "Quando será a próxima colheita?",
"HISTORICAL_CONTAINER_OR_IN_GROUND": "Foi plantado em um recipiente ou no solo?",
"IN_GROUND": "No solo",
- "INCOMPLETE_TASK_CONTENT": "Este plano têm tarefas que ainda não foram completadas. Você precisará marcar as tarefas como concluídas, a fim de concluir este plano de manejo da cultura. ",
+ "INCOMPLETE_TASK_CONTENT": "Este plano têm tarefas que ainda não foram completadas. Você precisará marcar as tarefas como concluídas, a fim de concluir este plano de cultivo. ",
"INCOMPLETE_TASK_TITLE": "Você tem tarefas incompletas",
"INDIVIDUAL_CONTAINER": "Individual ou recipiente",
"IS_TRANSPLANT": "Este cultivo será transplantado?",
"KNOW_HOW_IS_CROP_PLANTED": "Você sabe como o cultivo foi plantado?",
"LOCATION_SUBTEXT": "Apenas os locais que podem cultivar são mostrados.",
- "MANAGEMENT_PLAN_FLOW": "criação do plano de manejo",
- "MANAGEMENT_SPOTLIGHT_1": "Criar novos planos para esta cultura",
- "MANAGEMENT_SPOTLIGHT_2": "Visualizar e modifique os planos para este cultivo",
+ "MANAGEMENT_PLAN_FLOW": "criação do plano de cultivo",
+ "MANAGEMENT_SPOTLIGHT_1": "Criar novos planos para este cultivo",
+ "MANAGEMENT_SPOTLIGHT_2": "Visualizar e modificar os planos para este cultivo",
"MANAGEMENT_SPOTLIGHT_3": "Criar e atribuir tarefas",
"MANAGEMENT_SPOTLIGHT_TITLE": "Manejo",
"NEXT_HARVEST": "Quando será a próxima colheita?",
@@ -931,7 +976,8 @@
"NUMBER_OF_CONTAINER": "Nº dos recipientes",
"PENDING_TASK": "Tarefas pendentes",
"PLAN_AND_ID": "Plan {{id}}",
- "PLAN_NAME": "Nome do plano de manejo",
+ "PLAN_AND_ID_plural": "",
+ "PLAN_NAME": "Nome do plano de cultivo",
"PLAN_NOTES": "Notas do plano",
"PLANT_SPACING": "Espaçamento de plantas",
"PLANTED_ALREADY": "Você vai plantar este cultivo ou ele já está plantado?",
@@ -945,6 +991,7 @@
"PLANTING_NOTE": "Notas de plantio",
"PLANTING_SOIL": "Solo de plantio a ser usado",
"PLANTS_PER_CONTAINER": "Nº de plantas /recipiente",
+ "RATE_THIS_MANAGEMENT_PLAN": "Avalie este plano de cultivo",
"REMOVE_PIN": "Remover alfinete",
"ROW_METHOD": {
"HISTORICAL_SAME_LENGTH": "As linhas eram todas do mesmo comprimento?",
@@ -966,12 +1013,19 @@
"SELECTED_STARTING_LOCATION": "Sempre selecione este como o local de início para os cultivos que serão transplantados ",
"SPOTLIGHT_HERE_YOU_CAN": "Aqui você pode:",
"STARTED": "Vamos começar",
+ "STATUS": {
+ "ABANDONED": "Abandonado",
+ "ACTIVE": "Ativo",
+ "COMPLETED": "Completo",
+ "PLANNED": "Planejado"
+ },
"SUPPLIER": "Fornecedor",
"TERMINATION": "Terminação",
"TERMINATION_DATE": "Quando você encerrará esta colheita?",
"TOTAL_PLANTS": "Nº de plantas",
"TRANSPLANT": "Transplantar",
"TRANSPLANT_DATE": "Qual é a sua data de transplante?",
+ "TRANSPLANT_LOCATION": "Para onde você fará o transplante?",
"TRANSPLANT_SPOTLIGHT": {
"BODY": {
"PLANTED": "Plantado",
@@ -987,18 +1041,10 @@
"VARIETY": "Variedade",
"WHAT_IS_AGE": "Qual é a idade aproximada do cultivo?",
"WHAT_WAS_PLANTING_METHOD": "Qual foi o método de plantio?",
+ "WHAT_WAS_PLANTING_METHOD_INFO": "Selecionando corretamente o método de plantio vai ajudar o LiteFarm a estimar com mais precisão a quantidade de sementes necessárias, a produção e outros conhecimentos úteis.",
"WHERE_START_LOCATION": "Onde é o seu local de partida?",
"WHERE_TRANSPLANT_LOCATION": "Onde você fará o transplante?",
- "WILD_CROP": "Você está colhendo uma planta silvestre?",
- "STATUS": {
- "ABANDONED": "Abandonado",
- "ACTIVE": "Ativo",
- "COMPLETED": "Completo",
- "PLANNED": "Planejado"
- },
- "WHAT_WAS_PLANTING_METHOD_INFO": "Selecionando corretamente o método de plantio vai ajudar o LiteFarm a estimar com mais precisão a quantidade de sementes necessárias, a produção e outros conhecimentos úteis.",
- "TRANSPLANT_LOCATION": "Para onde você fará o transplante?",
- "PLAN_AND_ID_plural": ""
+ "WILD_CROP": "Você está colhendo uma planta silvestre?"
},
"MY_FARM": {
"CERTIFICATIONS": "Certificações",
@@ -1008,35 +1054,77 @@
},
"NAVIGATION": {
"SPOTLIGHT": {
+ "COORDINATE_ACTIVITIES": "Coordenar as atividades da fazenda",
+ "EDIT_FARM_SETTING": "Editar as configurações da sua fazenda",
"FARM": "Aqui você pode :, • Editar as configurações da sua fazenda, • Mapear sua fazenda, • Orientar seus funcionários",
"FARM_TITLE": "O perfil de fazenda",
+ "INFO": "Suas informações",
+ "LOG_OUT": "O botão de logout",
+ "MANAGE_EMPLOYEE": "Orientar seus funcionários",
+ "MANAGE_TASK": "Administrar suas tarefas",
+ "MAP_FARM": "Mapear sua fazenda",
+ "SEE_UPDATES": "Veja atualizações importantes",
"NOTIFICATION": "Aqui você pode:, • Administrar suas tarefas, • Ver o que mais está acontecendo, • Coordenar as atividades da fazenda",
- "NOTIFICATION_TITLE": "Essas são as tarefas da sua propriedade",
+ "NOTIFICATION_TITLE": "Este é o seu centro de notificações",
"PROFILE": "Aqui você encontrará :, • Suas informações, • Dicas úteis, • O botão de logout",
- "PROFILE_TITLE": "Seu Perfil"
+ "PROFILE_TITLE": "Seu Perfil",
+ "SEE_TASK": "Ver o que mais está acontecendo",
+ "TASK_TITLE": "Essas são as tarefas da sua propriedade",
+ "TIPS": "Dicas úteis",
+ "YOU_CAN": "Aqui você pode:",
+ "YOU_WILL_FIND": "Aqui você encontrará:"
}
},
"NOTIFICATION": {
- "NOTIFICATION_TEASER": "Em breve!"
+ "DAILY_TASKS_DUE_TODAY": {
+ "BODY": "Você tem tarefas para vencer hoje.",
+ "TITLE": "Tarefas para hoje"
+ },
+ "NONE_TO_DISPLAY": "Não há notificações para exibir.",
+ "NOTIFICATION_TEASER": "Em breve!",
+ "PAGE_TITLE": "Notificações",
+ "TAKE_ME_THERE": "Me leve lá",
+ "TASK_ABANDONED": {
+ "BODY": "Uma tarefa {{taskType}} atribuída a você foi abandonada por {{abandoner}}.",
+ "TITLE": "Tarefa abandonada"
+ },
+ "TASK_ASSIGNED": {
+ "BODY": "A tarefa {{taskType}} foi atribuída a {{assignee}}. ",
+ "TITLE": "Tarefa atribuída"
+ },
+ "TASK_COMPLETED_BY_OTHER_USER": {
+ "BODY": "Uma tarefa {{taskType}} atribuída a você foi marcada como concluída por {{assigner}}.",
+ "TITLE": "Tarefa completa"
+ },
+ "TASK_REASSIGNED": {
+ "BODY": "Uma tarefa {{taskType}} atribuída anteriormente a você foi atribuída a outra pessoa por {{assigner}}.",
+ "TITLE": "Tarefa reatribuída"
+ },
+ "WEEKLY_UNASSIGNED_TASKS": {
+ "BODY": "Você tem tarefas não atribuídas para esta semana.",
+ "TITLE": "Tarefas não atribuídas"
+ }
},
"OUTRO": {
"ALL_DONE": "Excelente. Pronto para sujar as mãos?",
"IMPORTANT_THINGS": "E, por fim, vamos mostrar algumas coisas importantes!"
},
- "PASSWORD_RESET_SUCCESS_MODAL": {
- "BUTTON": "Ótimo!",
- "DESCRIPTION": "Sua senha foi atualizada. Redirecionando você para suas fazendas em 10 segundos ...",
- "TITLE": "Sucesso!"
- },
"PASSWORD_RESET": {
"BUTTON": "Reenviar link",
"BUTTON_SENDING": "Enviando...",
"DESCRIPTION_BOTTOM": "Por favor verifique seu e-mail.",
"DESCRIPTION_TOP": "Um link foi enviado.",
+ "LABEL_EMAIL": "Email",
+ "LABEL_NEW_PASSWORD": "Nova Senha",
"NEW_ACCOUNT_BUTTON": "Atualizar",
"NEW_ACCOUNT_TITLE": "Defina sua nova senha",
"TITLE": "Link enviado"
},
+ "PASSWORD_RESET_SUCCESS_MODAL": {
+ "BUTTON": "Ótimo!",
+ "DESCRIPTION": "Sua senha foi atualizada. Redirecionando você para suas fazendas em 10 segundos ...",
+ "TITLE": "Sucesso!"
+ },
"PLAN_GUIDANCE": {
"ADDITIONAL_GUIDANCE": "Há alguma orientação adicional que você deseja fornecer para a tarefa de semeadura?",
"BED": "Canteiro",
@@ -1048,23 +1136,15 @@
"SPACE_BETWEEN": "Espaço entre {{types}}",
"SPECIFY": "Especificar {{types}}",
"SPECIFY_PLACEHOLDER": "Ex. {{types}} 1 - 4",
- "TOOLTIP": "Os 40 primeiros caracteres deste campo serão exibidos em qualquer lugar em que seu plano de manejo esteja visível. ",
- "WIDTH": "{{types}} Largura",
+ "TOOLTIP": "Os 40 primeiros caracteres deste campo serão exibidos em qualquer lugar em que seu plano de cultivo esteja visível. ",
+ "WIDTH": "Largura de {{type}}",
"WORD_LIMIT": "Somente {{limit}} caracteres podem ser exibidos"
},
"PREPARING_EXPORT": {
"MESSAGE": "O LiteFarm está reunindo seus documentos da certificação e você receberá um e-mail quando terminarmos - pode levar alguns minutinhos... Você pode clicar fora desta caixa para continuar usando o LiteFarm sem interromper o processo.",
"TITLE": "Sua exportação está sendo preparada"
},
- "PROFILE_FLOATER": {
- "HELP": "Ajuda",
- "INFO": "Minha informação",
- "LOG_OUT": "Sair",
- "SWITCH": "Mudar de fazenda",
- "TUTORIALS": "Tutoriais"
- },
"PROFILE": {
- "ACCOUNT_TAB": "Conta",
"ACCOUNT": {
"CONVERT_TO_HAVE_ACCOUNT": "Converter este trabalhador para usuário com conta",
"EDIT_USER": "Editar usuário",
@@ -1080,7 +1160,7 @@
"SPANISH": "Espanhol",
"USER_ADDRESS": "Endereço do usuário"
},
- "FARM_TAB": "Sítio/Fazenda",
+ "ACCOUNT_TAB": "Conta",
"FARM": {
"ADDRESS": "Endereço",
"CURRENCY": "Moeda",
@@ -1090,7 +1170,7 @@
"PHONE_NUMBER": "Número de telefone",
"UNITS": "Unidades"
},
- "PEOPLE_TAB": "Pessoas",
+ "FARM_TAB": "Sítio/Fazenda",
"PEOPLE": {
"DO_YOU_WANT_TO_REMOVE": "Você quer remover este usuário de sua propriedade?",
"EO": "Agente de Extensão",
@@ -1108,13 +1188,21 @@
"THIS_WILL_REMOVE": "Esta ação removerá o usuário de sua propriedade.",
"USERS_FOUND": "Usuários encontrados"
},
+ "PEOPLE_TAB": "Pessoas",
"TABLE": {
- "HEADER_EMAIL": "Emai",
+ "HEADER_EMAIL": "E-mail",
"HEADER_NAME": "Nome",
- "HEADER_ROLE": "Função no estabelecimento",
- "HEADER_STATUS": "Status"
+ "HEADER_ROLE": "Função",
+ "HEADER_STATUS": "Situação"
}
},
+ "PROFILE_FLOATER": {
+ "HELP": "Ajuda",
+ "INFO": "Minha informação",
+ "LOG_OUT": "Sair",
+ "SWITCH": "Mudar de fazenda",
+ "TUTORIALS": "Tutoriais"
+ },
"REACT_SELECT": {
"CLEAR": "Limpar",
"CLEAR_ALL": "Limpar tudo"
@@ -1133,8 +1221,8 @@
},
"SALE": {
"ADD_SALE": {
- "CROP_PLACEHOLDER": "Selecione cultivo",
- "CROP_REQUIRED": "Cultivo é necessário",
+ "CROP_PLACEHOLDER": "Selecione o cultivo",
+ "CROP_REQUIRED": "O cultivo é necessário",
"CROP_VARIETY": "Variedade de cultivo",
"CUSTOMER_NAME": "Nome do Cliente",
"CUSTOMER_NAME_REQUIRED": "Nome do Cliente é necessário",
@@ -1237,7 +1325,7 @@
"CROPS_LABEL": "Cultivos",
"DID_NOT_PROVIDE_ANSWER": "Não forneceu resposta",
"HAPPY": "Contente",
- "INDIVIDUAL_CROPS": "Cultivos individuos",
+ "INDIVIDUAL_CROPS": "Cultivos individuais",
"LOCATIONS": "Locais",
"LOCATIONS_LABEL": "Locais",
"MOOD": "Como você se sentiu durante este turno?",
@@ -1257,7 +1345,7 @@
"MY_SHIFT": {
"DELETE_CONFIRMATION": "Tem certeza que deseja deletar este turno?",
"DURATION": "Duração",
- "LOCATION_CROPS": "Locations/Crops",
+ "LOCATION_CROPS": "Localizações/Cultivos",
"SUBMITTED_FOR": "Insira para",
"TASK": "Tarefa",
"TITLE": "Detalhes do turno"
@@ -1278,12 +1366,14 @@
"EMAIL_INVALID": "Email é inválido",
"ENTER_EMAIL": "Digite seu endereço de email",
"EXPIRED_ERROR": "NÃO EXISTE",
+ "EXPIRED_INVITATION_LINK_ERROR": "Convite expirado ou inválido",
"GOOGLE_BUTTON": "CONTINUE COM O GOOGLE",
"INVITED_ERROR": "NÃO EXISTE",
"LITEFARM_UPDATED": "Nós atualizamos o LiteFarm!",
"PASSWORD_ERROR": "Senha incorreta",
"SIGN_IN": "Conecte-se",
"SSO_ERROR": "Faça login clicando no botão do Google acima",
+ "USED_INVITATION_LINK_ERROR": "Este convite já foi utilizado, por favor, faça o login para acessar essa fazenda",
"WELCOME_BACK": "Bem-vindo de volta",
"WRONG_BROWSER": "LiteFarm não é otimizado para este navegador.",
"WRONG_BROWSER_BOTTOM": "Faça login usando o Chrome."
@@ -1322,14 +1412,12 @@
"ROWS_TEXT": "linhas"
},
"TASK": {
- "ABANDON_TASK": "Abandonar esta tarefa",
- "ABANDON_TASK_DURATION": "Algum trabalho foi concluído para esta tarefa?",
"ABANDON": {
"ABANDON": "Abandonar",
+ "DATE": "Data do abandono",
"INFO": "Abandonar esta tarefa mudará seu estado para abandonado e a removerá das listas de 'Tarefas' e 'Não atribuídas' de todos os usuários.",
"NOTES": "Observações de abandono de tarefa",
"NOTES_CHAR_LIMIT": "Observações não devem exceder 10.000 caractéres",
- "REASON_FOR_ABANDONMENT": "Razão de abandono",
"REASON": {
"CROP_FAILURE": "Quebra de safra",
"LABOUR_ISSUE": "Questão trabalhista",
@@ -1339,9 +1427,13 @@
"SCHEDULING_ISSUE": "Problema de planejamento",
"WEATHER": "Clima"
},
+ "REASON_FOR_ABANDONMENT": "Razão de abandono",
"TITLE": "Abandonar tarefa",
- "WHAT_HAPPENED": "O que aconteceu?"
+ "WHAT_HAPPENED": "O que aconteceu?",
+ "WHEN": "Quando a tarefa foi abandonada?"
},
+ "ABANDON_TASK": "Abandonar esta tarefa",
+ "ABANDON_TASK_DURATION": "Algum trabalho foi concluído para esta tarefa?",
"ABANDONMENT_DETAILS": "Detalhes do abandono da tarefa",
"ADD_CUSTOM_HARVEST_USE": "Crie um uso de colheita personalizado",
"ADD_HARVEST_USE": "Adicionar outro uso para a colheita",
@@ -1353,6 +1445,10 @@
"MULTIPLE_CROPS": "Múltiplos cultivos",
"MULTIPLE_LOCATIONS": "Múltiplos locais"
},
+ "COMPLETE": {
+ "DATE": "Data de conclusão",
+ "WHEN": "Quando a tarefa foi concluída?"
+ },
"COMPLETE_HARVEST_QUANTITY": "Quanto foi colhido?",
"COMPLETE_TASK": "Completar tarefa",
"COMPLETE_TASK_CHANGES": "Você teve que fazer alguma alteração nesta tarefa?",
@@ -1368,6 +1464,23 @@
"DID_YOU_ENJOY": "Você gostou dessa tarefa?",
"DUE_DATE": "Data de finalização",
"DURATION": "Duração",
+ "FILTER": {
+ "ASCENDING": "mais antigo primeiro",
+ "ASSIGNEE": "Responsável",
+ "CROP": "Cultivo",
+ "DATE_RANGE": "Filtrar por intervalo de datas",
+ "DESCENDING": "mais recente primeito",
+ "FROM": "De",
+ "LOCATION": "Localização",
+ "MY_TASK": "Minhas tarefas",
+ "SORT_BY": "Ordenar por",
+ "STATUS": "Situação",
+ "TITLE": "Filtro das Tarefas",
+ "TO": "Até",
+ "TYPE": "Tipo",
+ "UNASSIGNED": "Não atribuída",
+ "VIEW": "Visualizar"
+ },
"HARVEST_USE": "Uso da colheita",
"HARVEST_USE_ALREADY_EXISTS": "Uso de colheita já existe",
"HOW_WILL_HARVEST_BE_USED": "Como a colheita vai ser utilizada?",
@@ -1383,20 +1496,23 @@
"SELECT_DATE": "Selecionar a data da tarefa",
"SELECT_TASK_LOCATIONS": "Selecionar o(s) local(is) da tarefa",
"SELECT_WILD_CROP": "Esta tarefa é para um cultivo silvestre",
- "TASK": "tarefa",
- "TASKS_COUNT": "{{count}} tarefa",
- "TASKS_COUNT_plural": "{{count}} tarefas",
- "TODO": "A fazer",
- "TRANSPLANT": "Transplantar",
- "TRANSPLANT_LOCATIONS": "Selecione um local de transplante",
- "UNASSIGNED": "Não atribuída",
"STATUS": {
"ABANDONED": "Abandonada",
"COMPLETED": "Completa",
"FOR_REVIEW": "Em revisão",
"LATE": "Atrasada",
"PLANNED": "Planejada"
- }
+ },
+ "TASK": "tarefa",
+ "TASKS_COUNT": "{{count}} tarefa",
+ "TASKS_COUNT_one": "{{count}} tarefa",
+ "TASKS_COUNT_many": "{{count}} tarefas",
+ "TASKS_COUNT_other": "{{count}} tarefas",
+ "TASKS_COUNT_plural": "{{count}} tarefas",
+ "TODO": "A fazer",
+ "TRANSPLANT": "Transplantar",
+ "TRANSPLANT_LOCATIONS": "Selecione um local de transplante",
+ "UNASSIGNED": "Não atribuída"
},
"UNIT": {
"TIME": {
diff --git a/packages/webapp/src/App.js b/packages/webapp/src/App.js
deleted file mode 100644
index 3ab5f18aad..0000000000
--- a/packages/webapp/src/App.js
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (App.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React from 'react';
-import NavBar from './containers/Navigation';
-import history from './history';
-import Routes from './Routes.js';
-import './locales/i18n';
-import { makeStyles } from '@material-ui/core/styles';
-import clsx from 'clsx';
-import { SnackbarProvider } from 'notistack';
-import { NotistackSnackbar } from './containers/Snackbar/NotistackSnackbar';
-
-const useStyles = makeStyles((theme) => ({
- container: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- width: '100vw',
- flexGrow: 1,
- },
- defaultHeight: {
- minHeight: '100vh',
- },
- webkitHeight: {
- minHeight: '-webkit-fill-available',
- },
- root: {
- width: 'calc(100vw - 48px)',
- maxWidth: '976px',
- },
-}));
-
-function App() {
- const classes = useStyles();
- return (
- <>
-
- >
- );
-}
-
-export default App;
diff --git a/packages/webapp/src/App.jsx b/packages/webapp/src/App.jsx
new file mode 100644
index 0000000000..c64d16976e
--- /dev/null
+++ b/packages/webapp/src/App.jsx
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (App.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React from 'react';
+import NavBar from './containers/Navigation';
+import history from './history';
+import Routes from './Routes.jsx';
+import { makeStyles } from '@material-ui/core/styles';
+import clsx from 'clsx';
+import { SnackbarProvider } from 'notistack';
+import { NotistackSnackbar } from './containers/Snackbar/NotistackSnackbar';
+
+const useStyles = makeStyles((theme) => ({
+ container: {
+ display: 'flex',
+ flexDirection: 'column',
+ alignItems: 'center',
+ width: '100vw',
+ flexGrow: 1,
+ },
+ defaultHeight: {
+ minHeight: '100vh',
+ },
+ webkitHeight: {
+ minHeight: '-webkit-fill-available',
+ },
+ root: {
+ width: 'calc(100vw - 48px)',
+ maxWidth: '976px',
+ },
+}));
+
+function App() {
+ const classes = useStyles();
+ return (
+ <>
+
+ >
+ );
+}
+
+export default App;
diff --git a/packages/webapp/src/App.test.js b/packages/webapp/src/App.test.js
deleted file mode 100644
index 4e1330c50b..0000000000
--- a/packages/webapp/src/App.test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (App.test.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import baseReducer from './containers/reducer';
-
-describe('test intitial state of baseReducer', () => {
- it('should be initialized', () => {
- expect(baseReducer(undefined, {})).toEqual({
- users: null,
- farm: null,
- fields: null,
- managementPlans: null,
- });
- });
-});
diff --git a/packages/webapp/src/Routes.js b/packages/webapp/src/Routes.js
deleted file mode 100644
index 9cb8bd463a..0000000000
--- a/packages/webapp/src/Routes.js
+++ /dev/null
@@ -1,1034 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (Routes.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Suspense } from 'react';
-import { Redirect, Route, Switch } from 'react-router-dom';
-import Spinner from './components/Spinner';
-
-// Components that have already been set up with code splitting
-import OnboardingFlow from './routes/Onboarding';
-import CustomSignUp from './containers/CustomSignUp';
-import { useSelector } from 'react-redux';
-import { isAuthenticated } from './util/jwt';
-
-// action
-import { userFarmSelector } from './containers/userFarmSlice';
-import { chooseFarmFlowSelector } from './containers/ChooseFarm/chooseFarmFlowSlice';
-import useScrollToTop from './containers/hooks/useScrollToTop';
-import { useReduxSnackbar } from './containers/Snackbar/useReduxSnackbar';
-
-//dynamic imports
-const Home = React.lazy(() => import('./containers/Home'));
-const HelpRequest = React.lazy(() => import('./containers/Help'));
-const Profile = React.lazy(() => import('./containers/Profile'));
-const ConsentForm = React.lazy(() => import('./containers/Consent'));
-const Finances = React.lazy(() => import('./containers/Finances'));
-const ChooseFarm = React.lazy(() => import('./containers/ChooseFarm'));
-const PasswordResetAccount = React.lazy(() => import('./containers/PasswordResetAccount'));
-const InviteSignUp = React.lazy(() => import('./containers/InviteSignUp'));
-const InvitedUserCreateAccount = React.lazy(() => import('./containers/InvitedUserCreateAccount'));
-const Callback = React.lazy(() => import('./containers/Callback'));
-const JoinFarmSuccessScreen = React.lazy(() => import('./containers/JoinFarmSuccessScreen'));
-const InviteUser = React.lazy(() => import('./containers/InviteUser'));
-// Insights imports
-const Insights = React.lazy(() => import('./containers/Insights'));
-const PeopleFed = React.lazy(() => import('./containers/Insights/PeopleFed'));
-const SoilOM = React.lazy(() => import('./containers/Insights/SoilOM'));
-const LabourHappiness = React.lazy(() => import('./containers/Insights/LabourHappiness'));
-const Biodiversity = React.lazy(() => import('./containers/Insights/Biodiversity'));
-const Prices = React.lazy(() => import('./containers/Insights/Prices'));
-const WaterBalance = React.lazy(() => import('./containers/Insights/WaterBalance'));
-const Erosion = React.lazy(() => import('./containers/Insights/Erosion'));
-const NitrogenBalance = React.lazy(() => import('./containers/Insights/NitrogenBalance'));
-const SalesSummary = React.lazy(() => import('./containers/Finances/SalesSummary'));
-const AddSale = React.lazy(() => import('./containers/Finances/AddSale'));
-const EditSale = React.lazy(() => import('./containers/Finances/EditSale'));
-const LegacyEstimatedRevenue = React.lazy(() =>
- import('./containers/Finances/LegacyEstimatedRevenue'),
-);
-const EstimatedRevenue = React.lazy(() => import('./containers/Finances/EstimatedRevenue'));
-const Labour = React.lazy(() => import('./containers/Finances/Labour'));
-const OtherExpense = React.lazy(() => import('./containers/Finances/OtherExpense'));
-const ExpenseDetail = React.lazy(() => import('./containers/Finances/ExpenseDetail'));
-const ExpenseCategories = React.lazy(() =>
- import('./containers/Finances/NewExpense/ExpenseCategories'),
-);
-const AddExpense = React.lazy(() => import('./containers/Finances/NewExpense/AddExpense'));
-const TempEditExpense = React.lazy(() =>
- import('./containers/Finances/EditExpense/TempEditExpense'),
-);
-const SaleDetail = React.lazy(() => import('./containers/Finances/SaleDetail'));
-const ExpiredTokenScreen = React.lazy(() => import('./containers/ExpiredTokenScreen'));
-const Map = React.lazy(() => import('./containers/Map'));
-const MapVideo = React.lazy(() => import('./components/Map/Videos'));
-const PostFarmSiteBoundaryForm = React.lazy(() =>
- import(
- './containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary'
- ),
-);
-const FarmSiteBoundaryDetails = React.lazy(() => import('./routes/FarmSiteBoundaryDetailsRoutes'));
-
-const PostFieldForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/FieldDetailForm/PostField'),
-);
-const FieldDetails = React.lazy(() => import('./routes/FieldDetailsRoutes'));
-
-const PostGardenForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden'),
-);
-const GardenDetails = React.lazy(() => import('./routes/GardenDetailsRoutes'));
-
-const PostGateForm = React.lazy(() =>
- import('./containers/LocationDetails/PointDetails/GateDetailForm/PostGate'),
-);
-const GateDetails = React.lazy(() => import('./routes/GateDetailsRoutes'));
-
-const PostWaterValveForm = React.lazy(() =>
- import('./containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve'),
-);
-const WaterValveDetails = React.lazy(() => import('./routes/WaterValveDetailsRoutes'));
-
-const PostBarnForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn'),
-);
-const BarnDetails = React.lazy(() => import('./routes/BarnDetailsRoutes'));
-
-const PostNaturalAreaForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea'),
-);
-const NaturalAreaDetails = React.lazy(() => import('./routes/NaturalAreaDetailsRoutes'));
-
-const PostSurfaceWaterForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater'),
-);
-const SurfaceWaterDetails = React.lazy(() => import('./routes/SurfaceWaterDetailsRoutes'));
-
-const PostResidenceForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence'),
-);
-const ResidenceDetails = React.lazy(() => import('./routes/ResidenceDetailsRoutes'));
-
-const PostCeremonialForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea'),
-);
-const CeremonialAreaDetails = React.lazy(() => import('./routes/CeremonialAreaDetailsRoutes'));
-
-const PostGreenhouseForm = React.lazy(() =>
- import('./containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse'),
-);
-const GreenhouseDetails = React.lazy(() => import('./routes/GreenhouseDetailsRoutes'));
-
-const CropManagement = React.lazy(() => import('./containers/Crop/CropManagement'));
-const CropDetail = React.lazy(() => import('./containers/Crop/CropDetail/index'));
-
-const PostFenceForm = React.lazy(() =>
- import('./containers/LocationDetails/LineDetails/FenceDetailForm/PostFence'),
-);
-const FenceDetails = React.lazy(() => import('./routes/FenceDetailsRoutes'));
-
-const PostBufferZoneForm = React.lazy(() =>
- import('./containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone'),
-);
-const BufferZoneDetails = React.lazy(() => import('./routes/BufferZoneDetailsRoutes'));
-
-const PostWatercourseForm = React.lazy(() =>
- import('./containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse'),
-);
-const WatercourseDetails = React.lazy(() => import('./routes/WatercourseDetailsRoutes'));
-
-const CropCatalogue = React.lazy(() => import('./containers/CropCatalogue'));
-const CropVarieties = React.lazy(() => import('./containers/CropVarieties'));
-const AddCrop = React.lazy(() => import('./containers/AddCropVariety/AddCropVariety'));
-const EditCrop = React.lazy(() => import('./containers/EditCropVariety'));
-const ComplianceInfo = React.lazy(() => import('./containers/AddCropVariety/ComplianceInfo'));
-const AddNewCrop = React.lazy(() => import('./containers/AddNewCrop'));
-const PlantingLocation = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/PlantingLocation'),
-);
-const Transplant = React.lazy(() => import('./containers/Crop/AddManagementPlan/Transplant'));
-const PlantingDate = React.lazy(() => import('./containers/Crop/AddManagementPlan/PlantingDate'));
-const PlantingMethod = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/PlantingMethod'),
-);
-const PlantInContainer = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/PlantInContainer'),
-);
-const PlantBroadcast = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/BroadcastPlan'),
-);
-const BedPlan = React.lazy(() => import('./containers/Crop/AddManagementPlan/BedPlan/BedPlan'));
-const BedPlanGuidance = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance'),
-);
-const ManagementPlanName = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/ManagementPlanName'),
-);
-const RowMethod = React.lazy(() => import('./containers/Crop/AddManagementPlan/RowMethod'));
-const RowMethodGuidance = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/RowMethod/RowGuidance'),
-);
-
-const PlantedAlready = React.lazy(() =>
- import('./containers/Crop/AddManagementPlan/PlantedAlready'),
-);
-
-const Documents = React.lazy(() => import('./containers/Documents'));
-
-const EditDocument = React.lazy(() => import('./containers/Documents/Edit'));
-
-const AddDocument = React.lazy(() => import('./containers/Documents/Add'));
-const MainDocument = React.lazy(() => import('./containers/Documents/Main'));
-const CertificationReportingPeriod = React.lazy(() =>
- import('./containers/Certifications/ReportingPeriod'),
-);
-const CertificationSurvey = React.lazy(() => import('./containers/Certifications/Survey'));
-
-const InterestedOrganic = React.lazy(() =>
- import('./containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic'),
-);
-const CertificationSelection = React.lazy(() =>
- import('./containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection'),
-);
-
-const CertifierSelectionMenu = React.lazy(() =>
- import('./containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu'),
-);
-
-const SetCertificationSummary = React.lazy(() =>
- import(
- './containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary'
- ),
-);
-
-const RequestCertifier = React.lazy(() =>
- import('./containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier'),
-);
-const ViewCertification = React.lazy(() =>
- import('./containers/OrganicCertifierSurvey/ViewCertification/ViewCertification'),
-);
-
-const RenderSurvey = React.lazy(() => import('./containers/RenderSurvey/RenderSurvey'));
-const ExportDownload = React.lazy(() => import('./containers/ExportDownload'));
-
-const ManagementTasks = React.lazy(() =>
- import('./containers/Crop/ManagementDetail/ManagementTasks'),
-);
-const ManagementDetails = React.lazy(() =>
- import('./containers/Crop/ManagementDetail/ManagementDetails'),
-);
-const EditManagementDetails = React.lazy(() =>
- import('./containers/Crop/ManagementDetail/EditManagementDetails'),
-);
-const CompleteManagementPlan = React.lazy(() =>
- import('./containers/Crop/CompleteManagementPlan/CompleteManagementPlan'),
-);
-const AbandonManagementPlan = React.lazy(() =>
- import('./containers/Crop/CompleteManagementPlan/AbandonManagementPlan'),
-);
-
-const TaskAssignment = React.lazy(() => import('./containers/Task/TaskAssignment'));
-const TaskDetails = React.lazy(() => import('./containers/Task/TaskDetails'));
-const TaskTypeSelection = React.lazy(() => import('./containers/Task/TaskTypeSelection'));
-const TaskDate = React.lazy(() => import('./containers/Task/TaskDate'));
-const TaskCrops = React.lazy(() => import('./containers/Task/TaskCrops'));
-const TaskLocations = React.lazy(() => import('./containers/Task/TaskLocations'));
-const Tasks = React.lazy(() => import('./containers/Task'));
-const ManageCustomTasks = React.lazy(() => import('./containers/Task/ManageCustomTasks'));
-const AddCustomTask = React.lazy(() => import('./containers/Task/AddCustomTask'));
-const TaskComplete = React.lazy(() => import('./containers/Task/TaskComplete'));
-const HarvestCompleteQuantity = React.lazy(() =>
- import('./containers/Task/TaskComplete/HarvestComplete/Quantity'),
-);
-const HarvestUses = React.lazy(() =>
- import('./containers/Task/TaskComplete/HarvestComplete/HarvestUses'),
-);
-const TaskCompleteStepOne = React.lazy(() => import('./containers/Task/TaskComplete/StepOne'));
-const TaskReadOnly = React.lazy(() => import('./containers/Task/TaskReadOnly'));
-const EditCustomTask = React.lazy(() => import('./containers/Task/EditCustomTask'));
-const TaskAbandon = React.lazy(() => import('./containers/Task/TaskAbandon'));
-const EditCustomTaskUpdate = React.lazy(() => import('./containers/Task/EditCustomTaskUpdate'));
-const TaskTransplantMethod = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskTransplantMethod'),
-);
-const TaskBedMethod = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskBedMethod'),
-);
-const TaskBedGuidance = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskBedGuidance'),
-);
-const TaskRowMethod = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskRowMethod'),
-);
-const TaskRowGuidance = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskRowGuidance'),
-);
-const TaskContainerMethod = React.lazy(() =>
- import('./containers/Task/TaskTransplantMethod/TaskContainerMethod'),
-);
-const ActualRevenue = React.lazy(() => import('./containers/Finances/ActualRevenue'));
-const UpdateEstimatedCropRevenue = React.lazy(() =>
- import('./containers/Finances/UpdateEstimatedCropRevenue'),
-);
-const Forbidden = React.lazy(() =>
- import('./containers/ErrorHandler/Forbidden/Forbidden'),
-);
-
-
-const Routes = () => {
- useScrollToTop();
- useReduxSnackbar();
- const userFarm = useSelector(
- userFarmSelector,
- (pre, next) =>
- pre.step_five === next.step_five &&
- pre.step_two === next.step_two &&
- pre.step_four === next.step_four &&
- pre.has_consent === next.has_consent &&
- pre.role_id === next.role_id &&
- pre.step_one === next.step_one &&
- pre.farm_id === next.farm_id &&
- pre.step_three === next.step_three,
- );
- const { isInvitationFlow } = useSelector(
- chooseFarmFlowSelector,
- (pre, next) => pre.isInvitationFlow === next.isInvitationFlow,
- );
- let {
- step_five,
- has_consent,
- role_id,
- status,
- step_one,
- farm_id,
- step_three,
- step_four,
- } = userFarm;
- const hasSelectedFarm = !!farm_id;
- const hasFinishedOnBoardingFlow = step_one && step_four && step_five;
- if (isAuthenticated()) {
- role_id = Number(role_id);
- // TODO check every step
- if (isInvitationFlow) {
- return (
- }>
-
-
- }
- />
-
- {!has_consent && }
-
-
- );
- } else if (!hasSelectedFarm || !hasFinishedOnBoardingFlow) {
- return ;
- } else if (!has_consent) {
- return (
- }>
-
-
- }
- />
- {!has_consent && }
-
-
- );
- } else if (role_id === 1) {
- return (
- }>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
- {/* */}
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- } else if (role_id === 2 || role_id === 5) {
- return (
- }>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* TODO: use edit_expense_categories and edit_add_expense when restructuring edit expense */}
- {/* and remove edit_expense */}
- {/* */}
- {/* */}
-
-
-
-
-
-
-
-
-
- {/* */}
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- } else {
- return (
- }>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {/* */}
-
- {/* */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
- } else if (!isAuthenticated()) {
- return (
- }>
-
-
-
-
-
-
-
-
-
-
-
- );
- }
-};
-
-export default Routes;
diff --git a/packages/webapp/src/Routes.jsx b/packages/webapp/src/Routes.jsx
new file mode 100644
index 0000000000..7a09d6a4a4
--- /dev/null
+++ b/packages/webapp/src/Routes.jsx
@@ -0,0 +1,1054 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (Routes.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { Suspense } from 'react';
+import { Redirect, Route, Switch } from 'react-router-dom';
+import Spinner from './components/Spinner';
+
+// Components that have already been set up with code splitting
+import OnboardingFlow from './routes/Onboarding';
+import CustomSignUp from './containers/CustomSignUp';
+import { useSelector } from 'react-redux';
+import { isAuthenticated } from './util/jwt';
+
+// action
+import { userFarmSelector } from './containers/userFarmSlice';
+import { chooseFarmFlowSelector } from './containers/ChooseFarm/chooseFarmFlowSlice';
+import useScrollToTop from './containers/hooks/useScrollToTop';
+import { useReduxSnackbar } from './containers/Snackbar/useReduxSnackbar';
+
+//dynamic imports
+const Home = React.lazy(() => import('./containers/Home'));
+const HelpRequest = React.lazy(() => import('./containers/Help'));
+const Account = React.lazy(() => import('./containers/Profile/Account'));
+const Farm = React.lazy(() => import('./containers/Profile/Farm/Farm'));
+const People = React.lazy(() => import('./containers/Profile/People/People'));
+const EditUser = React.lazy(() => import('./containers/Profile/EditUser'));
+const ConsentForm = React.lazy(() => import('./containers/Consent'));
+const Finances = React.lazy(() => import('./containers/Finances'));
+const ChooseFarm = React.lazy(() => import('./containers/ChooseFarm'));
+const PasswordResetAccount = React.lazy(() => import('./containers/PasswordResetAccount'));
+const InviteSignUp = React.lazy(() => import('./containers/InviteSignUp'));
+const InvitedUserCreateAccount = React.lazy(() => import('./containers/InvitedUserCreateAccount'));
+const Callback = React.lazy(() => import('./containers/Callback'));
+const JoinFarmSuccessScreen = React.lazy(() => import('./containers/JoinFarmSuccessScreen'));
+const InviteUser = React.lazy(() => import('./containers/InviteUser'));
+// Insights imports
+const Insights = React.lazy(() => import('./containers/Insights'));
+const PeopleFed = React.lazy(() => import('./containers/Insights/PeopleFed'));
+const SoilOM = React.lazy(() => import('./containers/Insights/SoilOM'));
+const LabourHappiness = React.lazy(() => import('./containers/Insights/LabourHappiness'));
+const Biodiversity = React.lazy(() => import('./containers/Insights/Biodiversity'));
+const Prices = React.lazy(() => import('./containers/Insights/Prices'));
+const WaterBalance = React.lazy(() => import('./containers/Insights/WaterBalance'));
+const Erosion = React.lazy(() => import('./containers/Insights/Erosion'));
+const NitrogenBalance = React.lazy(() => import('./containers/Insights/NitrogenBalance'));
+const SalesSummary = React.lazy(() => import('./containers/Finances/SalesSummary'));
+const AddSale = React.lazy(() => import('./containers/Finances/AddSale'));
+const EditSale = React.lazy(() => import('./containers/Finances/EditSale'));
+const LegacyEstimatedRevenue = React.lazy(() =>
+ import('./containers/Finances/LegacyEstimatedRevenue'),
+);
+const EstimatedRevenue = React.lazy(() => import('./containers/Finances/EstimatedRevenue'));
+const Labour = React.lazy(() => import('./containers/Finances/Labour'));
+const OtherExpense = React.lazy(() => import('./containers/Finances/OtherExpense'));
+const ExpenseDetail = React.lazy(() => import('./containers/Finances/ExpenseDetail'));
+const ExpenseCategories = React.lazy(() =>
+ import('./containers/Finances/NewExpense/ExpenseCategories'),
+);
+const AddExpense = React.lazy(() => import('./containers/Finances/NewExpense/AddExpense'));
+const TempEditExpense = React.lazy(() =>
+ import('./containers/Finances/EditExpense/TempEditExpense'),
+);
+const SaleDetail = React.lazy(() => import('./containers/Finances/SaleDetail'));
+const ExpiredTokenScreen = React.lazy(() => import('./containers/ExpiredTokenScreen'));
+const Map = React.lazy(() => import('./containers/Map'));
+const MapVideo = React.lazy(() => import('./components/Map/Videos'));
+const PostFarmSiteBoundaryForm = React.lazy(() =>
+ import(
+ './containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary'
+ ),
+);
+const FarmSiteBoundaryDetails = React.lazy(() => import('./routes/FarmSiteBoundaryDetailsRoutes'));
+
+const PostFieldForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/FieldDetailForm/PostField'),
+);
+const FieldDetails = React.lazy(() => import('./routes/FieldDetailsRoutes'));
+
+const PostGardenForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden'),
+);
+const GardenDetails = React.lazy(() => import('./routes/GardenDetailsRoutes'));
+
+const PostGateForm = React.lazy(() =>
+ import('./containers/LocationDetails/PointDetails/GateDetailForm/PostGate'),
+);
+const GateDetails = React.lazy(() => import('./routes/GateDetailsRoutes'));
+
+const PostWaterValveForm = React.lazy(() =>
+ import('./containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve'),
+);
+const WaterValveDetails = React.lazy(() => import('./routes/WaterValveDetailsRoutes'));
+
+const PostBarnForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn'),
+);
+const BarnDetails = React.lazy(() => import('./routes/BarnDetailsRoutes'));
+
+const PostNaturalAreaForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea'),
+);
+const NaturalAreaDetails = React.lazy(() => import('./routes/NaturalAreaDetailsRoutes'));
+
+const PostSurfaceWaterForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater'),
+);
+const SurfaceWaterDetails = React.lazy(() => import('./routes/SurfaceWaterDetailsRoutes'));
+
+const PostResidenceForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence'),
+);
+const ResidenceDetails = React.lazy(() => import('./routes/ResidenceDetailsRoutes'));
+
+const PostCeremonialForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea'),
+);
+const CeremonialAreaDetails = React.lazy(() => import('./routes/CeremonialAreaDetailsRoutes'));
+
+const PostGreenhouseForm = React.lazy(() =>
+ import('./containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse'),
+);
+const GreenhouseDetails = React.lazy(() => import('./routes/GreenhouseDetailsRoutes'));
+
+const CropManagement = React.lazy(() => import('./containers/Crop/CropManagement'));
+const CropDetail = React.lazy(() => import('./containers/Crop/CropDetail/index'));
+
+const PostFenceForm = React.lazy(() =>
+ import('./containers/LocationDetails/LineDetails/FenceDetailForm/PostFence'),
+);
+const FenceDetails = React.lazy(() => import('./routes/FenceDetailsRoutes'));
+
+const PostBufferZoneForm = React.lazy(() =>
+ import('./containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone'),
+);
+const BufferZoneDetails = React.lazy(() => import('./routes/BufferZoneDetailsRoutes'));
+
+const PostWatercourseForm = React.lazy(() =>
+ import('./containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse'),
+);
+const WatercourseDetails = React.lazy(() => import('./routes/WatercourseDetailsRoutes'));
+
+const CropCatalogue = React.lazy(() => import('./containers/CropCatalogue'));
+const CropVarieties = React.lazy(() => import('./containers/CropVarieties'));
+const AddCrop = React.lazy(() => import('./containers/AddCropVariety/AddCropVariety'));
+const EditCrop = React.lazy(() => import('./containers/EditCropVariety'));
+const ComplianceInfo = React.lazy(() => import('./containers/AddCropVariety/ComplianceInfo'));
+const AddNewCrop = React.lazy(() => import('./containers/AddNewCrop'));
+const PlantingLocation = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/PlantingLocation'),
+);
+const Transplant = React.lazy(() => import('./containers/Crop/AddManagementPlan/Transplant'));
+const PlantingDate = React.lazy(() => import('./containers/Crop/AddManagementPlan/PlantingDate'));
+const PlantingMethod = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/PlantingMethod'),
+);
+const PlantInContainer = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/PlantInContainer'),
+);
+const PlantBroadcast = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/BroadcastPlan'),
+);
+const BedPlan = React.lazy(() => import('./containers/Crop/AddManagementPlan/BedPlan/BedPlan'));
+const BedPlanGuidance = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance'),
+);
+const ManagementPlanName = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/ManagementPlanName'),
+);
+const RowMethod = React.lazy(() => import('./containers/Crop/AddManagementPlan/RowMethod'));
+const RowMethodGuidance = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/RowMethod/RowGuidance'),
+);
+
+const PlantedAlready = React.lazy(() =>
+ import('./containers/Crop/AddManagementPlan/PlantedAlready'),
+);
+
+const Documents = React.lazy(() => import('./containers/Documents'));
+
+const EditDocument = React.lazy(() => import('./containers/Documents/Edit'));
+
+const AddDocument = React.lazy(() => import('./containers/Documents/Add'));
+const MainDocument = React.lazy(() => import('./containers/Documents/Main'));
+const CertificationReportingPeriod = React.lazy(() =>
+ import('./containers/Certifications/ReportingPeriod'),
+);
+const CertificationSurvey = React.lazy(() => import('./containers/Certifications/Survey'));
+
+const InterestedOrganic = React.lazy(() =>
+ import('./containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic'),
+);
+const CertificationSelection = React.lazy(() =>
+ import('./containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection'),
+);
+
+const CertifierSelectionMenu = React.lazy(() =>
+ import('./containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu'),
+);
+
+const SetCertificationSummary = React.lazy(() =>
+ import(
+ './containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary'
+ ),
+);
+
+const RequestCertifier = React.lazy(() =>
+ import('./containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier'),
+);
+const ViewCertification = React.lazy(() =>
+ import('./containers/OrganicCertifierSurvey/ViewCertification/ViewCertification'),
+);
+
+const RenderSurvey = React.lazy(() => import('./containers/RenderSurvey/RenderSurvey'));
+const ExportDownload = React.lazy(() => import('./containers/ExportDownload'));
+
+const ManagementTasks = React.lazy(() =>
+ import('./containers/Crop/ManagementDetail/ManagementTasks'),
+);
+const ManagementDetails = React.lazy(() =>
+ import('./containers/Crop/ManagementDetail/ManagementDetails'),
+);
+const EditManagementDetails = React.lazy(() =>
+ import('./containers/Crop/ManagementDetail/EditManagementDetails'),
+);
+const CompleteManagementPlan = React.lazy(() =>
+ import('./containers/Crop/CompleteManagementPlan/CompleteManagementPlan'),
+);
+const AbandonManagementPlan = React.lazy(() =>
+ import('./containers/Crop/CompleteManagementPlan/AbandonManagementPlan'),
+);
+
+const TaskAssignment = React.lazy(() => import('./containers/Task/TaskAssignment'));
+const TaskDetails = React.lazy(() => import('./containers/Task/TaskDetails'));
+const TaskTypeSelection = React.lazy(() => import('./containers/Task/TaskTypeSelection'));
+const TaskDate = React.lazy(() => import('./containers/Task/TaskDate'));
+const TaskCrops = React.lazy(() => import('./containers/Task/TaskCrops'));
+const TaskLocations = React.lazy(() => import('./containers/Task/TaskLocations'));
+const Tasks = React.lazy(() => import('./containers/Task'));
+const ManageCustomTasks = React.lazy(() => import('./containers/Task/ManageCustomTasks'));
+const AddCustomTask = React.lazy(() => import('./containers/Task/AddCustomTask'));
+const TaskComplete = React.lazy(() => import('./containers/Task/TaskComplete'));
+const HarvestCompleteQuantity = React.lazy(() =>
+ import('./containers/Task/TaskComplete/HarvestComplete/Quantity'),
+);
+const HarvestUses = React.lazy(() =>
+ import('./containers/Task/TaskComplete/HarvestComplete/HarvestUses'),
+);
+const TaskCompleteStepOne = React.lazy(() => import('./containers/Task/TaskComplete/StepOne'));
+const TaskReadOnly = React.lazy(() => import('./containers/Task/TaskReadOnly'));
+const EditCustomTask = React.lazy(() => import('./containers/Task/EditCustomTask'));
+const TaskAbandon = React.lazy(() => import('./containers/Task/TaskAbandon'));
+const EditCustomTaskUpdate = React.lazy(() => import('./containers/Task/EditCustomTaskUpdate'));
+const TaskTransplantMethod = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskTransplantMethod'),
+);
+const TaskBedMethod = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskBedMethod'),
+);
+const TaskBedGuidance = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskBedGuidance'),
+);
+const TaskRowMethod = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskRowMethod'),
+);
+const TaskRowGuidance = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskRowGuidance'),
+);
+const TaskContainerMethod = React.lazy(() =>
+ import('./containers/Task/TaskTransplantMethod/TaskContainerMethod'),
+);
+const ActualRevenue = React.lazy(() => import('./containers/Finances/ActualRevenue'));
+const UpdateEstimatedCropRevenue = React.lazy(() =>
+ import('./containers/Finances/UpdateEstimatedCropRevenue'),
+);
+const Notification = React.lazy(() => import('./containers/Notification'));
+const NotificationReadOnly = React.lazy(() =>
+ import('./containers/Notification/NotificationReadOnly'),
+);
+const Forbidden = React.lazy(() => import('./containers/ErrorHandler/Forbidden/Forbidden'));
+
+const Routes = () => {
+ useScrollToTop();
+ useReduxSnackbar();
+ const userFarm = useSelector(
+ userFarmSelector,
+ (pre, next) =>
+ pre.step_five === next.step_five &&
+ pre.step_two === next.step_two &&
+ pre.step_four === next.step_four &&
+ pre.has_consent === next.has_consent &&
+ pre.role_id === next.role_id &&
+ pre.step_one === next.step_one &&
+ pre.farm_id === next.farm_id &&
+ pre.step_three === next.step_three,
+ );
+ const { isInvitationFlow } = useSelector(
+ chooseFarmFlowSelector,
+ (pre, next) => pre.isInvitationFlow === next.isInvitationFlow,
+ );
+ let { step_five, has_consent, role_id, status, step_one, farm_id, step_three, step_four } =
+ userFarm;
+ const hasSelectedFarm = !!farm_id;
+ const hasFinishedOnBoardingFlow = step_one && step_four && step_five;
+ if (isAuthenticated()) {
+ role_id = Number(role_id);
+ // TODO check every step
+ if (isInvitationFlow) {
+ return (
+ }>
+
+
+ }
+ />
+
+ {!has_consent && }
+
+
+ );
+ } else if (!hasSelectedFarm || !hasFinishedOnBoardingFlow) {
+ return ;
+ } else if (!has_consent) {
+ return (
+ }>
+
+
+ }
+ />
+ {!has_consent && }
+
+
+ );
+ } else if (role_id === 1) {
+ return (
+ }>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+ {/* */}
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ } else if (role_id === 2 || role_id === 5) {
+ return (
+ }>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ } else {
+ return (
+ }>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+
+ {/* */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+ } else if (!isAuthenticated()) {
+ return (
+ }>
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+};
+
+export default Routes;
diff --git a/packages/webapp/src/apiConfig.js b/packages/webapp/src/apiConfig.js
index 55b48f4271..100bf4629d 100644
--- a/packages/webapp/src/apiConfig.js
+++ b/packages/webapp/src/apiConfig.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (apiConfig.js) is part of LiteFarm.
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,57 +14,98 @@
*/
let URI;
-const NODE_ENV = process.env.NODE_ENV || 'development';
-const REACT_APP_ENV = process.env.REACT_APP_ENV || 'development';
-
-if (NODE_ENV === 'development') {
- URI = window.location.href.replace(/3000.*/, '5000');
-} else if (NODE_ENV === 'production') {
- if (REACT_APP_ENV === 'production') {
+const VITE_ENV = import.meta.env.VITE_ENV || 'development';
+if (import.meta.env.VITE_API_URL?.length) {
+ URI = import.meta.env.VITE_API_URL;
+} else {
+ if (VITE_ENV === 'development') {
+ URI = window.location.href.replace(/3000.*/, '5000');
+ } else if (VITE_ENV === 'production') {
URI = 'https://api.app.litefarm.org';
- } else if (REACT_APP_ENV === 'integration') {
+ } else if (VITE_ENV === 'integration') {
URI = 'https://api.beta.litefarm.org';
}
}
-const apiConfig = {
- userUrl: `${URI}/user`,
- pseudoUserUrl: `${URI}/user/pseudo`,
- farmUrl: `${URI}/farm`,
- inviteUserUrl: `${URI}/user/invite`,
- fieldURL: `${URI}/field`,
- locationURL: `${URI}/location`,
- cropURL: `${URI}/crop`,
- cropVarietyURL: `${URI}/crop_variety`,
- logURL: `${URI}/log`,
- fertUrl: `${URI}/fertilizer`,
- managementPlanURL: `${URI}/management_plan`,
- pesticideUrl: `${URI}/pesticide`,
- diseaseUrl: `${URI}/disease`,
- taskTypeUrl: `${URI}/task_type`,
- shiftUrl: `${URI}/shift`,
- priceURL: `${URI}/price`,
- yieldURL: `${URI}/yield`,
- insightUrl: `${URI}/insight`,
- documentUrl: `${URI}/document`,
- salesURL: URI + '/sale',
- cropSalesURL: URI + '/crop_sale',
- farmShiftUrl: URI + '/shift/farm/',
- expenseUrl: URI + '/expense',
- expenseTypeDefaultUrl: URI + '/expense_type',
- contactURL: URI + '/contact',
- farmDataUrl: URI + '/farmdata',
- userFarmUrl: `${URI}/user_farm`,
- weatherAPIKey: process.env.REACT_APP_WEATHER_API_KEY,
- // userFarm: URI + '/user_farm',
- rolesUrl: URI + '/roles',
- signUpUrl: `${URI}/sign_up`,
- loginUrl: `${URI}/login`,
- resetPasswordUrl: `${URI}/password_reset`,
- spotlightUrl: `${URI}/showed_spotlight`,
- taskUrl: `${URI}/task`,
- productsUrl: `${URI}/product`,
- url: URI,
-};
+export const userUrl = `${URI}/user`;
+export const pseudoUserUrl = `${URI}/user/pseudo`;
+export const farmUrl = `${URI}/farm`;
+export const inviteUserUrl = `${URI}/user/invite`;
+export const fieldURL = `${URI}/field`;
+export const locationURL = `${URI}/location`;
+export const cropURL = `${URI}/crop`;
+export const cropVarietyURL = `${URI}/crop_variety`;
+export const logURL = `${URI}/log`;
+export const fertUrl = `${URI}/fertilizer`;
+export const managementPlanURL = `${URI}/management_plan`;
+export const pesticideUrl = `${URI}/pesticide`;
+export const diseaseUrl = `${URI}/disease`;
+export const taskTypeUrl = `${URI}/task_type`;
+export const shiftUrl = `${URI}/shift`;
+export const priceURL = `${URI}/price`;
+export const yieldURL = `${URI}/yield`;
+export const insightUrl = `${URI}/insight`;
+export const documentUrl = `${URI}/document`;
+export const salesURL = URI + '/sale';
+export const cropSalesURL = URI + '/crop_sale';
+export const farmShiftUrl = URI + '/shift/farm/';
+export const expenseUrl = URI + '/expense';
+export const expenseTypeDefaultUrl = URI + '/expense_type';
+export const contactURL = URI + '/contact';
+export const farmDataUrl = URI + '/farmdata';
+export const userFarmUrl = `${URI}/user_farm`;
+export const weatherAPIKey = import.meta.env.VITE_WEATHER_API_KEY;
+// export const userFarm = URI + '/user_farm';
+export const rolesUrl = URI + '/roles';
+export const signUpUrl = `${URI}/sign_up`;
+export const loginUrl = `${URI}/login`;
+export const resetPasswordUrl = `${URI}/password_reset`;
+export const spotlightUrl = `${URI}/showed_spotlight`;
+export const taskUrl = `${URI}/task`;
+export const productsUrl = `${URI}/product`;
+export const alertsUrl = `${URI}/notification_user/subscribe`;
+export const notificationsUrl = `${URI}/notification_user`;
+export const clearAlertsUrl = `${URI}/notification_user/clear_alerts`;
+export const url = URI;
-module.exports = apiConfig;
+export default {
+ userUrl,
+ pseudoUserUrl,
+ farmUrl,
+ inviteUserUrl,
+ fieldURL,
+ locationURL,
+ cropURL,
+ cropVarietyURL,
+ logURL,
+ fertUrl,
+ managementPlanURL,
+ pesticideUrl,
+ diseaseUrl,
+ taskTypeUrl,
+ shiftUrl,
+ priceURL,
+ yieldURL,
+ insightUrl,
+ documentUrl,
+ salesURL,
+ cropSalesURL,
+ farmShiftUrl,
+ expenseUrl,
+ expenseTypeDefaultUrl,
+ contactURL,
+ farmDataUrl,
+ userFarmUrl,
+ weatherAPIKey,
+ // userFarm,
+ rolesUrl,
+ signUpUrl,
+ loginUrl,
+ resetPasswordUrl,
+ spotlightUrl,
+ taskUrl,
+ productsUrl,
+ alertsUrl,
+ notificationsUrl,
+ url,
+};
diff --git a/packages/webapp/src/assets/images/alert.svg b/packages/webapp/src/assets/images/alert.svg
new file mode 100644
index 0000000000..1f47668007
--- /dev/null
+++ b/packages/webapp/src/assets/images/alert.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/webapp/src/assets/images/my-farm-fr.svg b/packages/webapp/src/assets/images/my-farm-fr.svg
new file mode 100644
index 0000000000..bd2cb62bc0
--- /dev/null
+++ b/packages/webapp/src/assets/images/my-farm-fr.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/packages/webapp/src/assets/images/signUp/signup_french.svg b/packages/webapp/src/assets/images/signUp/signup_french.svg
new file mode 100644
index 0000000000..57391206eb
--- /dev/null
+++ b/packages/webapp/src/assets/images/signUp/signup_french.svg
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/webapp/src/assets/images/task/CalendarIcon.svg b/packages/webapp/src/assets/images/task/CalendarIcon.svg
new file mode 100644
index 0000000000..182fc385d2
--- /dev/null
+++ b/packages/webapp/src/assets/images/task/CalendarIcon.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/packages/webapp/src/assets/images/taskFilter/CalendarDown.svg b/packages/webapp/src/assets/images/taskFilter/CalendarDown.svg
new file mode 100755
index 0000000000..33c37e9e94
--- /dev/null
+++ b/packages/webapp/src/assets/images/taskFilter/CalendarDown.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/packages/webapp/src/assets/images/taskFilter/CalendarUp.svg b/packages/webapp/src/assets/images/taskFilter/CalendarUp.svg
new file mode 100755
index 0000000000..23b78a8082
--- /dev/null
+++ b/packages/webapp/src/assets/images/taskFilter/CalendarUp.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/packages/webapp/src/assets/theme/index.js b/packages/webapp/src/assets/theme/index.js
deleted file mode 100644
index 5f3674a014..0000000000
--- a/packages/webapp/src/assets/theme/index.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import { createMuiTheme, ThemeProvider } from '@material-ui/core';
-import React from 'react';
-
-export const colors = {
- teal900: '#085d50',
- teal700: '#028577',
- teal600: '#3ea992',
- teal500: '#89d1c7',
- teal100: '#f1fbf9',
- green700: '#78c99e',
- green400: '#a8e6bd',
- green200: '#c7efd3',
- green100: '#e3f8ec',
- yellow700: '#ffb800',
- yellow400: '#fed450',
- yellow300: '#fce38d',
- grey900: '#282b36',
- grey600: '#66738a',
- grey500: '#9faabe',
- grey400: '#d4dae3',
- grey200: '#f3f6fb',
- grey100: '#fafafd',
- overlay: 'rgba(36, 39, 48, 0.5)',
- red700: '#D02620',
- red400: '#f58282',
- orange700: '#ffa73f',
- orange400: '#ffc888',
- purple700: '#8f26f0',
- purple400: '#ffe55b',
- brightGreen700: '#037A0F',
- brightGreen400: '#a6f7ae',
- cyan700: '#03a6ca',
- cayn400: '#4fdbfa',
- blue200: '#e9f3ff',
- blue700: '#0669E1',
- grey1: '#333333',
- brown700: '#AA5F04',
- brown900: '#7E4C0E',
-};
-
-const theme = createMuiTheme({
- palette: {
- primary: {
- contrastText: colors.grey900,
- main: colors.teal700,
- },
- secondary: {
- contrastText: colors.grey900,
- main: '#fff',
- },
- success: {
- contrastText: colors.grey900,
- main: colors.brightGreen700,
- },
- info: {
- contrastText: colors.grey900,
- main: colors.blue700,
- },
- warning: {
- contrastText: colors.grey900,
- main: colors.orange700,
- },
- error: {
- contrastText: colors.grey900,
- main: colors.red700,
- },
- background: {
- default: '#fff',
- paper: '#fff',
- },
- text: {
- primary: colors.grey900,
- disabled: colors.grey600,
- hint: colors.grey600,
- },
- action: {
- hover: colors.green100,
- hoverOpacity: 0.5,
- active: colors.green100,
- selected: colors.green100,
- focus: colors.green100,
- },
- },
- typography: {
- fontFamily: '"Open Sans"," SansSerif", serif',
- },
- props: {
- MuiButtonBase: {
- disableRipple: true,
- },
- },
- overrides: {
- MuiCssBaseline: {
- '@global': {
- body: {
- backgroundColor: '#fff',
- overflowX: 'hidden !important',
- },
- '*': {
- boxSizing: 'border-box',
- margin: 0,
- padding: 0,
- },
- },
- },
- },
-});
-
-export default theme;
-const defaultTheme = createMuiTheme({});
-export const DefaultThemeProvider = ({ children }) => (
- {children}
-);
diff --git a/packages/webapp/src/assets/theme/index.tsx b/packages/webapp/src/assets/theme/index.tsx
new file mode 100644
index 0000000000..a8efd9b008
--- /dev/null
+++ b/packages/webapp/src/assets/theme/index.tsx
@@ -0,0 +1,117 @@
+import { createTheme, ThemeProvider } from '@material-ui/core';
+import React, { FC } from 'react';
+
+export const colors = {
+ teal900: '#085d50',
+ teal700: '#028577',
+ teal600: '#3ea992',
+ teal500: '#89d1c7',
+ teal100: '#f1fbf9',
+ green700: '#78c99e',
+ green400: '#a8e6bd',
+ green200: '#c7efd3',
+ green100: '#e3f8ec',
+ yellow700: '#ffb800',
+ yellow400: '#fed450',
+ yellow300: '#fce38d',
+ grey900: '#282b36',
+ grey600: '#66738a',
+ grey500: '#9faabe',
+ grey400: '#d4dae3',
+ grey200: '#f3f6fb',
+ grey100: '#fafafd',
+ overlay: 'rgba(36, 39, 48, 0.5)',
+ red700: '#D02620',
+ red400: '#f58282',
+ orange700: '#ffa73f',
+ orange400: '#ffc888',
+ purple700: '#8f26f0',
+ purple400: '#ffe55b',
+ brightGreen700: '#037A0F',
+ brightGreen400: '#a6f7ae',
+ cyan700: '#03a6ca',
+ cayn400: '#4fdbfa',
+ blue200: '#e9f3ff',
+ blue700: '#0669E1',
+ grey1: '#333333',
+ brown700: '#AA5F04',
+ brown900: '#7E4C0E',
+};
+
+const theme = createTheme({
+ palette: {
+ primary: {
+ contrastText: colors.grey900,
+ main: colors.teal700,
+ },
+ secondary: {
+ contrastText: colors.grey900,
+ main: '#fff',
+ },
+ success: {
+ contrastText: colors.grey900,
+ main: colors.brightGreen700,
+ },
+ info: {
+ contrastText: colors.grey900,
+ main: colors.blue700,
+ },
+ warning: {
+ contrastText: colors.grey900,
+ main: colors.orange700,
+ },
+ error: {
+ contrastText: colors.grey900,
+ main: colors.red700,
+ },
+ background: {
+ default: '#fff',
+ paper: '#fff',
+ },
+ text: {
+ primary: colors.grey900,
+ disabled: colors.grey600,
+ hint: colors.grey600,
+ },
+ action: {
+ hover: colors.green100,
+ hoverOpacity: 0.5,
+ active: colors.green100,
+ selected: colors.green100,
+ focus: colors.green100,
+ },
+ },
+ typography: {
+ fontFamily: '"Open Sans"," SansSerif", serif',
+ },
+ props: {
+ MuiButtonBase: {
+ disableRipple: true,
+ },
+ },
+ overrides: {
+ MuiCssBaseline: {
+ '@global': {
+ html: {
+ height: '100%',
+ },
+ body: {
+ height: '100%',
+ backgroundColor: '#fff',
+ overflowX: 'hidden',
+ },
+ '*': {
+ boxSizing: 'border-box',
+ margin: 0,
+ padding: 0,
+ },
+ },
+ },
+ },
+});
+
+export default theme;
+const defaultTheme = createTheme({});
+export const DefaultThemeProvider: FC = ({ children }) => (
+ {children}
+);
diff --git a/packages/webapp/src/components/ActiveFilterBox/index.js b/packages/webapp/src/components/ActiveFilterBox/index.js
deleted file mode 100644
index e53cb4f2bf..0000000000
--- a/packages/webapp/src/components/ActiveFilterBox/index.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import Pill from '../Filter/Pill';
-import clsx from 'clsx';
-import { BsChevronDown } from 'react-icons/bs';
-import { useDispatch } from 'react-redux';
-import { removeFilter, removeNonFilterValue } from '../../containers/filterSlice';
-import { VALID_ON } from '../../containers/Filter/constants';
-import { useTranslation } from 'react-i18next';
-
-const ActiveFilterBox = ({ pageFilter, pageFilterKey, style }) => {
- const [firstRow, setFirstRow] = useState(0);
- const [open, setOpen] = useState(false);
-
- const { t } = useTranslation();
- const dispatch = useDispatch();
-
- const activeFilters = Object.keys(pageFilter).reduce((acc, filterKey) => {
- if (filterKey === 'date') return acc;
- if (filterKey === VALID_ON) {
- if (pageFilter[filterKey])
- return [
- ...acc,
- {
- filterKey,
- value: pageFilter[filterKey],
- label: `${t('DOCUMENTS.FILTER.VALID_ON')}: ${pageFilter[filterKey]}`,
- customRemoveFilter: removeNonFilterValue({ pageFilterKey, filterKey }),
- },
- ];
- else return acc;
- }
- return [...acc].concat(
- Object.keys(pageFilter[filterKey])
- .filter((k) => pageFilter[filterKey][k].active)
- .map((k) => ({
- filterKey,
- value: k,
- label: pageFilter[filterKey][k].label,
- })),
- );
- }, []);
-
- const handleResize = () => {
- const elements = document.getElementsByClassName('activePill');
- let y = 0;
- let firstRowEle = 0;
- for (const element of elements) {
- const top = element.getClientRects()?.[0]?.top;
- if (!y) {
- y = top;
- } else if (y !== top) {
- setFirstRow(firstRowEle);
- return;
- }
- firstRowEle++;
- }
- setFirstRow(firstRowEle);
- };
-
- useEffect(() => {
- handleResize();
- window.addEventListener('resize', handleResize);
- return (_) => window.removeEventListener('resize', handleResize);
- }, []);
-
- useEffect(() => {
- handleResize();
- }, [activeFilters]);
-
- const numHidden = activeFilters.length - firstRow;
-
- const handleRemovePill = (filter) => () => {
- const { filterKey, customRemoveFilter } = filter;
- if (customRemoveFilter) {
- dispatch(customRemoveFilter);
- return;
- }
- dispatch(removeFilter({ pageFilterKey, filterKey, value: filter.value }));
- };
-
- // open
- if (open)
- return (
-
-
- {activeFilters.map((filter) => {
- return (
-
- );
- })}
- {numHidden > 0 && (
-
setOpen(false)}>
-
-
- )}
-
-
- );
-
- // closed
- return (
-
-
- {activeFilters.map((filter) => {
- return (
-
- );
- })}
-
- {numHidden > 0 && (
-
setOpen(true)}>
- {`+${numHidden}`}
-
-
- )}
-
- );
-};
-
-ActiveFilterBox.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
- filterKey: PropTypes.string,
-};
-
-export default ActiveFilterBox;
diff --git a/packages/webapp/src/components/ActiveFilterBox/index.jsx b/packages/webapp/src/components/ActiveFilterBox/index.jsx
new file mode 100644
index 0000000000..20514d46d7
--- /dev/null
+++ b/packages/webapp/src/components/ActiveFilterBox/index.jsx
@@ -0,0 +1,147 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import Pill from '../Filter/Pill';
+import clsx from 'clsx';
+import { BsChevronDown } from 'react-icons/bs';
+import { useDispatch } from 'react-redux';
+import { removeFilter, removeNonFilterValue } from '../../containers/filterSlice';
+import { VALID_ON } from '../../containers/Filter/constants';
+import { useTranslation } from 'react-i18next';
+
+const ActiveFilterBox = ({ pageFilter, pageFilterKey, style }) => {
+ const [firstRow, setFirstRow] = useState(0);
+ const [open, setOpen] = useState(false);
+
+ const { t } = useTranslation(['translation', 'filter']);
+ const dispatch = useDispatch();
+
+ const activeFilters = Object.keys(pageFilter).reduce((acc, filterKey) => {
+ const filter = pageFilter[filterKey];
+ const filterType = typeof filter;
+
+ if (filterType === 'object') {
+ return [...acc].concat(
+ Object.keys(pageFilter[filterKey])
+ .filter((k) => pageFilter[filterKey][k].active)
+ .map((k) => ({
+ filterKey,
+ value: k,
+ label: pageFilter[filterKey][k].label,
+ })),
+ );
+ }
+
+ if (filterType === 'string') {
+ return [
+ ...acc,
+ {
+ filterKey,
+ value: pageFilter[filterKey],
+ label: `${t(`filter:FILTER.${filterKey}`)}: ${pageFilter[filterKey]}`,
+ customRemoveFilter: removeNonFilterValue({ pageFilterKey, filterKey }),
+ },
+ ];
+ }
+
+ return acc;
+ }, []);
+
+ const handleResize = () => {
+ const elements = document.getElementsByClassName('activePill');
+ let y = 0;
+ let firstRowEle = 0;
+ for (const element of elements) {
+ const top = element.getClientRects()?.[0]?.top;
+ if (!y) {
+ y = top;
+ } else if (y !== top) {
+ setFirstRow(firstRowEle);
+ return;
+ }
+ firstRowEle++;
+ }
+ setFirstRow(firstRowEle);
+ };
+
+ useEffect(() => {
+ handleResize();
+ window.addEventListener('resize', handleResize);
+ return (_) => window.removeEventListener('resize', handleResize);
+ }, []);
+
+ useEffect(() => {
+ handleResize();
+ }, [activeFilters]);
+
+ const numHidden = activeFilters.length - firstRow;
+
+ const handleRemovePill = (filter) => () => {
+ const { filterKey, customRemoveFilter } = filter;
+ if (customRemoveFilter) {
+ dispatch(customRemoveFilter);
+ return;
+ }
+ dispatch(removeFilter({ pageFilterKey, filterKey, value: filter.value }));
+ };
+
+ // open
+ if (open)
+ return (
+
+
+ {activeFilters.map((filter) => {
+ return (
+
+ );
+ })}
+ {numHidden > 0 && (
+
setOpen(false)}>
+
+
+ )}
+
+
+ );
+
+ // closed
+ return (
+
+
+ {activeFilters.map((filter) => {
+ return (
+
+ );
+ })}
+
+ {numHidden > 0 && (
+
setOpen(true)}>
+ {`+${numHidden}`}
+
+
+ )}
+
+ );
+};
+
+ActiveFilterBox.prototype = {
+ subject: PropTypes.string,
+ items: PropTypes.array,
+ filterKey: PropTypes.string,
+};
+
+export default ActiveFilterBox;
diff --git a/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.js b/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.js
deleted file mode 100644
index 53915552e4..0000000000
--- a/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.js
+++ /dev/null
@@ -1,201 +0,0 @@
-import Button from '../../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Label } from '../../Typography';
-import Form from '../../Form';
-import Leaf from '../../../assets/images/farmMapFilter/Leaf.svg';
-import RadioGroup from '../../Form/RadioGroup';
-import Infoi from '../../Tooltip/Infoi';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import Input, { integerOnKeyDown } from '../../Form/Input';
-
-export default function ComplianceInfo({
- onSubmit,
- onError,
- onGoBack,
- persistedFormData,
- useHookFormPersist,
- match,
- crop,
-}) {
- const { t } = useTranslation(['translation', 'common', 'crop']);
- const CERTIFIED_ORGANIC = 'organic';
- const COMMERCIAL_AVAILABILITY = 'searched';
- const GENETIC_EGINEERED = 'genetically_engineered';
- const TREATED = 'treated';
- const HS_CODE_ID = 'hs_code_id';
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: { [HS_CODE_ID]: crop?.[HS_CODE_ID], ...persistedFormData },
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- const organic = watch(CERTIFIED_ORGANIC);
- const disabled = !isValid;
-
- const labelStyle = {
- paddingRight: '10px',
- fontSize: '16px',
- lineHeight: '20px',
- display: 'inline-block',
- };
-
- const progress = 66;
-
- return (
-
- );
-}
-
-ComplianceInfo.prototype = {
- onSubmit: PropTypes.func,
- onError: PropTypes.func,
- onGoBack: PropTypes.func,
- onCancel: PropTypes.func,
- persistedFormData: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- match: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.jsx b/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.jsx
new file mode 100644
index 0000000000..8e3a7366ea
--- /dev/null
+++ b/packages/webapp/src/components/AddCropVariety/ComplianceInfo/index.jsx
@@ -0,0 +1,210 @@
+import Button from '../../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Label } from '../../Typography';
+import Form from '../../Form';
+import Leaf from '../../../assets/images/farmMapFilter/Leaf.svg';
+import RadioGroup from '../../Form/RadioGroup';
+import Infoi from '../../Tooltip/Infoi';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import Input, { integerOnKeyDown } from '../../Form/Input';
+
+export default function ComplianceInfo({
+ onSubmit,
+ onError,
+ onGoBack,
+ persistedFormData,
+ useHookFormPersist,
+ match,
+ crop,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'crop']);
+ const CERTIFIED_ORGANIC = 'organic';
+ const COMMERCIAL_AVAILABILITY = 'searched';
+ const GENETIC_EGINEERED = 'genetically_engineered';
+ const TREATED = 'treated';
+ const HS_CODE_ID = 'hs_code_id';
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: true,
+ defaultValues: { [HS_CODE_ID]: crop?.[HS_CODE_ID], ...persistedFormData },
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const organic = watch(CERTIFIED_ORGANIC);
+ const disabled = !isValid;
+
+ const labelStyle = {
+ paddingRight: '10px',
+ fontSize: '16px',
+ lineHeight: '20px',
+ display: 'inline-block',
+ };
+
+ const progress = 66;
+
+ return (
+
+ );
+}
+
+ComplianceInfo.prototype = {
+ onSubmit: PropTypes.func,
+ onError: PropTypes.func,
+ onGoBack: PropTypes.func,
+ onCancel: PropTypes.func,
+ persistedFormData: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ match: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/AddCropVariety/index.js b/packages/webapp/src/components/AddCropVariety/index.js
deleted file mode 100644
index 1aec8ca4ea..0000000000
--- a/packages/webapp/src/components/AddCropVariety/index.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import Button from '../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Label } from '../Typography';
-import Input from '../Form/Input';
-import styles from './styles.module.scss';
-import Radio from '../Form/Radio';
-import Form from '../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
-
-export default function PureAddCropVariety({
- match,
- onSubmit,
- onError,
- useHookFormPersist,
- isSeekingCert,
- persistedFormData,
- crop,
- imageUploader,
- handleGoBack,
-}) {
- const { t } = useTranslation(['translation', 'common', 'crop']);
- const VARIETY = 'crop_variety_name';
- const SUPPLIER = 'supplier';
- const LIFE_CYCLE = 'lifecycle';
- const CROP_VARIETY_PHOTO_URL = 'crop_variety_photo_url';
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: {
- crop_variety_photo_url:
- crop.crop_photo_url ||
- `https://${process.env.REACT_APP_DO_BUCKET_NAME}.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp`,
- [LIFE_CYCLE]: crop[LIFE_CYCLE],
- ...persistedFormData,
- },
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- const disabled = !isValid;
-
- const varietyRegister = register(VARIETY, { required: true });
- const supplierRegister = register(SUPPLIER, { required: isSeekingCert ? true : false });
- const lifeCycleRegister = register(LIFE_CYCLE, { required: true });
- const imageUrlRegister = register(CROP_VARIETY_PHOTO_URL, { required: true });
-
- const crop_variety_photo_url = watch(CROP_VARIETY_PHOTO_URL);
- const cropTranslationKey = crop.crop_translation_key;
- const cropNameLabel = cropTranslationKey
- ? t(`crop:${cropTranslationKey}`)
- : crop.crop_common_name;
-
- const progress = 33;
- return (
-
- );
-}
-
-PureAddCropVariety.prototype = {
- history: PropTypes.object,
- match: PropTypes.object,
- onSubmit: PropTypes.func,
- onError: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- isSeekingCert: PropTypes.bool,
- persistedFormData: PropTypes.object,
- crop: PropTypes.object,
- imageUploader: PropTypes.node,
-};
diff --git a/packages/webapp/src/components/AddCropVariety/index.jsx b/packages/webapp/src/components/AddCropVariety/index.jsx
new file mode 100644
index 0000000000..6cabaa4029
--- /dev/null
+++ b/packages/webapp/src/components/AddCropVariety/index.jsx
@@ -0,0 +1,182 @@
+import Button from '../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Label } from '../Typography';
+import Input, { integerOnKeyDown } from '../Form/Input';
+import styles from './styles.module.scss';
+import Radio from '../Form/Radio';
+import Form from '../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
+
+export default function PureAddCropVariety({
+ match,
+ onSubmit,
+ onError,
+ useHookFormPersist,
+ isSeekingCert,
+ persistedFormData,
+ crop,
+ imageUploader,
+ handleGoBack,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'crop']);
+ const VARIETY = 'crop_variety_name';
+ const SUPPLIER = 'supplier';
+ const LIFE_CYCLE = 'lifecycle';
+ const CROP_VARIETY_PHOTO_URL = 'crop_variety_photo_url';
+ const HS_CODE_ID = 'hs_code_id';
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: true,
+ defaultValues: {
+ crop_variety_photo_url:
+ crop.crop_photo_url ||
+ `https://${
+ import.meta.env.VITE_DO_BUCKET_NAME
+ }.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp`,
+ [LIFE_CYCLE]: crop[LIFE_CYCLE],
+ [HS_CODE_ID]: crop?.[HS_CODE_ID],
+ ...persistedFormData,
+ },
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const disabled = !isValid;
+
+ const varietyRegister = register(VARIETY, { required: true });
+ const supplierRegister = register(SUPPLIER, { required: isSeekingCert ? true : false });
+ const lifeCycleRegister = register(LIFE_CYCLE, { required: true });
+ const imageUrlRegister = register(CROP_VARIETY_PHOTO_URL, { required: true });
+
+ const crop_variety_photo_url = watch(CROP_VARIETY_PHOTO_URL);
+ const cropTranslationKey = crop.crop_translation_key;
+ const cropNameLabel = cropTranslationKey
+ ? t(`crop:${cropTranslationKey}`)
+ : crop.crop_common_name;
+
+ const progress = 33;
+ return (
+
+ );
+}
+
+PureAddCropVariety.prototype = {
+ history: PropTypes.object,
+ match: PropTypes.object,
+ onSubmit: PropTypes.func,
+ onError: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ isSeekingCert: PropTypes.bool,
+ persistedFormData: PropTypes.object,
+ crop: PropTypes.object,
+ imageUploader: PropTypes.node,
+};
diff --git a/packages/webapp/src/components/AddFarm/index.js b/packages/webapp/src/components/AddFarm/index.js
deleted file mode 100644
index 32c2d46331..0000000000
--- a/packages/webapp/src/components/AddFarm/index.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import Input from '../Form/Input';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../PageTitle/v2';
-
-const style = {
- marginBottom: '28px',
-};
-
-export default function PureAddFarm({
- title,
- inputs = [{}, {}],
- onGoBack,
- onSubmit,
- map,
- loading,
- disabled,
-}) {
- const { t } = useTranslation(['translation', 'common']);
- return (
-
- );
-}
-
-PureAddFarm.prototype = {
- title: PropTypes.string,
- onSubmit: PropTypes.func,
- map: PropTypes.node,
- inputs: PropTypes.arrayOf(
- PropTypes.exact({
- label: PropTypes.string,
- info: PropTypes.string,
- icon: PropTypes.node,
- }),
- ),
-};
diff --git a/packages/webapp/src/components/AddFarm/index.jsx b/packages/webapp/src/components/AddFarm/index.jsx
new file mode 100644
index 0000000000..39cf5fbece
--- /dev/null
+++ b/packages/webapp/src/components/AddFarm/index.jsx
@@ -0,0 +1,51 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import Input from '../Form/Input';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../PageTitle/v2';
+
+const style = {
+ marginBottom: '28px',
+};
+
+export default function PureAddFarm({
+ title,
+ inputs = [{}, {}],
+ onGoBack,
+ onSubmit,
+ map,
+ loading,
+ disabled,
+}) {
+ const { t } = useTranslation(['translation', 'common']);
+ return (
+
+ );
+}
+
+PureAddFarm.prototype = {
+ title: PropTypes.string,
+ onSubmit: PropTypes.func,
+ map: PropTypes.node,
+ inputs: PropTypes.arrayOf(
+ PropTypes.exact({
+ label: PropTypes.string,
+ info: PropTypes.string,
+ icon: PropTypes.node,
+ }),
+ ),
+};
diff --git a/packages/webapp/src/components/AddNewCrop/index.js b/packages/webapp/src/components/AddNewCrop/index.js
deleted file mode 100644
index c988ac008a..0000000000
--- a/packages/webapp/src/components/AddNewCrop/index.js
+++ /dev/null
@@ -1,193 +0,0 @@
-import Button from '../Form/Button';
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Semibold } from '../Typography';
-import Input, { getInputErrors } from '../Form/Input';
-//import styles from './styles.module.scss';
-import Form from '../Form';
-import { Controller, useForm } from 'react-hook-form';
-import ReactSelect from '../Form/ReactSelect';
-import { BsChevronDown } from 'react-icons/bs';
-import {
- BEVERAGE_AND_SPICE_CROPS,
- CEREALS,
- FIRST_NUTRIENT_ARRAY,
- FRUITS_AND_NUTS,
- HIGH_STARCH_ROOT_TUBER_CROP,
- LEGUMINOUS_CROPS,
- NUTRIENT_ARRAY,
- NUTRIENT_DICT,
- OILSEED_CROPS,
- OTHER_CROPS,
- POTATOES_AND_YAMS,
- SECOND_NUTRIENT_ARRAY,
- STIMULANT_SPICE_AROMATIC_CROPS,
- SUGAR_CROPS,
- VEGETABLE_AND_MELONS,
-} from './constants';
-import { cropGroupAverages as cropGroupAveragesSelector } from '../../containers/cropSlice';
-import { useSelector } from 'react-redux';
-import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
-import RadioGroup from '../Form/RadioGroup';
-import styles from './styles.module.scss';
-
-export default function PureAddNewCrop({
- handleContinue,
- handleGoBack,
- handleCancel,
- persistedFormData,
- useHookFormPersist,
- isPhysiologyAnatomyDropDownOpen,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- setValue,
- control,
- getValues,
- formState: { isValid, errors },
- } = useForm({
- mode: 'onChange',
- defaultValues: { ...persistedFormData },
- });
- const { historyCancel } = useHookFormPersist(getValues);
- const allCropGroupAverages = useSelector(cropGroupAveragesSelector);
-
- const cropGroupOptions = [
- { value: BEVERAGE_AND_SPICE_CROPS, label: t('crop_group:BEVERAGE_AND_SPICE_CROPS') },
- { value: CEREALS, label: t('crop_group:CEREALS') },
- { value: FRUITS_AND_NUTS, label: t('crop_group:FRUITS_AND_NUTS') },
- { value: LEGUMINOUS_CROPS, label: t('crop_group:LEGUMINOUS_CROPS') },
- { value: OILSEED_CROPS, label: t('crop_group:OILSEED_CROPS') },
- { value: OTHER_CROPS, label: t('crop_group:OTHER_CROPS') },
- { value: POTATOES_AND_YAMS, label: t('crop_group:POTATOES_AND_YAMS') },
- { value: SUGAR_CROPS, label: t('crop_group:SUGAR_CROPS') },
- { value: VEGETABLE_AND_MELONS, label: t('crop_group:VEGETABLE_AND_MELONS') },
- {
- value: STIMULANT_SPICE_AROMATIC_CROPS,
- label: t('crop_group:STIMULANT_SPICE_AROMATIC_CROPS'),
- },
- { value: HIGH_STARCH_ROOT_TUBER_CROP, label: t('crop_group:HIGH_STARCH_ROOT_TUBER_CROP') },
- ];
-
- const progress = 33;
- const disabled = !isValid;
-
- const updatePAValues = (selected) => {
- const cropGroupAverages = allCropGroupAverages[selected.value];
- for (const nutrient of NUTRIENT_ARRAY) {
- setValue(nutrient, cropGroupAverages[nutrient].toFixed(2));
- }
- };
-
- return (
-
- );
-}
-
-PureAddNewCrop.prototype = {
- onClick: PropTypes.func,
- text: PropTypes.string,
- showSpotLight: PropTypes.bool,
-};
-
-function PhysiologyAnatomyDropDown({ register, isPhysiologyAnatomyDropDownOpen }) {
- const { t } = useTranslation();
- const [open, setOpen] = useState(isPhysiologyAnatomyDropDownOpen);
-
- return (
-
-
setOpen(!open)}>
- {t('CROP.PHYSIOLOGY_AND_ANATOMY')}
-
-
-
-
- {FIRST_NUTRIENT_ARRAY.map((nutrient) => {
- return (
-
- );
- })}
-
-
- {t('CROP.NUTRIENTS_IN_EDIBLE_PORTION')}
-
-
- {SECOND_NUTRIENT_ARRAY.map((nutrient) => {
- return (
-
- );
- })}
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/AddNewCrop/index.jsx b/packages/webapp/src/components/AddNewCrop/index.jsx
new file mode 100644
index 0000000000..802ca75cc6
--- /dev/null
+++ b/packages/webapp/src/components/AddNewCrop/index.jsx
@@ -0,0 +1,194 @@
+import Button from '../Form/Button';
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Semibold } from '../Typography';
+import Input, { getInputErrors } from '../Form/Input';
+//import styles from './styles.module.scss';
+import Form from '../Form';
+import { Controller, useForm } from 'react-hook-form';
+import ReactSelect from '../Form/ReactSelect';
+import { BsChevronDown } from 'react-icons/bs';
+import {
+ BEVERAGE_AND_SPICE_CROPS,
+ CEREALS,
+ FIRST_NUTRIENT_ARRAY,
+ FRUITS_AND_NUTS,
+ HIGH_STARCH_ROOT_TUBER_CROP,
+ LEGUMINOUS_CROPS,
+ NUTRIENT_ARRAY,
+ NUTRIENT_DICT,
+ OILSEED_CROPS,
+ OTHER_CROPS,
+ POTATOES_AND_YAMS,
+ SECOND_NUTRIENT_ARRAY,
+ STIMULANT_SPICE_AROMATIC_CROPS,
+ SUGAR_CROPS,
+ VEGETABLE_AND_MELONS,
+} from './constants';
+import { cropGroupAverages as cropGroupAveragesSelector } from '../../containers/cropSlice';
+import { useSelector } from 'react-redux';
+import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
+import RadioGroup from '../Form/RadioGroup';
+import styles from './styles.module.scss';
+
+export default function PureAddNewCrop({
+ handleContinue,
+ handleGoBack,
+ handleCancel,
+ persistedFormData,
+ useHookFormPersist,
+ isPhysiologyAnatomyDropDownOpen,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ handleSubmit,
+ setValue,
+ control,
+ getValues,
+ formState: { isValid, errors },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: { ...persistedFormData },
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+ const allCropGroupAverages = useSelector(cropGroupAveragesSelector);
+
+ const cropGroupOptions = [
+ { value: BEVERAGE_AND_SPICE_CROPS, label: t('crop_group:BEVERAGE_AND_SPICE_CROPS') },
+ { value: CEREALS, label: t('crop_group:CEREALS') },
+ { value: FRUITS_AND_NUTS, label: t('crop_group:FRUITS_AND_NUTS') },
+ { value: LEGUMINOUS_CROPS, label: t('crop_group:LEGUMINOUS_CROPS') },
+ { value: OILSEED_CROPS, label: t('crop_group:OILSEED_CROPS') },
+ { value: OTHER_CROPS, label: t('crop_group:OTHER_CROPS') },
+ { value: POTATOES_AND_YAMS, label: t('crop_group:POTATOES_AND_YAMS') },
+ { value: SUGAR_CROPS, label: t('crop_group:SUGAR_CROPS') },
+ { value: VEGETABLE_AND_MELONS, label: t('crop_group:VEGETABLE_AND_MELONS') },
+ {
+ value: STIMULANT_SPICE_AROMATIC_CROPS,
+ label: t('crop_group:STIMULANT_SPICE_AROMATIC_CROPS'),
+ },
+ { value: HIGH_STARCH_ROOT_TUBER_CROP, label: t('crop_group:HIGH_STARCH_ROOT_TUBER_CROP') },
+ ];
+
+ const progress = 33;
+ const disabled = !isValid;
+
+ const updatePAValues = (selected) => {
+ const cropGroupAverages = allCropGroupAverages[selected.value];
+ for (const nutrient of NUTRIENT_ARRAY) {
+ setValue(nutrient, cropGroupAverages[nutrient].toFixed(2));
+ }
+ };
+
+ return (
+
+ );
+}
+
+PureAddNewCrop.prototype = {
+ onClick: PropTypes.func,
+ text: PropTypes.string,
+ showSpotLight: PropTypes.bool,
+};
+
+function PhysiologyAnatomyDropDown({ register, isPhysiologyAnatomyDropDownOpen }) {
+ const { t } = useTranslation();
+ const [open, setOpen] = useState(isPhysiologyAnatomyDropDownOpen);
+
+ return (
+
+
setOpen(!open)}>
+ {t('CROP.PHYSIOLOGY_AND_ANATOMY')}
+
+
+
+
+ {FIRST_NUTRIENT_ARRAY.map((nutrient) => {
+ return (
+
+ );
+ })}
+
+
+ {t('CROP.NUTRIENTS_IN_EDIBLE_PORTION')}
+
+
+ {SECOND_NUTRIENT_ARRAY.map((nutrient) => {
+ return (
+
+ );
+ })}
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/ButtonGroup/SubmitButton.js b/packages/webapp/src/components/ButtonGroup/SubmitButton.jsx
similarity index 100%
rename from packages/webapp/src/components/ButtonGroup/SubmitButton.js
rename to packages/webapp/src/components/ButtonGroup/SubmitButton.jsx
diff --git a/packages/webapp/src/components/Card/NewReleaseCard/NewReleaseCard.js b/packages/webapp/src/components/Card/NewReleaseCard/NewReleaseCard.jsx
similarity index 100%
rename from packages/webapp/src/components/Card/NewReleaseCard/NewReleaseCard.js
rename to packages/webapp/src/components/Card/NewReleaseCard/NewReleaseCard.jsx
diff --git a/packages/webapp/src/components/Card/NotificationCard/NotificationCard.jsx b/packages/webapp/src/components/Card/NotificationCard/NotificationCard.jsx
new file mode 100644
index 0000000000..b2db2a92ae
--- /dev/null
+++ b/packages/webapp/src/components/Card/NotificationCard/NotificationCard.jsx
@@ -0,0 +1,141 @@
+import Card from '../index';
+import { Semibold, Text } from '../../Typography';
+import styles from '../card.module.scss';
+import { useTranslation } from 'react-i18next';
+import clsx from 'clsx';
+import { colors } from '../../../assets/theme';
+import { ReactComponent as AlertIcon } from '../../../assets/images/alert.svg';
+import getTaskTypeIcon from '../../util/getTaskTypeIcon';
+import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
+
+/**
+ * Renders a card containing notification data.
+ * @param {NotificationCardConfig} param0
+ * @returns {ReactComponent}
+ */
+export function PureNotificationCard({
+ alert,
+ status,
+ title,
+ body,
+ variables,
+ context,
+ created_at,
+ onClick,
+}) {
+ const { t } = useTranslation();
+ const currentLang = getLanguageFromLocalStorage();
+ // Construct translation options from interpolation variables, translating them as needed.
+ const tOptions = variables.reduce((optionsSoFar, currentOption) => {
+ let options = { ...optionsSoFar };
+ options[currentOption.name] = currentOption.translate
+ ? t(currentOption.value)
+ : currentOption.value;
+ return options;
+ }, {});
+
+ let Icon;
+ // The "context" can indicate that a particular type of task icon is appropriate.
+ if (context?.task_translation_key) Icon = getTaskTypeIcon(context.task_translation_key);
+
+ return (
+
+
+
+ {created_at}
+
+
+ {Icon && (
+
+ )}
+
+
+
+
+ {title.translation_key ? t(title.translation_key) : title[currentLang]}
+ {alert && }
+
+
+ {body.translation_key ? t(body.translation_key, tOptions) : body[currentLang]}
+
+
+
+ );
+}
+
+/**
+ * @typedef NotificationCardConfig
+ * @desc Configures the presentation of a notification card.
+ * @type {object}
+ * @property {boolean} alert - Indicates if the card should display an alert indication.
+ * @property {userNotificationStatusType} status - The notification's status.
+ * @property {string} translation_key - The translation key for the notification, which must contain subkeys for the title and body.
+ * @property {InterpolationVariable[]} variables - An array of translation interpolation variables.
+ * @property {string} entity_type - The type of entity that the notification refers to, e.g., 'task'.
+ * @property {string} entity_id - A unique identifier for the specific entity_type instance that the notification refers to.
+ * @property {object} context - A dictionary of context-specific data for the notification.
+ * @property {string} created_at - The creation time of the notification.
+ */
+
+/**
+ * @typedef InterpolationVariable
+ * @desc Describes a variable to be interpolated into the translation of a notification's body.
+ * @type {object}
+ * @property {string} name - A name for the variable.
+ * @property {string} value - The variable's value.
+ * @property {boolean} translate - Indicates if the value is a key to be translated.
+ */
diff --git a/packages/webapp/src/components/Card/card.module.scss b/packages/webapp/src/components/Card/card.module.scss
index 8595a6ebed..5fcc86cad5 100644
--- a/packages/webapp/src/components/Card/card.module.scss
+++ b/packages/webapp/src/components/Card/card.module.scss
@@ -88,3 +88,12 @@
color: var(--teal900);
box-shadow: 0px 2px 4px rgba(102, 115, 138, 0.3);
}
+
+// notification styles
+.notificationUnread {
+ background-color: var(--white);
+}
+
+.notificationRead {
+ background-color: var(--grey200);
+}
diff --git a/packages/webapp/src/components/Card/index.js b/packages/webapp/src/components/Card/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Card/index.js
rename to packages/webapp/src/components/Card/index.jsx
diff --git a/packages/webapp/src/components/CardWithStatus/CardWithStatusContainer/CardWithStatusContainer.js b/packages/webapp/src/components/CardWithStatus/CardWithStatusContainer/CardWithStatusContainer.jsx
similarity index 100%
rename from packages/webapp/src/components/CardWithStatus/CardWithStatusContainer/CardWithStatusContainer.js
rename to packages/webapp/src/components/CardWithStatus/CardWithStatusContainer/CardWithStatusContainer.jsx
diff --git a/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.js b/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.js
deleted file mode 100644
index 80e129bc7d..0000000000
--- a/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { CardWithStatus } from '../index';
-import styles from './styles.module.scss';
-import { ReactComponent as CalendarIcon } from '../../../assets/images/task/Calendar.svg';
-import clsx from 'clsx';
-import React from 'react';
-import { getManagementPlanCardDate } from '../../../util/moment';
-import { useTranslation } from 'react-i18next';
-import PropTypes from 'prop-types';
-import i18n from '../../../locales/i18n';
-
-const statusColorMap = {
- active: 'secondary',
- planned: 'secondary',
- completed: 'completed',
- abandoned: 'completed',
-};
-
-export const managementPlanStatusTranslateKey = {
- active: 'ACTIVE',
- planned: 'PLANNED',
- completed: 'COMPLETED',
- abandoned: 'ABANDONED',
-};
-
-export function ManagementPlanCard({
- managementPlanName,
- locationName,
- notes,
- startDate,
- endDate,
- numberOfPendingTask,
- style,
- status,
- classes = { card: {} },
- onClick,
- score,
-}) {
- const { t } = useTranslation();
-
- return (
-
-
-
{managementPlanName}
-
- {locationName} {notes ? ` | ${notes}` : ''}
-
-
- {startDate && (
- <>
-
-
-
- {getManagementPlanCardDate(startDate)}
- {endDate && ` - ${getManagementPlanCardDate(endDate)}`}
-
-
-
- >
- )}
- {
-
-
-
{numberOfPendingTask <= 99 ? numberOfPendingTask : '+99'}
-
-
{t('MANAGEMENT_PLAN.PENDING_TASK')}
-
- }
-
-
-
- );
-}
-
-ManagementPlanCard.propTypes = {
- style: PropTypes.object,
- status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
- classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
- onClick: PropTypes.func,
- score: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
- managementPlanName: PropTypes.string,
- locationName: PropTypes.string,
- notes: PropTypes.string,
- startDate: PropTypes.any,
- endDate: PropTypes.any,
- numberOfPendingTask: PropTypes.number,
- management_plan_id: PropTypes.number,
-};
diff --git a/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.jsx b/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.jsx
new file mode 100644
index 0000000000..3bd66defcb
--- /dev/null
+++ b/packages/webapp/src/components/CardWithStatus/ManagementPlanCard/ManagementPlanCard.jsx
@@ -0,0 +1,94 @@
+import { CardWithStatus } from '../index';
+import styles from './styles.module.scss';
+import { ReactComponent as CalendarIcon } from '../../../assets/images/task/Calendar.svg';
+import clsx from 'clsx';
+import React from 'react';
+import { getManagementPlanCardDate } from '../../../util/moment';
+import { useTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+
+const statusColorMap = {
+ active: 'secondary',
+ planned: 'secondary',
+ completed: 'completed',
+ abandoned: 'completed',
+};
+
+export const managementPlanStatusTranslateKey = {
+ active: 'ACTIVE',
+ planned: 'PLANNED',
+ completed: 'COMPLETED',
+ abandoned: 'ABANDONED',
+};
+
+export function ManagementPlanCard({
+ managementPlanName,
+ locationName,
+ notes,
+ startDate,
+ endDate,
+ numberOfPendingTask,
+ style,
+ status,
+ classes = { card: {} },
+ onClick,
+ score,
+}) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
{managementPlanName}
+
+ {locationName} {notes ? ` | ${notes}` : ''}
+
+
+ {startDate && (
+ <>
+
+
+
+ {getManagementPlanCardDate(startDate)}
+ {endDate && ` - ${getManagementPlanCardDate(endDate)}`}
+
+
+
+ >
+ )}
+ {
+
+
+
{numberOfPendingTask <= 99 ? numberOfPendingTask : '+99'}
+
+
{t('MANAGEMENT_PLAN.PENDING_TASK')}
+
+ }
+
+
+
+ );
+}
+
+ManagementPlanCard.propTypes = {
+ style: PropTypes.object,
+ status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
+ classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
+ onClick: PropTypes.func,
+ score: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
+ managementPlanName: PropTypes.string,
+ locationName: PropTypes.string,
+ notes: PropTypes.string,
+ startDate: PropTypes.any,
+ endDate: PropTypes.any,
+ numberOfPendingTask: PropTypes.number,
+ management_plan_id: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/CardWithStatus/StatusLabel/index.js b/packages/webapp/src/components/CardWithStatus/StatusLabel/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CardWithStatus/StatusLabel/index.js
rename to packages/webapp/src/components/CardWithStatus/StatusLabel/index.jsx
diff --git a/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.js b/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.js
deleted file mode 100644
index be4fd14280..0000000000
--- a/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { ReactComponent as CalendarIcon } from '../../../assets/images/task/Calendar.svg';
-import { ReactComponent as UnassignedIcon } from '../../../assets/images/task/Unassigned.svg';
-import { ReactComponent as CustomIcon } from '../../../assets/images/task/Custom.svg';
-import { ReactComponent as RecordSoilSample } from '../../../assets/images/task/RecordSoilSample.svg';
-import { ReactComponent as Sales } from '../../../assets/images/task/Sales.svg';
-import { ReactComponent as Scout } from '../../../assets/images/task/Scout.svg';
-import { ReactComponent as WashAndPack } from '../../../assets/images/task/WashAndPack.svg';
-import { ReactComponent as Transplant } from '../../../assets/images/task/Transplant.svg';
-import { ReactComponent as Harvest } from '../../../assets/images/task/Harvest.svg';
-import { ReactComponent as PestControl } from '../../../assets/images/task/PestControl.svg';
-import { ReactComponent as Irrigate } from '../../../assets/images/task/Irrigate.svg';
-import { ReactComponent as Transport } from '../../../assets/images/task/Transport.svg';
-import { ReactComponent as FieldWork } from '../../../assets/images/task/FieldWork.svg';
-import { ReactComponent as Plant } from '../../../assets/images/task/Plant.svg';
-import { ReactComponent as SocialEvent } from '../../../assets/images/task/SocialEvent.svg';
-import { ReactComponent as Clean } from '../../../assets/images/task/Clean.svg';
-import { ReactComponent as SoilAmendment } from '../../../assets/images/task/SoilAmendment.svg';
-import styles from './styles.module.scss';
-
-import { useTranslation } from 'react-i18next';
-import { CardWithStatus } from '../index';
-import i18n from '../../../locales/i18n';
-import clsx from 'clsx';
-
-const statusColorMap = {
- planned: 'secondary',
- late: 'secondary',
- completed: 'completed',
- abandoned: 'completed',
-};
-
-const activeCardColorMap = {
- planned: 'taskCurrentActive',
- late: 'taskCurrentActive',
- completed: 'taskMarkedActive',
- abandoned: 'taskMarkedActive',
-};
-
-export const taskStatusTranslateKey = {
- forReview: 'FOR_REVIEW',
- planned: 'PLANNED',
- completed: 'COMPLETED',
- late: 'LATE',
- abandoned: 'ABANDONED',
-};
-
-const iconDict = {
- CLEANING_TASK: Clean, // for release
- HARVEST_TASK: Harvest, // for release
- PEST_CONTROL_TASK: PestControl, // for release
- PLANT_TASK: Plant, // for release
- FIELD_WORK_TASK: FieldWork, // for release
- TRANSPLANT_TASK: Transplant, // for release
- SOIL_AMENDMENT_TASK: SoilAmendment, // for release
- BED_PREPARATION_TASK: CustomIcon,
- SALE_TASK: Sales,
- FERTILIZING: SoilAmendment, // soil amendment replaces fertilizing
- SCOUTING_TASK: Scout,
- WASH_AND_PACK_TASK: WashAndPack,
- OTHER_TASK: CustomIcon,
- BREAK_TASK: CustomIcon,
- SOIL_TASK: RecordSoilSample,
- IRRIGATION_TASK: Irrigate,
- TRANSPORT_TASK: Transport,
- SOCIAL_TASK: SocialEvent,
-};
-
-export const PureTaskCard = ({
- taskType,
- status,
- locationName,
- cropVarietyName,
- completeOrDueDate,
- assignee = null,
- style,
- onClick = null,
- onClickAssignee = null,
- selected,
- happiness,
- classes = { card: {} },
- ...props
-}) => {
- const { t } = useTranslation();
- const isCustomType = !!taskType.farm_id;
- const TaskIcon = isCustomType ? CustomIcon : iconDict[taskType.task_translation_key];
- const onAssignTask = (e) => {
- e.stopPropagation();
- onClickAssignee?.();
- };
- return (
-
-
-
-
- {t(`task:${taskType.task_translation_key}`)}
-
-
- {locationName || t('TASK.CARD.MULTIPLE_LOCATIONS')}
- {cropVarietyName && ` | ${cropVarietyName}`}
-
-
-
-
-
{completeOrDueDate}
-
- {assignee ? (
-
-
- {assignee.first_name.toUpperCase().charAt(0)}
-
-
{`${assignee.first_name} ${assignee.last_name.charAt(0)}.`}
-
- ) : (
-
-
-
{t('TASK.UNASSIGNED')}
-
- )}
-
-
-
- );
-};
-
-PureTaskCard.propTypes = {
- style: PropTypes.object,
- status: PropTypes.oneOf(['late', 'planned', 'completed', 'abandoned', 'forReview']),
- classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
- onClick: PropTypes.func,
- happiness: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
- locationName: PropTypes.string,
- taskType: PropTypes.object,
- cropVarietyName: PropTypes.string,
- completeOrDueDate: PropTypes.string,
- assignee: PropTypes.object,
- onClickAssignee: PropTypes.func,
- selected: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.jsx b/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.jsx
new file mode 100644
index 0000000000..89b87a0c28
--- /dev/null
+++ b/packages/webapp/src/components/CardWithStatus/TaskCard/TaskCard.jsx
@@ -0,0 +1,157 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { ReactComponent as CalendarIcon } from '../../../assets/images/task/Calendar.svg';
+import { ReactComponent as UnassignedIcon } from '../../../assets/images/task/Unassigned.svg';
+import styles from './styles.module.scss';
+
+import getTaskTypeIcon from '../../util/getTaskTypeIcon';
+
+import { useTranslation } from 'react-i18next';
+import { CardWithStatus } from '../index';
+import clsx from 'clsx';
+
+const statusColorMap = {
+ planned: 'secondary',
+ late: 'secondary',
+ completed: 'completed',
+ abandoned: 'completed',
+};
+
+const activeCardColorMap = {
+ planned: 'taskCurrentActive',
+ late: 'taskCurrentActive',
+ completed: 'taskMarkedActive',
+ abandoned: 'taskMarkedActive',
+};
+
+export const taskStatusTranslateKey = {
+ forReview: 'FOR_REVIEW',
+ planned: 'PLANNED',
+ completed: 'COMPLETED',
+ late: 'LATE',
+ abandoned: 'ABANDONED',
+};
+
+export const PureTaskCard = ({
+ taskType,
+ status,
+ locationName,
+ cropVarietyName,
+ completeOrDueDate,
+ assignee = null,
+ style,
+ onClick = null,
+ onClickAssignee = null,
+ onClickCompleteOrDueDate = null,
+ selected,
+ happiness,
+ classes = { card: {} },
+ isAdmin,
+ isAssignee,
+ ...props
+}) => {
+ const { t } = useTranslation();
+ const isCustomType = !!taskType.farm_id;
+ const TaskIcon = getTaskTypeIcon(isCustomType ? 'CUSTOM_TASK' : taskType.task_translation_key);
+ const onAssignTask = (e) => {
+ e.stopPropagation();
+ onClickAssignee?.();
+ };
+ const onAssignDate = (e) => {
+ e.stopPropagation();
+ onClickCompleteOrDueDate?.();
+ };
+
+ let trueDate = completeOrDueDate;
+ if (status == 'abandoned') {
+ let [day, month, date, year] = new Date(props['abandonDate']).toDateString().split(' ');
+ trueDate = `${month} ${date}, ${year}`;
+ }
+
+ return (
+
+
+
+
+ {t(`task:${taskType.task_translation_key}`)}
+
+
+ {locationName || t('TASK.CARD.MULTIPLE_LOCATIONS')}
+ {cropVarietyName && ` | ${cropVarietyName}`}
+
+
+
+ {assignee ? (
+
+
+ {assignee.first_name.toUpperCase().charAt(0)}
+
+
{`${assignee.first_name} ${assignee.last_name.charAt(0)}.`}
+
+ ) : (
+
+
+
{t('TASK.UNASSIGNED')}
+
+ )}
+
+
+
+ );
+};
+
+PureTaskCard.propTypes = {
+ style: PropTypes.object,
+ status: PropTypes.oneOf(['late', 'planned', 'completed', 'abandoned', 'forReview']),
+ classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
+ onClick: PropTypes.func,
+ happiness: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
+ locationName: PropTypes.string,
+ taskType: PropTypes.object,
+ cropVarietyName: PropTypes.string,
+ completeOrDueDate: PropTypes.string,
+ assignee: PropTypes.object,
+ onClickAssignee: PropTypes.func,
+ onClickCompleteOrDueDate: PropTypes.func,
+ selected: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/CardWithStatus/TaskCard/styles.module.scss b/packages/webapp/src/components/CardWithStatus/TaskCard/styles.module.scss
index 853381279b..3fb484037c 100644
--- a/packages/webapp/src/components/CardWithStatus/TaskCard/styles.module.scss
+++ b/packages/webapp/src/components/CardWithStatus/TaskCard/styles.module.scss
@@ -53,6 +53,13 @@
border-bottom: 1px solid var(--teal700);
}
+.iconTextContainerNoUnderline {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 3px;
+}
+
.statusLabel {
display: flex;
right: 0;
diff --git a/packages/webapp/src/components/CardWithStatus/index.js b/packages/webapp/src/components/CardWithStatus/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CardWithStatus/index.js
rename to packages/webapp/src/components/CardWithStatus/index.jsx
diff --git a/packages/webapp/src/components/CertificationReportingPeriod/index.js b/packages/webapp/src/components/CertificationReportingPeriod/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CertificationReportingPeriod/index.js
rename to packages/webapp/src/components/CertificationReportingPeriod/index.jsx
diff --git a/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierNoQuestions/index.js b/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierNoQuestions/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CertificationSurvey/RegisteredCertifierNoQuestions/index.js
rename to packages/webapp/src/components/CertificationSurvey/RegisteredCertifierNoQuestions/index.jsx
diff --git a/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.js b/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.js
deleted file mode 100644
index dee3ca4637..0000000000
--- a/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import React from 'react';
-import styles from '../styles.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Info, Main, Semibold } from '../../Typography';
-import { colors } from '../../../assets/theme';
-import { ReactComponent as PostSurveySplash } from '../../../assets/images/certification/CompleteSurveySplash.svg';
-
-const RegisteredCertifierQuestionsSurvey = ({ certiferAcronym, surveyId, submissionId, email }) => {
- const { t } = useTranslation();
-
- return (
- <>
-
- {`${t('CERTIFICATIONS.ORGANIC_CERTIFICATION_FROM')} ${certiferAcronym}`}
-
-
-
- {t('CERTIFICATIONS.WOULD_LIKE_ANSWERS')}
-
-
- {t('CERTIFICATIONS.NOTE_CANNOT_RESUBMIT')}
-
- {submissionId ? : }
- >
- );
-};
-
-const PreSurveyBody = ({ surveyId }) => {
- return (
-
- );
-};
-
-const PostSurveyBody = ({ email }) => {
- const { t } = useTranslation();
-
- return (
-
-
-
- {t('CERTIFICATIONS.FILES_ARE_READY')}
-
-
-
{email}
-
- );
-};
-
-RegisteredCertifierQuestionsSurvey.propTypes = {
- certiferAcronym: PropTypes.string,
-};
-
-export default RegisteredCertifierQuestionsSurvey;
diff --git a/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.jsx b/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.jsx
new file mode 100644
index 0000000000..e0df0f8841
--- /dev/null
+++ b/packages/webapp/src/components/CertificationSurvey/RegisteredCertifierQuestions/index.jsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import styles from '../styles.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Info, Main, Semibold } from '../../Typography';
+import { colors } from '../../../assets/theme';
+import { ReactComponent as PostSurveySplash } from '../../../assets/images/certification/CompleteSurveySplash.svg';
+
+const RegisteredCertifierQuestionsSurvey = ({
+ certiferAcronym,
+ surveyId,
+ submissionId,
+ isSurveySkipped,
+ email,
+}) => {
+ const { t } = useTranslation();
+
+ return (
+ <>
+
+ {`${t('CERTIFICATIONS.ORGANIC_CERTIFICATION_FROM')} ${certiferAcronym}`}
+
+
+
+ {t('CERTIFICATIONS.WOULD_LIKE_ANSWERS')}
+
+
+ {t('CERTIFICATIONS.NOTE_CANNOT_RESUBMIT')}
+
+ {submissionId || isSurveySkipped ? (
+
+ ) : (
+
+ )}
+ >
+ );
+};
+
+const PreSurveyBody = ({ surveyId }) => {
+ return (
+
+ );
+};
+
+const PostSurveyBody = ({ email }) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {t('CERTIFICATIONS.FILES_ARE_READY')}
+
+
+
{email}
+
+ );
+};
+
+RegisteredCertifierQuestionsSurvey.propTypes = {
+ certiferAcronym: PropTypes.string,
+};
+
+export default RegisteredCertifierQuestionsSurvey;
diff --git a/packages/webapp/src/components/CertificationSurvey/UnregisteredCertifier/index.js b/packages/webapp/src/components/CertificationSurvey/UnregisteredCertifier/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CertificationSurvey/UnregisteredCertifier/index.js
rename to packages/webapp/src/components/CertificationSurvey/UnregisteredCertifier/index.jsx
diff --git a/packages/webapp/src/components/CertificationSurvey/index.js b/packages/webapp/src/components/CertificationSurvey/index.js
deleted file mode 100644
index 367881247c..0000000000
--- a/packages/webapp/src/components/CertificationSurvey/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import Button from '../Form/Button';
-import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
-import { useTranslation } from 'react-i18next';
-import Layout from '../Layout';
-import RegisteredCertifierQuestionsSurvey from './RegisteredCertifierQuestions';
-import RegisteredCertifierNoQuestionsSurvey from './RegisteredCertifierNoQuestions';
-import UnregisteredCertifierSurvey from './UnregisteredCertifier';
-
-const PureCertificationSurveyPage = ({
- onExport,
- handleGoBack,
- handleCancel,
- certifier,
- requested_certifier,
- persistedFormData,
- useHookFormPersist,
- onSurveyComplete,
- email,
-}) => {
- const { t } = useTranslation();
- const [submissionId, setSubmissionId] = useState(persistedFormData?.submission_id);
-
- const persistedPath = ['/certification/report_period'];
- useHookFormPersist(() => ({}), persistedPath);
-
- const progress = 67;
-
- useEffect(() => {
- const handler = (event) => {
- // if (typeof event.data !== 'string') return; // TODO: figure out better way to filter iframe message. maybe source?
- // const data = JSON.parse(event.data);
- const { type, payload } = event.data;
- if (type === 'SUBMISSION_RESULT_SUCCESS_CLOSE') {
- setSubmissionId(payload.submissionId);
- onSurveyComplete(payload.submissionId);
- }
- };
-
- window.addEventListener('message', handler);
-
- // clean up
- return () => window.removeEventListener('message', handler);
- }, []);
-
- const { certifier_acronym, survey_id } = certifier ?? {};
-
- return (
- <>
-
- onExport({
- ...persistedFormData,
- submission_id: submissionId,
- })
- }
- disabled={survey_id && !submissionId}
- >
- {t('CERTIFICATIONS.EXPORT')}
-
- }
- >
-
-
-
-
- >
- );
-};
-
-const SurveyBody = ({ requested_certifier, certifier_acronym, surveyId, submissionId, email }) => {
- if (requested_certifier) {
- return ;
- } else {
- if (surveyId) {
- // TODO: this is hard coded for the purpose of proof-of-concept
- return (
-
- );
- } else {
- return ;
- }
- }
-};
-
-PureCertificationSurveyPage.propTypes = {
- onExport: PropTypes.func,
- handleGoBack: PropTypes.func,
- handleCancel: PropTypes.func,
-};
-
-export default PureCertificationSurveyPage;
diff --git a/packages/webapp/src/components/CertificationSurvey/index.jsx b/packages/webapp/src/components/CertificationSurvey/index.jsx
new file mode 100644
index 0000000000..64c7a7f3fe
--- /dev/null
+++ b/packages/webapp/src/components/CertificationSurvey/index.jsx
@@ -0,0 +1,122 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import Button from '../Form/Button';
+import MultiStepPageTitle from '../PageTitle/MultiStepPageTitle';
+import { useTranslation } from 'react-i18next';
+import Layout from '../Layout';
+import RegisteredCertifierQuestionsSurvey from './RegisteredCertifierQuestions';
+import RegisteredCertifierNoQuestionsSurvey from './RegisteredCertifierNoQuestions';
+import UnregisteredCertifierSurvey from './UnregisteredCertifier';
+
+const PureCertificationSurveyPage = ({
+ onExport,
+ handleGoBack,
+ handleCancel,
+ certifier,
+ requested_certifier,
+ persistedFormData,
+ useHookFormPersist,
+ onSurveyComplete,
+ email,
+}) => {
+ const { t } = useTranslation();
+ const [submissionId, setSubmissionId] = useState(persistedFormData?.submission_id);
+
+ const persistedPath = ['/certification/report_period'];
+ useHookFormPersist(() => ({}), persistedPath);
+
+ const progress = 67;
+
+ useEffect(() => {
+ const handler = (event) => {
+ // if (typeof event.data !== 'string') return; // TODO: figure out better way to filter iframe message. maybe source?
+ // const data = JSON.parse(event.data);
+ const { type, payload } = event.data;
+ if (type === 'SUBMISSION_RESULT_SUCCESS_CLOSE') {
+ setSubmissionId(payload.submissionId);
+ onSurveyComplete(payload.submissionId);
+ }
+ };
+
+ window.addEventListener('message', handler);
+
+ // clean up
+ return () => window.removeEventListener('message', handler);
+ }, []);
+
+ const { certifier_acronym, survey_id } = certifier ?? {};
+ const [isSurveySkipped, setSurveySkipped] = useState(false);
+
+ return (
+ <>
+
+ {survey_id && !isSurveySkipped &&
+ setSurveySkipped(true)}>{t('common:SKIP')} }
+
+ onExport({
+ ...persistedFormData,
+ submission_id: submissionId,
+ })
+ }
+ disabled={survey_id && !submissionId && !isSurveySkipped}
+ >
+ {t('CERTIFICATIONS.EXPORT')}
+
+ >
+ }
+ >
+
+
+
+
+ >
+ );
+};
+
+const SurveyBody = ({ requested_certifier, certifier_acronym, surveyId, submissionId, email, isSurveySkipped }) => {
+ if (requested_certifier) {
+ return ;
+ } else {
+ if (surveyId) {
+ // TODO: this is hard coded for the purpose of proof-of-concept
+ return (
+
+ );
+ } else {
+ return ;
+ }
+ }
+};
+
+PureCertificationSurveyPage.propTypes = {
+ onExport: PropTypes.func,
+ handleGoBack: PropTypes.func,
+ handleCancel: PropTypes.func,
+};
+
+export default PureCertificationSurveyPage;
diff --git a/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/chooseFarmMenuItem.module.scss b/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/chooseFarmMenuItem.module.scss
index 42373d9b52..a3a0d9cd6f 100644
--- a/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/chooseFarmMenuItem.module.scss
+++ b/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/chooseFarmMenuItem.module.scss
@@ -1,16 +1,20 @@
@import '../../../../assets/mixin';
.leftColumn {
margin-left: 18px;
+ margin-right: 12px;
margin-bottom: 3px;
+ overflow: hidden;
+ word-break: break-word;
display: flex;
flex-direction: column;
justify-content: center;
+ flex: 1.3;
}
.rightColumn {
display: flex;
flex-direction: row;
justify-content: center;
- width: 42.3%;
+ flex: 1;
}
.farmName {
color: var(--fontColor);
diff --git a/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.js b/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.js
deleted file mode 100644
index 0e6d280a6f..0000000000
--- a/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import styles from './chooseFarmMenuItem.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import Card from '../../../Card';
-import { ReactComponent as EmailIcon } from '../../../../assets/images/chooseFarm/emailIcon.svg';
-
-const ChooseFarmMenuItem = ({
- color = 'secondary',
- ownerName,
- farmName = 'Farm name',
- address,
- style,
- onClick,
- ...props
-}) => {
- const isInvited = color === 'blue' || color === 'blueActive';
- return (
-
-
-
{farmName}
- {ownerName &&
{ownerName}
}
-
-
-
- {address?.map((row, index) => (
-
- {row}
-
- ))}
-
- {isInvited && (
-
- {' '}
-
-
- )}
-
-
- );
-};
-
-ChooseFarmMenuItem.propTypes = {
- color: PropTypes.oneOf(['secondary', 'active', 'disabled', 'blue', 'blueActive']),
- onClick: PropTypes.func,
- ownerName: PropTypes.string,
- farmName: PropTypes.string,
- address: PropTypes.arrayOf(PropTypes.string),
- style: PropTypes.object,
-};
-
-export default ChooseFarmMenuItem;
diff --git a/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.jsx b/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.jsx
new file mode 100644
index 0000000000..7fabcb0763
--- /dev/null
+++ b/packages/webapp/src/components/ChooseFarm/ChooseFarmMenu/ChooseFarmMenuItem/index.jsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import styles from './chooseFarmMenuItem.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import Card from '../../../Card';
+import { ReactComponent as EmailIcon } from '../../../../assets/images/chooseFarm/emailIcon.svg';
+
+const ChooseFarmMenuItem = ({
+ color = 'secondary',
+ ownerName,
+ farmName = 'Farm name',
+ address,
+ style,
+ onClick,
+ ...props
+}) => {
+ const isInvited = color === 'blue' || color === 'blueActive';
+ return (
+
+
+
+ {farmName.length > 77 ? `${farmName.substring(0, 77).trim()}...` : farmName}
+
+ {ownerName &&
{ownerName}
}
+
+
+
+ {address?.map((row, index) => (
+
+ {row}
+
+ ))}
+
+ {isInvited && (
+
+ {' '}
+
+
+ )}
+
+
+ );
+};
+
+ChooseFarmMenuItem.propTypes = {
+ color: PropTypes.oneOf(['secondary', 'active', 'disabled', 'blue', 'blueActive']),
+ onClick: PropTypes.func,
+ ownerName: PropTypes.string,
+ farmName: PropTypes.string,
+ address: PropTypes.arrayOf(PropTypes.string),
+ style: PropTypes.object,
+};
+
+export default ChooseFarmMenuItem;
diff --git a/packages/webapp/src/components/ChooseFarm/index.js b/packages/webapp/src/components/ChooseFarm/index.js
deleted file mode 100644
index 1579977b04..0000000000
--- a/packages/webapp/src/components/ChooseFarm/index.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import Layout from '../Layout';
-import Button from '../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { Title, Underlined } from '../Typography';
-import ChooseFarmMenuItem from './ChooseFarmMenu/ChooseFarmMenuItem';
-import Input from '../Form/Input';
-import { useTranslation } from 'react-i18next';
-
-export default function PureChooseFarmScreen({
- farms = [],
- onGoBack,
- onProceed,
- onSelectFarm,
- onCreateFarm,
- isOnBoarding,
- onFilterChange,
- isSearchable,
- disabled,
- title = 'Choose your farm',
-}) {
- const { t } = useTranslation(['translation', 'common']);
-
- return (
-
- {!isOnBoarding && (
-
- {t('common:BACK')}
-
- )}
-
- {t('common:PROCEED')}
-
- >
- }
- >
- {title}
-
- + {t('CHOOSE_FARM.ADD_NEW')}
-
- {isSearchable && (
-
- )}
- {farms.map((farm) => {
- return (
- onSelectFarm(farm.farm_id)}
- ownerName={farm.ownerName}
- key={farm.farm_id}
- />
- );
- })}
-
- );
-}
-
-PureChooseFarmScreen.prototype = {
- farms: PropTypes.arrayOf(
- PropTypes.exact({
- farmName: PropTypes.string,
- address: PropTypes.arrayOf(PropTypes.string),
- farm_id: PropTypes.string,
- coordinate: PropTypes.exact({
- lon: PropTypes.number,
- lat: PropTypes.number,
- }),
- ownerName: PropTypes.string,
- }),
- ),
- onGoBack: PropTypes.func,
- onProceed: PropTypes.func,
- onSelectFarm: PropTypes.func,
- onCreateFarm: PropTypes.func,
- isOnBoarding: PropTypes.bool,
- isSearchable: PropTypes.bool,
- onFilterChange: PropTypes.func,
- disabled: PropTypes.bool,
- title: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/ChooseFarm/index.jsx b/packages/webapp/src/components/ChooseFarm/index.jsx
new file mode 100644
index 0000000000..cb1940e324
--- /dev/null
+++ b/packages/webapp/src/components/ChooseFarm/index.jsx
@@ -0,0 +1,103 @@
+import Layout from '../Layout';
+import Button from '../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Title, Underlined } from '../Typography';
+import ChooseFarmMenuItem from './ChooseFarmMenu/ChooseFarmMenuItem';
+import Input from '../Form/Input';
+import { useTranslation } from 'react-i18next';
+
+export default function PureChooseFarmScreen({
+ farms = [],
+ onGoBack,
+ onProceed,
+ onSelectFarm,
+ onCreateFarm,
+ isOnBoarding,
+ onFilterChange,
+ isSearchable,
+ disabled,
+ title = 'Choose your farm',
+}) {
+ const { t } = useTranslation(['translation', 'common']);
+
+ return (
+
+ {!isOnBoarding && (
+
+ {t('common:BACK')}
+
+ )}
+
+ {t('common:PROCEED')}
+
+ >
+ }
+ >
+ {title}
+
+ + {t('CHOOSE_FARM.ADD_NEW')}
+
+ {isSearchable && (
+
+ )}
+ {farms.map((farm) => {
+ return (
+ onSelectFarm(farm.farm_id)}
+ ownerName={farm.ownerName}
+ key={farm.farm_id}
+ />
+ );
+ })}
+
+ );
+}
+
+PureChooseFarmScreen.prototype = {
+ farms: PropTypes.arrayOf(
+ PropTypes.exact({
+ farmName: PropTypes.string,
+ address: PropTypes.arrayOf(PropTypes.string),
+ farm_id: PropTypes.string,
+ coordinate: PropTypes.exact({
+ lon: PropTypes.number,
+ lat: PropTypes.number,
+ }),
+ ownerName: PropTypes.string,
+ }),
+ ),
+ onGoBack: PropTypes.func,
+ onProceed: PropTypes.func,
+ onSelectFarm: PropTypes.func,
+ onCreateFarm: PropTypes.func,
+ isOnBoarding: PropTypes.bool,
+ isSearchable: PropTypes.bool,
+ onFilterChange: PropTypes.func,
+ disabled: PropTypes.bool,
+ title: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Consent/consent.module.scss b/packages/webapp/src/components/Consent/consent.module.scss
index c4116a8f49..98a4f78cdf 100644
--- a/packages/webapp/src/components/Consent/consent.module.scss
+++ b/packages/webapp/src/components/Consent/consent.module.scss
@@ -8,6 +8,10 @@
flex-grow: 1;
width: 100%;
overflow-y: scroll;
+ display: flex;
+ row-gap: 20px;
+ flex-direction: column;
+ padding-bottom: 40px;
}
.consentTextContainer li {
diff --git a/packages/webapp/src/components/Consent/consent.test.js b/packages/webapp/src/components/Consent/consent.test.js
deleted file mode 100644
index f458bc2d60..0000000000
--- a/packages/webapp/src/components/Consent/consent.test.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import { render, fireEvent, screen } from '@testing-library/react';
-import PureConsent from './index';
-describe('Consent View', () => {
- beforeAll(() => {
- // To get rid of useless error message until better solution
- // https://github.com/jsdom/jsdom/issues/1937
- const tempErrorFn = console.error;
- console.error = (message, optionalParams) => {
- if (!message.includes('Not implemented')) {
- tempErrorFn(message, optionalParams);
- }
- };
- });
- it('renders correctly with given props', () => {
- const fakeFunc = jest.fn();
- render(
- ,
- );
- expect(screen.queryByText('PureConsentTest')).toBeDefined();
- });
-
- it('calls on submit when continue button is clicked', () => {
- const mockSubmit = jest.fn();
- const mockGoBack = jest.fn();
- render(
- ,
- );
- fireEvent.click(screen.getByText(/continue/i));
- expect(mockSubmit).toHaveBeenCalled();
- });
-
- it('calls on go back when go back button is clicked', () => {
- const mockGoBack = jest.fn();
- const mockSubmit = jest.fn();
- render(
- ,
- );
- fireEvent.click(screen.getByText(/go back/i));
- expect(mockGoBack).toHaveBeenCalled();
- });
-
- it('disables continue button if disabled prop is true', () => {
- const mockSubmit = jest.fn();
- const mockGoBack = jest.fn();
- render(
- ,
- );
- fireEvent.click(screen.getByText(/continue/i));
- expect(mockSubmit).not.toHaveBeenCalled();
- });
-});
diff --git a/packages/webapp/src/components/Consent/index.js b/packages/webapp/src/components/Consent/index.js
deleted file mode 100644
index ae16871166..0000000000
--- a/packages/webapp/src/components/Consent/index.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import clsx from 'clsx';
-import styles from './consent.module.scss';
-import ReactMarkdown from 'react-markdown';
-import Checkbox from '../Form/Checkbox';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../PageTitle/v2';
-
-export default function PureConsent({ onSubmit, checkboxArgs, onGoBack, text, disabled }) {
- const { t } = useTranslation(['translation', 'common']);
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Consent/index.jsx b/packages/webapp/src/components/Consent/index.jsx
new file mode 100644
index 0000000000..a3247ec43e
--- /dev/null
+++ b/packages/webapp/src/components/Consent/index.jsx
@@ -0,0 +1,48 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import clsx from 'clsx';
+import styles from './consent.module.scss';
+import Checkbox from '../Form/Checkbox';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../PageTitle/v2';
+
+export default function PureConsent({ onSubmit, checkboxArgs, onGoBack, consent, disabled }) {
+ const { t } = useTranslation(['translation', 'common']);
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/ConsentFooter/index.js b/packages/webapp/src/components/ConsentFooter/index.js
deleted file mode 100644
index 7773779e83..0000000000
--- a/packages/webapp/src/components/ConsentFooter/index.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React from 'react';
-import styles from './styles.module.scss';
-import ConfirmModal from '../Modals/Confirm';
-
-//TODO to deprecate
-class ConsentFooter extends React.Component {
- constructor(props) {
- super(props);
- this.state = {
- showModal: false,
- };
- }
-
- render() {
- const { enableAgree, hasConsent, updateConsent } = this.props;
- const setShowModal = (showModal = true) => this.setState({ showModal: showModal });
- return hasConsent ? (
-
- ) : (
-
- );
- }
-}
-
-function GiveConsent({ enableAgree, updateConsent, showModal, setShowModal }) {
- return (
-
- setShowModal(true)}
- >
- Disagree
-
-
- setShowModal(false)}
- onConfirm={() => updateConsent({ consent: false })}
- message="You must agree with this policy to use the app. Are you sure you wish to exit?"
- option="Exit"
- />
- {enableAgree ? (
- updateConsent({ consent: true })}>
- Agree
-
- ) : (
-
- Agree
-
- )}
-
- );
-}
-
-function WithdrawConsent({ updateConsent, showModal, setShowModal }) {
- return (
-
- setShowModal(false)}
- onConfirm={() => updateConsent({ consent: false })}
- message="If you withdraw consent you won’t be able to use LiteFarm. Are you sure you wish to exit?"
- option="Withdraw"
- />
- setShowModal(true)}>
- Withdraw Consent
-
-
- );
-}
-
-export default ConsentFooter;
diff --git a/packages/webapp/src/components/ConsentFooter/styles.module.scss b/packages/webapp/src/components/ConsentFooter/styles.module.scss
deleted file mode 100644
index 10eb0441b9..0000000000
--- a/packages/webapp/src/components/ConsentFooter/styles.module.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-.bottomContainer {
- max-width: 1024px;
- width: 100%;
- position: fixed;
- bottom: 0;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- font-weight: 600;
- align-items: center;
- padding: 2% 5% 2% 5%;
- margin-left: -5%;
- background: white;
- box-shadow: 0 -5px 5px -5px #333;
- border-radius: 10px;
-}
-
-.cancelButton {
- width: 40%;
- font-size: 20px;
- color: #4d4d4d;
-}
diff --git a/packages/webapp/src/components/ContainerWithIcon/ContainerWithIcon.js b/packages/webapp/src/components/ContainerWithIcon/ContainerWithIcon.jsx
similarity index 100%
rename from packages/webapp/src/components/ContainerWithIcon/ContainerWithIcon.js
rename to packages/webapp/src/components/ContainerWithIcon/ContainerWithIcon.jsx
diff --git a/packages/webapp/src/components/CreateUserAccount/index.js b/packages/webapp/src/components/CreateUserAccount/index.js
deleted file mode 100644
index 394646e865..0000000000
--- a/packages/webapp/src/components/CreateUserAccount/index.js
+++ /dev/null
@@ -1,131 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import Input from '../Form/Input';
-import React from 'react';
-import { Title } from '../Typography';
-import PropTypes from 'prop-types';
-import { Controller, useForm } from 'react-hook-form';
-import { validatePasswordWithErrors } from '../Signup/utils';
-import { PasswordError } from '../Form/Errors';
-import ReactSelect from '../Form/ReactSelect';
-import { useTranslation } from 'react-i18next';
-
-export default function PureCreateUserAccount({ onSignUp, email, onGoBack }) {
- const {
- register,
- handleSubmit,
- watch,
- control,
- setValue,
-
- formState: { isDirty, isValid, errors },
- } = useForm({
- mode: 'onTouched',
- });
- const NAME = 'name';
- const GENDER = 'gender';
- const BIRTHYEAR = 'birth_year';
- const PASSWORD = 'password';
- const password = watch(PASSWORD, undefined);
- const { t } = useTranslation(['translation', 'common', 'gender']);
- const title = t('CREATE_USER.TITLE');
- const {
- isValid: isPasswordValid,
- hasNoSymbol,
- hasNoDigit,
- hasNoUpperCase,
- isTooShort,
- } = validatePasswordWithErrors(password);
- const genderOptions = [
- { value: 'MALE', label: t('gender:MALE') },
- { value: 'FEMALE', label: t('gender:FEMALE') },
- { value: 'OTHER', label: t('gender:OTHER') },
- { value: 'PREFER_NOT_TO_SAY', label: t('gender:PREFER_NOT_TO_SAY') },
- ];
-
- const disabled = !isDirty || !isValid || !isPasswordValid;
-
- const onSubmit = (data) => {
- data[GENDER] = data?.[GENDER]?.value || 'PREFER_NOT_TO_SAY';
- onSignUp({ ...data, email });
- };
- const onError = (data) => {};
-
- return (
-
- );
-}
-
-PureCreateUserAccount.prototype = {
- onLogin: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/CreateUserAccount/index.jsx b/packages/webapp/src/components/CreateUserAccount/index.jsx
new file mode 100644
index 0000000000..7d1603b7e7
--- /dev/null
+++ b/packages/webapp/src/components/CreateUserAccount/index.jsx
@@ -0,0 +1,133 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import Input from '../Form/Input';
+import React from 'react';
+import { Title } from '../Typography';
+import PropTypes from 'prop-types';
+import { Controller, useForm } from 'react-hook-form';
+import { validatePasswordWithErrors } from '../Signup/utils';
+import { PasswordError } from '../Form/Errors';
+import ReactSelect from '../Form/ReactSelect';
+import { useTranslation } from 'react-i18next';
+
+export default function PureCreateUserAccount({ onSignUp, email, onGoBack }) {
+ const {
+ register,
+ handleSubmit,
+ watch,
+ control,
+ setValue,
+
+ formState: { isDirty, isValid, errors },
+ } = useForm({
+ mode: 'onTouched',
+ });
+ const NAME = 'name';
+ const GENDER = 'gender';
+ const BIRTHYEAR = 'birth_year';
+ const PASSWORD = 'password';
+ const password = watch(PASSWORD, undefined);
+ const { t } = useTranslation(['translation', 'common', 'gender']);
+ const title = t('CREATE_USER.TITLE');
+ const {
+ isValid: isPasswordValid,
+ hasNoSymbol,
+ hasNoDigit,
+ hasNoUpperCase,
+ isTooShort,
+ } = validatePasswordWithErrors(password);
+ const genderOptions = [
+ { value: 'MALE', label: t('gender:MALE') },
+ { value: 'FEMALE', label: t('gender:FEMALE') },
+ { value: 'OTHER', label: t('gender:OTHER') },
+ { value: 'PREFER_NOT_TO_SAY', label: t('gender:PREFER_NOT_TO_SAY') },
+ ];
+
+ const disabled = !isDirty || !isValid || !isPasswordValid;
+
+ const onSubmit = (data) => {
+ data[GENDER] = data?.[GENDER]?.value || 'PREFER_NOT_TO_SAY';
+ onSignUp({ ...data, email });
+ };
+ const onError = (data) => {};
+
+ return (
+
+ );
+}
+
+PureCreateUserAccount.prototype = {
+ onLogin: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PureBedForm.js b/packages/webapp/src/components/Crop/BedPlan/PureBedForm.js
deleted file mode 100644
index 8e22bb150d..0000000000
--- a/packages/webapp/src/components/Crop/BedPlan/PureBedForm.js
+++ /dev/null
@@ -1,183 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
-import { container_planting_depth, length_of_bed_or_row, seedYield } from '../../../util/unit';
-import clsx from 'clsx';
-import Unit from '../../Form/Unit';
-import { isNonNegativeNumber } from '../../Form/validations';
-import PropTypes from 'prop-types';
-
-export function PureBedForm({
- system,
- crop_variety,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- register,
- getValues,
- watch,
- control,
- setValue,
- errors,
- disabled,
-}) {
- const { t } = useTranslation();
- const NUMBER_OF_BEDS = `${prefix}.bed_method.number_of_beds`;
- const NUMBER_OF_ROWS_IN_BED = `${prefix}.bed_method.number_of_rows_in_bed`;
- const PLANT_SPACING_UNIT = `${prefix}.bed_method.plant_spacing_unit`;
- const PLANT_SPACING = `${prefix}.bed_method.plant_spacing`;
- const BED_LENGTH_UNIT = `${prefix}.bed_method.bed_length_unit`;
- const BED_LENGTH = `${prefix}.bed_method.bed_length`;
-
- const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
- const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
-
- const number_of_beds = watch(NUMBER_OF_BEDS);
- const number_of_rows_in_bed = watch(NUMBER_OF_ROWS_IN_BED);
- const bed_length = watch(BED_LENGTH);
- const plant_spacing = watch(PLANT_SPACING);
-
- const [showEstimatedValue, setShowEstimatedValue] = useState(false);
- const shouldSkipEstimatedValueCalculationRef = useRef(true);
- useEffect(() => {
- const shouldCalculateEstimatedValues =
- isNonNegativeNumber(number_of_beds) &&
- isNonNegativeNumber(number_of_rows_in_bed) &&
- isNonNegativeNumber(bed_length) &&
- isNonNegativeNumber(plant_spacing);
- if (shouldSkipEstimatedValueCalculationRef.current) {
- shouldSkipEstimatedValueCalculationRef.current = false;
- setShowEstimatedValue(shouldCalculateEstimatedValues);
- } else if (shouldCalculateEstimatedValues) {
- const yield_per_plant = crop_variety.yield_per_plant;
- const average_seed_weight = crop_variety.average_seed_weight;
-
- const estimated_yield =
- ((number_of_beds * number_of_rows_in_bed * bed_length) / plant_spacing) * yield_per_plant;
-
- const estimated_seed_required_in_weight =
- ((number_of_beds * number_of_rows_in_bed * bed_length) / plant_spacing) *
- average_seed_weight;
-
- average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required_in_weight);
- yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
- setShowEstimatedValue(true);
- } else {
- setShowEstimatedValue(false);
- }
- }, [number_of_beds, number_of_rows_in_bed, bed_length, plant_spacing]);
- const showEstimatedYield = prefix.endsWith('final');
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- {showEstimatedValue && (
-
-
- {showEstimatedYield && (
-
- )}
-
- )}
- >
- );
-}
-
-PureBedForm.prototype = {
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- register: PropTypes.func,
- getValues: PropTypes.func,
- watch: PropTypes.func,
- control: PropTypes.any,
- setValue: PropTypes.func,
- errors: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PureBedForm.jsx b/packages/webapp/src/components/Crop/BedPlan/PureBedForm.jsx
new file mode 100644
index 0000000000..68ec52188d
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BedPlan/PureBedForm.jsx
@@ -0,0 +1,183 @@
+import React, { useEffect, useRef, useState } from 'react';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
+import { container_planting_depth, length_of_bed_or_row, seedYield } from '../../../util/convert-units/unit';
+import clsx from 'clsx';
+import Unit from '../../Form/Unit';
+import { isNonNegativeNumber } from '../../Form/validations';
+import PropTypes from 'prop-types';
+
+export function PureBedForm({
+ system,
+ crop_variety,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ register,
+ getValues,
+ watch,
+ control,
+ setValue,
+ errors,
+ disabled,
+}) {
+ const { t } = useTranslation();
+ const NUMBER_OF_BEDS = `${prefix}.bed_method.number_of_beds`;
+ const NUMBER_OF_ROWS_IN_BED = `${prefix}.bed_method.number_of_rows_in_bed`;
+ const PLANT_SPACING_UNIT = `${prefix}.bed_method.plant_spacing_unit`;
+ const PLANT_SPACING = `${prefix}.bed_method.plant_spacing`;
+ const BED_LENGTH_UNIT = `${prefix}.bed_method.bed_length_unit`;
+ const BED_LENGTH = `${prefix}.bed_method.bed_length`;
+
+ const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
+ const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+
+ const number_of_beds = watch(NUMBER_OF_BEDS);
+ const number_of_rows_in_bed = watch(NUMBER_OF_ROWS_IN_BED);
+ const bed_length = watch(BED_LENGTH);
+ const plant_spacing = watch(PLANT_SPACING);
+
+ const [showEstimatedValue, setShowEstimatedValue] = useState(false);
+ const shouldSkipEstimatedValueCalculationRef = useRef(true);
+ useEffect(() => {
+ const shouldCalculateEstimatedValues =
+ isNonNegativeNumber(number_of_beds) &&
+ isNonNegativeNumber(number_of_rows_in_bed) &&
+ isNonNegativeNumber(bed_length) &&
+ isNonNegativeNumber(plant_spacing);
+ if (shouldSkipEstimatedValueCalculationRef.current) {
+ shouldSkipEstimatedValueCalculationRef.current = false;
+ setShowEstimatedValue(shouldCalculateEstimatedValues);
+ } else if (shouldCalculateEstimatedValues) {
+ const yield_per_plant = crop_variety.yield_per_plant;
+ const average_seed_weight = crop_variety.average_seed_weight;
+
+ const estimated_yield =
+ ((number_of_beds * number_of_rows_in_bed * bed_length) / plant_spacing) * yield_per_plant;
+
+ const estimated_seed_required_in_weight =
+ ((number_of_beds * number_of_rows_in_bed * bed_length) / plant_spacing) *
+ average_seed_weight;
+
+ average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required_in_weight);
+ yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
+ setShowEstimatedValue(true);
+ } else {
+ setShowEstimatedValue(false);
+ }
+ }, [number_of_beds, number_of_rows_in_bed, bed_length, plant_spacing]);
+ const showEstimatedYield = prefix.endsWith('final');
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ {showEstimatedValue && (
+
+
+ {showEstimatedYield && (
+
+ )}
+
+ )}
+ >
+ );
+}
+
+PureBedForm.prototype = {
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ register: PropTypes.func,
+ getValues: PropTypes.func,
+ watch: PropTypes.func,
+ control: PropTypes.any,
+ setValue: PropTypes.func,
+ errors: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.js b/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.js
deleted file mode 100644
index 26aac828e8..0000000000
--- a/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import { PureBedForm } from './PureBedForm';
-import PropTypes from 'prop-types';
-
-function PureBedPlan({
- history,
- system,
- crop_variety,
- useHookFormPersist,
- persistedFormData,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- submitPath,
- onGoBack = () => history.goBack(),
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- defaultValues: cloneObject(persistedFormData),
- shouldUnregister: false,
- mode: 'onChange',
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const onSubmit = () => history.push(submitPath);
-
- return (
-
- );
-}
-
-export default PureBedPlan;
-PureBedPlan.prototype = {
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.jsx b/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.jsx
new file mode 100644
index 0000000000..51f2606aed
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BedPlan/PureBedPlan.jsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import { PureBedForm } from './PureBedForm';
+import PropTypes from 'prop-types';
+
+function PureBedPlan({
+ history,
+ system,
+ crop_variety,
+ useHookFormPersist,
+ persistedFormData,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ submitPath,
+ onGoBack = () => history.back(),
+ location,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ defaultValues: cloneObject(persistedFormData),
+ shouldUnregister: false,
+ mode: 'onChange',
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const onSubmit = () => history.push(submitPath, location?.state);
+
+ return (
+
+ );
+}
+
+export default PureBedPlan;
+PureBedPlan.prototype = {
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.js b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.js
deleted file mode 100644
index 1a7178a421..0000000000
--- a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import { PurePlanGuidanceForm } from './PurePlanGuidanceForm';
-import PropTypes from 'prop-types';
-
-function PurePlanGuidance({
- system,
- persistedFormData,
- useHookFormPersist,
- isBed,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- history,
- submitPath,
- onGoBack = () => history.goBack(),
- onSubmit = () => history.push(submitPath),
-}) {
- const { t } = useTranslation(['translation']);
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- defaultValues: cloneObject(persistedFormData),
- shouldUnregister: false,
- mode: 'onChange',
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- return (
-
- );
-}
-
-export default PurePlanGuidance;
-PurePlanGuidance.prototype = {
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- isBed: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.jsx b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.jsx
new file mode 100644
index 0000000000..1e460cf294
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidance.jsx
@@ -0,0 +1,85 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import { PurePlanGuidanceForm } from './PurePlanGuidanceForm';
+import PropTypes from 'prop-types';
+
+function PurePlanGuidance({
+ system,
+ persistedFormData,
+ useHookFormPersist,
+ isBed,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ history,
+ submitPath,
+ location,
+ onGoBack = () => history.back(),
+ onSubmit = () => history.push(submitPath, location?.state),
+}) {
+ const { t } = useTranslation(['translation']);
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ defaultValues: cloneObject(persistedFormData),
+ shouldUnregister: false,
+ mode: 'onChange',
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ return (
+
+ );
+}
+
+export default PurePlanGuidance;
+PurePlanGuidance.prototype = {
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ isBed: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.js b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.js
deleted file mode 100644
index 86a64ddd3c..0000000000
--- a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors } from '../../Form/Input';
-import { container_planting_depth } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import PropTypes from 'prop-types';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export function PurePlanGuidanceForm({
- system,
- isBed,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- register,
- getValues,
- watch,
- control,
- setValue,
- errors,
- disabled,
-}) {
- const { t } = useTranslation(['translation']);
-
- const SPECIFY = `${prefix}.${isBed ? `bed_method.specify_beds` : `row_method.specify_rows`}`;
- const PLANTING_DEPTH = `${prefix}.${
- isBed ? `bed_method.planting_depth` : `row_method.planting_depth`
- }`;
- const PLANTING_DEPTH_UNIT = `${prefix}.${
- isBed ? `bed_method.planting_depth_unit` : `row_method.planting_depth_unit`
- }`;
- const WIDTH = `${prefix}.${isBed ? `bed_method.bed_width` : `row_method.row_width`}`;
- const WIDTH_UNIT = `${prefix}.${
- isBed ? `bed_method.bed_width_unit` : `row_method.row_width_unit`
- }`;
- const SPACING = `${prefix}.${isBed ? `bed_method.bed_spacing` : `row_method.row_spacing`}`;
- const SPACING_UNIT = `${prefix}.${
- isBed ? `bed_method.bed_spacing_unit` : `row_method.row_spacing_unit`
- }`;
- const PLANTING_NOTES = `${prefix}.notes`;
-
- const TYPE = isBed ? t('PLAN_GUIDANCE.BED') : t('PLAN_GUIDANCE.ROW');
- const TYPES = isBed ? [t('PLAN_GUIDANCE.BEDS')] : [t('PLAN_GUIDANCE.ROWS')];
-
- const SPECIFY_LIMIT = 40;
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
-PurePlanGuidanceForm.prototype = {
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- register: PropTypes.func,
- getValues: PropTypes.func,
- watch: PropTypes.func,
- control: PropTypes.any,
- setValue: PropTypes.func,
- errors: PropTypes.object,
- isBed: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.jsx b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.jsx
new file mode 100644
index 0000000000..e0c23467a9
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BedPlan/PurePlanGuidanceForm.jsx
@@ -0,0 +1,140 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors } from '../../Form/Input';
+import { container_planting_depth } from '../../../util/convert-units/unit';
+import Unit from '../../Form/Unit';
+import PropTypes from 'prop-types';
+import InputAutoSize from '../../Form/InputAutoSize';
+
+export function PurePlanGuidanceForm({
+ system,
+ isBed,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ register,
+ getValues,
+ watch,
+ control,
+ setValue,
+ errors,
+ disabled,
+}) {
+ const { t } = useTranslation(['translation']);
+
+ const SPECIFY = `${prefix}.${isBed ? `bed_method.specify_beds` : `row_method.specify_rows`}`;
+ const PLANTING_DEPTH = `${prefix}.${
+ isBed ? `bed_method.planting_depth` : `row_method.planting_depth`
+ }`;
+ const PLANTING_DEPTH_UNIT = `${prefix}.${
+ isBed ? `bed_method.planting_depth_unit` : `row_method.planting_depth_unit`
+ }`;
+ const WIDTH = `${prefix}.${isBed ? `bed_method.bed_width` : `row_method.row_width`}`;
+ const WIDTH_UNIT = `${prefix}.${
+ isBed ? `bed_method.bed_width_unit` : `row_method.row_width_unit`
+ }`;
+ const SPACING = `${prefix}.${isBed ? `bed_method.bed_spacing` : `row_method.row_spacing`}`;
+ const SPACING_UNIT = `${prefix}.${
+ isBed ? `bed_method.bed_spacing_unit` : `row_method.row_spacing_unit`
+ }`;
+ const PLANTING_NOTES = `${prefix}.notes`;
+
+ const TYPE = isBed ? t('PLAN_GUIDANCE.BED') : t('PLAN_GUIDANCE.ROW');
+ const TYPES = isBed ? [t('PLAN_GUIDANCE.BEDS')] : [t('PLAN_GUIDANCE.ROWS')];
+
+ const SPECIFY_LIMIT = 40;
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
+
+PurePlanGuidanceForm.prototype = {
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ register: PropTypes.func,
+ getValues: PropTypes.func,
+ watch: PropTypes.func,
+ control: PropTypes.any,
+ setValue: PropTypes.func,
+ errors: PropTypes.object,
+ isBed: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.js b/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.js
deleted file mode 100644
index 77d1fd6671..0000000000
--- a/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.js
+++ /dev/null
@@ -1,238 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import { Label } from '../../Typography';
-import Input from '../../Form/Input';
-import InputAutoSize from '../../Form/InputAutoSize';
-import { get } from 'react-hook-form';
-import { area_total_area, getDefaultUnit, seedYield } from '../../../util/unit';
-import clsx from 'clsx';
-import convert from 'convert-units';
-import Unit, { getUnitOptionMap } from '../../Form/Unit';
-import PropTypes from 'prop-types';
-
-export function PureBroadcastForm({
- system,
- locationSize,
- yieldPerArea,
- isFinalPage,
- register,
- getValues,
- watch,
- control,
- setValue,
- errors,
- prefix,
- disabled,
-}) {
- const { t } = useTranslation(['translation']);
-
- const shouldValidate = { shouldValidate: true };
- const [displayedLocationSize, setDisplayedLocationSize] = useState(null);
- const [initialSeedingRate, setInitialSeedingRate] = useState(null);
- const KgHaToKgM2 = 1 / 10000;
- const KgHaToLbAc = 2.20462 / 2.47105;
- const LbAcToKgHa = 0.453592 / 0.404686;
- const seedingRateUnit = system === 'metric' ? 'kg/ha' : 'lb/ac';
- const PERCENTAGE_PLANTED = `${prefix}.broadcast_method.percentage_planted`;
- const SEEDING_RATE = `${prefix}.broadcast_method.seeding_rate`;
- const AREA_USED = `${prefix}.broadcast_method.area_used`;
- const AREA_USED_UNIT = `${prefix}.broadcast_method.area_used_unit`;
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
- const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
- const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
- const NOTES = `${prefix}.notes`;
- const greenInput = { color: 'var(--teal900)', fontWeight: 600 };
-
- const percentageOfAreaPlanted = watch(PERCENTAGE_PLANTED);
- const seedingRateFormInKgM2 = watch(SEEDING_RATE);
- const areaUsed = watch(AREA_USED);
- const areaUsedUnit = watch(AREA_USED_UNIT);
-
- const getErrorMessage = (name, min, max) => {
- const type = get(errors, name)?.type;
- if (type === 'required') return t('common:REQUIRED');
- if (type === 'max') return t('common:MAX_ERROR', { value: max });
- if (type === 'min') return t('common:MIN_ERROR', { value: min });
- if (type === 'validate') return t('common:MIN_ERROR', { value: min });
- };
-
- const seedingRateHandler = (e) => {
- const seedingRateConversion = (system === 'metric' ? 1 : LbAcToKgHa) * KgHaToKgM2;
- setValue(
- SEEDING_RATE,
- e.target.value === '' ? '' : seedingRateConversion * Number(e.target.value),
- shouldValidate,
- );
- };
-
- useEffect(() => {
- if (seedingRateFormInKgM2) {
- setInitialSeedingRate(
- system === 'metric'
- ? seedingRateFormInKgM2 / KgHaToKgM2
- : ((seedingRateFormInKgM2 / KgHaToKgM2) * KgHaToLbAc).toFixed(2),
- );
- }
- }, []);
-
- useEffect(() => {
- const areaUsed = (locationSize * percentageOfAreaPlanted) / 100;
- setValue(AREA_USED, areaUsed, shouldValidate);
- setValue(
- AREA_USED_UNIT,
- getUnitOptionMap()[getDefaultUnit(area_total_area, areaUsed, system).displayUnit],
- shouldValidate,
- );
- }, [percentageOfAreaPlanted]);
- const shouldSkipEstimatedValueCalculationRef = useRef(true);
- useEffect(() => {
- if (shouldSkipEstimatedValueCalculationRef.current) {
- shouldSkipEstimatedValueCalculationRef.current = false;
- } else {
- setValue(ESTIMATED_SEED, seedingRateFormInKgM2 * areaUsed, shouldValidate);
- yieldPerArea && setValue(ESTIMATED_YIELD, areaUsed * yieldPerArea, shouldValidate);
- }
- }, [seedingRateFormInKgM2, areaUsed]);
-
- useEffect(() => {
- if (areaUsedUnit?.value) {
- const newDisplayedSize = convert(locationSize).from('m2').to(areaUsedUnit.value).toFixed(2);
- setDisplayedLocationSize(newDisplayedSize);
- }
- }, [areaUsedUnit]);
-
- return (
- <>
-
- {/*TODO: refactor and create new unit component with 2 disabled input field*/}
-
-
- {t('BROADCAST_PLAN.LOCATION_SIZE')}
-
-
-
-
-
- Number(value) > 0,
- })}
- style={{ display: 'none' }}
- disabled={disabled}
- />
-
- {areaUsed > 0 && seedingRateFormInKgM2 > 0 && (
-
-
- {isFinalPage && (
-
- )}
-
- )}
-
- >
- );
-}
-
-PureBroadcastForm.prototype = {
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- register: PropTypes.func,
- getValues: PropTypes.func,
- watch: PropTypes.func,
- control: PropTypes.any,
- setValue: PropTypes.func,
- errors: PropTypes.object,
- locationSize: PropTypes.number,
- yieldPerArea: PropTypes.number,
-};
diff --git a/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.jsx b/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.jsx
new file mode 100644
index 0000000000..c1b9f7c68b
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BroadcastPlan/PureBroadcastForm.jsx
@@ -0,0 +1,237 @@
+import React, { useEffect, useRef, useState } from 'react';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import { Label } from '../../Typography';
+import Input from '../../Form/Input';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { get } from 'react-hook-form';
+import { area_total_area, getDefaultUnit, seedYield } from '../../../util/convert-units/unit';
+import clsx from 'clsx';
+import { convert } from '../../../util/convert-units/convert';
+import Unit, { getUnitOptionMap } from '../../Form/Unit';
+import PropTypes from 'prop-types';
+
+export function PureBroadcastForm({
+ system,
+ locationSize,
+ yieldPerArea,
+ isFinalPage,
+ register,
+ getValues,
+ watch,
+ control,
+ setValue,
+ errors,
+ prefix,
+ disabled,
+}) {
+ const { t } = useTranslation(['translation']);
+
+ const shouldValidate = { shouldValidate: true };
+ const [displayedLocationSize, setDisplayedLocationSize] = useState(null);
+ const [initialSeedingRate, setInitialSeedingRate] = useState(null);
+ const KgHaToKgM2 = 1 / 10000;
+ const KgHaToLbAc = 2.20462 / 2.47105;
+ const LbAcToKgHa = 0.453592 / 0.404686;
+ const seedingRateUnit = system === 'metric' ? 'kg/ha' : 'lb/ac';
+ const PERCENTAGE_PLANTED = `${prefix}.broadcast_method.percentage_planted`;
+ const SEEDING_RATE = `${prefix}.broadcast_method.seeding_rate`;
+ const AREA_USED = `${prefix}.broadcast_method.area_used`;
+ const AREA_USED_UNIT = `${prefix}.broadcast_method.area_used_unit`;
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+ const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
+ const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
+ const NOTES = `${prefix}.notes`;
+ const greenInput = { color: 'var(--teal900)', fontWeight: 600 };
+
+ const percentageOfAreaPlanted = watch(PERCENTAGE_PLANTED);
+ const seedingRateFormInKgM2 = watch(SEEDING_RATE);
+ const areaUsed = watch(AREA_USED);
+ const areaUsedUnit = watch(AREA_USED_UNIT);
+
+ const getErrorMessage = (name, min, max) => {
+ const type = get(errors, name)?.type;
+ if (type === 'required') return t('common:REQUIRED');
+ if (type === 'max') return t('common:MAX_ERROR', { value: max });
+ if (type === 'min') return t('common:MIN_ERROR', { value: min });
+ if (type === 'validate') return t('common:MIN_ERROR', { value: min });
+ };
+
+ const seedingRateHandler = (e) => {
+ const seedingRateConversion = (system === 'metric' ? 1 : LbAcToKgHa) * KgHaToKgM2;
+ setValue(
+ SEEDING_RATE,
+ e.target.value === '' ? '' : seedingRateConversion * Number(e.target.value),
+ shouldValidate,
+ );
+ };
+
+ useEffect(() => {
+ if (seedingRateFormInKgM2) {
+ setInitialSeedingRate(
+ system === 'metric'
+ ? seedingRateFormInKgM2 / KgHaToKgM2
+ : ((seedingRateFormInKgM2 / KgHaToKgM2) * KgHaToLbAc).toFixed(2),
+ );
+ }
+ }, []);
+
+ useEffect(() => {
+ const areaUsed = (locationSize * percentageOfAreaPlanted) / 100;
+ setValue(AREA_USED, areaUsed, shouldValidate);
+ setValue(
+ AREA_USED_UNIT,
+ getUnitOptionMap()[getDefaultUnit(area_total_area, areaUsed, system).displayUnit],
+ shouldValidate,
+ );
+ }, [percentageOfAreaPlanted]);
+ const shouldSkipEstimatedValueCalculationRef = useRef(true);
+ useEffect(() => {
+ if (shouldSkipEstimatedValueCalculationRef.current) {
+ shouldSkipEstimatedValueCalculationRef.current = false;
+ } else {
+ setValue(ESTIMATED_SEED, seedingRateFormInKgM2 * areaUsed, shouldValidate);
+ yieldPerArea && setValue(ESTIMATED_YIELD, areaUsed * yieldPerArea, shouldValidate);
+ }
+ }, [seedingRateFormInKgM2, areaUsed]);
+
+ useEffect(() => {
+ if (areaUsedUnit?.value) {
+ const newDisplayedSize = convert(locationSize).from('m2').to(areaUsedUnit.value).toFixed(2);
+ setDisplayedLocationSize(newDisplayedSize);
+ }
+ }, [areaUsedUnit]);
+
+ return (
+ <>
+
+ {/*TODO: refactor and create new unit component with 2 disabled input field*/}
+
+
+ {t('BROADCAST_PLAN.LOCATION_SIZE')}
+
+
+
+
+
+ Number(value) > 0,
+ })}
+ style={{ display: 'none' }}
+ disabled={disabled}
+ />
+
+ {areaUsed > 0 && seedingRateFormInKgM2 > 0 && (
+
+
+ {isFinalPage && (
+
+ )}
+
+ )}
+
+ >
+ );
+}
+
+PureBroadcastForm.prototype = {
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ register: PropTypes.func,
+ getValues: PropTypes.func,
+ watch: PropTypes.func,
+ control: PropTypes.any,
+ setValue: PropTypes.func,
+ errors: PropTypes.object,
+ locationSize: PropTypes.number,
+ yieldPerArea: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Crop/BroadcastPlan/index.js b/packages/webapp/src/components/Crop/BroadcastPlan/index.js
deleted file mode 100644
index ca832b0e8c..0000000000
--- a/packages/webapp/src/components/Crop/BroadcastPlan/index.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import React, { useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import { getBroadcastMethodPaths } from '../getAddManagementPlanPath';
-import { PureBroadcastForm } from './PureBroadcastForm';
-import PropTypes from 'prop-types';
-
-function PureBroadcastPlan({
- persistedFormData,
- useHookFormPersist,
- system,
- variety_id,
- history,
- locationSize,
- yieldPerArea,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
-}) {
- const { t } = useTranslation(['translation']);
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- defaultValues: cloneObject(persistedFormData),
- shouldUnregister: false,
- mode: 'onChange',
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const { submitPath } = useMemo(
- () => getBroadcastMethodPaths(variety_id, isFinalPage),
- [],
- );
- const onSubmit = () => history.push(submitPath);
- const onGoBack = () => history.goBack();
-
- const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
- const isHistoricalPage =
- already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
-
- return (
-
- );
-}
-
-export default PureBroadcastPlan;
-PureBroadcastPlan.prototype = {
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- locationSize: PropTypes.number,
- yieldPerArea: PropTypes.number,
-};
diff --git a/packages/webapp/src/components/Crop/BroadcastPlan/index.jsx b/packages/webapp/src/components/Crop/BroadcastPlan/index.jsx
new file mode 100644
index 0000000000..985b39918e
--- /dev/null
+++ b/packages/webapp/src/components/Crop/BroadcastPlan/index.jsx
@@ -0,0 +1,98 @@
+import React, { useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import { getBroadcastMethodPaths } from '../getAddManagementPlanPath';
+import { PureBroadcastForm } from './PureBroadcastForm';
+import PropTypes from 'prop-types';
+
+function PureBroadcastPlan({
+ persistedFormData,
+ useHookFormPersist,
+ system,
+ variety_id,
+ history,
+ locationSize,
+ yieldPerArea,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ location,
+}) {
+ const { t } = useTranslation(['translation']);
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ defaultValues: cloneObject(persistedFormData),
+ shouldUnregister: false,
+ mode: 'onChange',
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const { submitPath } = useMemo(() => getBroadcastMethodPaths(variety_id, isFinalPage), []);
+ const onSubmit = () => history.push(submitPath, location?.state);
+ const onGoBack = () => history.back();
+
+ const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
+ const isHistoricalPage =
+ already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
+
+ return (
+
+ );
+}
+
+export default PureBroadcastPlan;
+PureBroadcastPlan.prototype = {
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ locationSize: PropTypes.number,
+ yieldPerArea: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.js b/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.js
deleted file mode 100644
index 869038b212..0000000000
--- a/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.js
+++ /dev/null
@@ -1,152 +0,0 @@
-import Form from '../../Form';
-import CropHeader from '../cropHeader';
-import React, { useState } from 'react';
-import { Controller, useForm } from 'react-hook-form';
-import Button from '../../Form/Button';
-import { useTranslation } from 'react-i18next';
-import { Title } from '../../Typography';
-import ReactSelect from '../../Form/ReactSelect';
-import Rating from '../../Rating';
-import InputAutoSize from '../../Form/InputAutoSize';
-import Input from '../../Form/Input';
-import { getDateInputFormat } from '../../../util/moment';
-import AbandonManagementPlanModal from '../../Modals/AbandonManagementPlanModal';
-import i18n from '../../../locales/i18n';
-
-export const SOMETHING_ELSE = 'SOMETHING_ELSE';
-export const defaultAbandonManagementPlanReasonOptions = [
- { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.CROP_FAILURE'), value: 'CROP_FAILURE' },
- { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.LABOUR_ISSUE'), value: 'LABOUR_ISSUE' },
- { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.MARKET_PROBLEM'), value: 'MARKET_PROBLEM' },
- { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.WEATHER'), value: 'WEATHER' },
- {
- label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.MACHINERY_ISSUE'),
- value: 'MACHINERY_ISSUE',
- },
- {
- label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.SCHEDULING_ISSUE'),
- value: 'SCHEDULING_ISSUE',
- },
- { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.SOMETHING_ELSE'), value: SOMETHING_ELSE },
-];
-
-export function PureCompleteManagementPlan({
- onGoBack,
- crop_variety,
- onSubmit,
- isAbandonPage,
- reasonOptions,
- start_date,
-}) {
- const { t } = useTranslation();
- const DATE = isAbandonPage ? 'abandon_date' : 'complete_date';
-
- const RATING = 'rating';
- const NOTES = 'complete_notes';
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- defaultValues: { [DATE]: getDateInputFormat(new Date()) },
- });
-
- const ABANDON_REASON = 'abandon_reason';
- const abandon_reason = watch(ABANDON_REASON);
- const CREATED_ABANDON_REASON = 'created_abandon_reason';
-
- const [showAbandonModal, setShowAbandonModal] = useState(false);
-
- const disabled = !isValid;
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.jsx b/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.jsx
new file mode 100644
index 0000000000..08589817cd
--- /dev/null
+++ b/packages/webapp/src/components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan.jsx
@@ -0,0 +1,153 @@
+import Form from '../../Form';
+import CropHeader from '../CropHeader';
+import React, { useState } from 'react';
+import { Controller, useForm } from 'react-hook-form';
+import Button from '../../Form/Button';
+import { useTranslation } from 'react-i18next';
+import { Title } from '../../Typography';
+import ReactSelect from '../../Form/ReactSelect';
+import Rating from '../../Rating';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Input from '../../Form/Input';
+import { getDateInputFormat } from '../../../util/moment';
+import AbandonManagementPlanModal from '../../Modals/AbandonManagementPlanModal';
+import i18n from '../../../locales/i18n';
+
+export const SOMETHING_ELSE = 'Something Else';
+export const defaultAbandonManagementPlanReasonOptions = [
+ { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.CROP_FAILURE'), value: 'CROP_FAILURE' },
+ { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.LABOUR_ISSUE'), value: 'LABOUR_ISSUE' },
+ { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.MARKET_PROBLEM'), value: 'MARKET_PROBLEM' },
+ { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.WEATHER'), value: 'WEATHER' },
+ {
+ label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.MACHINERY_ISSUE'),
+ value: 'MACHINERY_ISSUE',
+ },
+ {
+ label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.SCHEDULING_ISSUE'),
+ value: 'SCHEDULING_ISSUE',
+ },
+ { label: i18n.t('MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.SOMETHING_ELSE'), value: SOMETHING_ELSE },
+];
+
+export function PureCompleteManagementPlan({
+ onGoBack,
+ crop_variety,
+ onSubmit,
+ isAbandonPage,
+ reasonOptions,
+ start_date,
+}) {
+ const { t } = useTranslation();
+ const DATE = isAbandonPage ? 'abandon_date' : 'complete_date';
+
+ const RATING = 'rating';
+ const NOTES = 'complete_notes';
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: { [DATE]: getDateInputFormat(new Date()) },
+ });
+
+ const ABANDON_REASON = 'abandon_reason';
+ const abandon_reason = watch(ABANDON_REASON);
+ const CREATED_ABANDON_REASON = 'created_abandon_reason';
+
+ const [showAbandonModal, setShowAbandonModal] = useState(false);
+
+ const disabled = !isValid;
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Crop/CropHeader.jsx b/packages/webapp/src/components/Crop/CropHeader.jsx
new file mode 100644
index 0000000000..6a7efbadae
--- /dev/null
+++ b/packages/webapp/src/components/Crop/CropHeader.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { Label, Text, Title } from '../Typography';
+import { ReactComponent as Back } from '../../assets/images/managementPlans/back.svg';
+import { useTranslation } from 'react-i18next';
+import styles from './styles.module.scss';
+
+function CropHeader({
+ crop_translation_key,
+ crop_variety_name,
+ supplier,
+ crop_variety_photo_url,
+ onBackClick,
+}) {
+ const { t } = useTranslation(['translation', 'crop']);
+ return (
+
+
+
+
{t(`crop:${crop_translation_key}`)}
+
+
+
+ {t('MANAGEMENT_PLAN.VARIETY')}:{' '}
+
+ {' '}
+ {crop_variety_name ?? t(`crop:${crop_translation_key}`)}{' '}
+
+
+
+
+
+ {t('MANAGEMENT_PLAN.SUPPLIER')}:{' '}
+ {supplier}
+
+
+
+
+
+
+ );
+}
+
+export default CropHeader;
diff --git a/packages/webapp/src/components/Crop/Detail.jsx b/packages/webapp/src/components/Crop/Detail.jsx
new file mode 100644
index 0000000000..374d258958
--- /dev/null
+++ b/packages/webapp/src/components/Crop/Detail.jsx
@@ -0,0 +1,169 @@
+import CropHeader from './CropHeader';
+import RouterTab from '../RouterTab';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import Button from '../Form/Button';
+import { ReactComponent as Leaf } from '../../assets/images/signUp/leaf.svg';
+import { Main, Title } from '../Typography';
+import { useForm } from 'react-hook-form';
+import RadioGroup from '../Form/RadioGroup';
+import styles from './styles.module.scss';
+import Layout from '../Layout';
+import Input, { integerOnKeyDown } from '../Form/Input';
+
+function PureCropDetail({
+ history,
+ match,
+ variety,
+ isEditing,
+ onBack,
+ isInterestedInOrganic,
+ onRetire,
+ onEdit,
+ isAdmin,
+ location,
+}) {
+ const { t } = useTranslation();
+ const {
+ handleSubmit,
+ register,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({ mode: 'onChange', defaultValues: { ...variety } });
+ const LIFECYCLE = 'lifecycle';
+ const ORGANIC = 'organic';
+ const TREATED = 'treated';
+ const SEARCHED = 'searched';
+ const GENETICALLY_ENGINEERED = 'genetically_engineered';
+ const HS_CODE_ID = 'hs_code_id';
+ const isOrganic = isEditing ? watch(ORGANIC) : variety.organic;
+ return (
+
+ {/*TODO: LF-2003 rework task/management plan/location/crop_variety soft delete*/}
+ {/**/}
+ {/* {t('common:RETIRE')}*/}
+ {/* */}
+
+ {t('common:EDIT')}
+
+ >
+ )
+ }
+ >
+ history.back()}
+ crop_translation_key={variety.crop_translation_key}
+ crop_variety_name={variety.crop_variety_name}
+ crop_variety_photo_url={variety.crop_variety_photo_url}
+ supplier={variety.supplier}
+ />
+ {!isEditing && (
+ <>
+
+
+ {/*
+ {t('CROP_DETAIL.COMPLIANCE_DOC')}
+
+ */}
+ >
+ )}
+ {isEditing && (
+ {t('CROP_DETAIL.EDIT_CROP_DETAIL')}
+ )}
+
+ {t('CROP_DETAIL.ANNUAL_PERENNIAL')}
+
+
+ {isInterestedInOrganic && (
+ <>
+
+ {t('CROP_DETAIL.ORGANIC')}
+
+
+
+ {!isOrganic && (
+ <>
+
+ {t('CROP_DETAIL.COMMERCIAL_AVAILABILITY')}
+
+
+
+
+ {t('CROP_DETAIL.GENETICALLY_ENGINEERED')}
+
+
+
+ >
+ )}
+
+ {t('CROP_DETAIL.TREATED')}
+
+
+
+ >
+ )}
+
+
+ );
+}
+
+export default PureCropDetail;
diff --git a/packages/webapp/src/components/Crop/Management.jsx b/packages/webapp/src/components/Crop/Management.jsx
new file mode 100644
index 0000000000..50979cb844
--- /dev/null
+++ b/packages/webapp/src/components/Crop/Management.jsx
@@ -0,0 +1,110 @@
+import Layout from '../Layout';
+import CropHeader from './CropHeader';
+import RouterTab from '../RouterTab';
+import React, { useMemo, useState } from 'react';
+import { AddLink, Semibold } from '../Typography';
+import { useTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+import { CardWithStatusContainer } from '../CardWithStatus/CardWithStatusContainer/CardWithStatusContainer';
+import { ManagementPlanCard } from '../CardWithStatus/ManagementPlanCard/ManagementPlanCard';
+import Input from '../Form/Input';
+
+export default function PureCropManagement({
+ history,
+ match,
+ onBack,
+ variety,
+ onAddManagementPlan,
+ managementPlanCardContents,
+ isAdmin,
+ location,
+}) {
+ const { t } = useTranslation();
+ const [searchString, setSearchString] = useState('');
+ const searchStringOnChange = (e) => setSearchString(e.target.value);
+ const filteredManagementPlanCardContents = useMemo(() => {
+ return searchString
+ ? managementPlanCardContents.filter(
+ ({ locationName, managementPlanName, status }) =>
+ locationName?.toLowerCase()?.includes(searchString?.toLowerCase()) ||
+ managementPlanName?.toLowerCase()?.includes(searchString?.toLowerCase()) ||
+ status?.toLowerCase()?.includes(searchString?.toLowerCase()),
+ )
+ : managementPlanCardContents;
+ }, [searchString, managementPlanCardContents]);
+
+ return (
+
+
+
+ {t('CROP_DETAIL.MANAGEMENT_PLANS')}
+ {managementPlanCardContents?.length > 2 && (
+
+ )}
+ {isAdmin && (
+
+ {' '}
+ {t('CROP_DETAIL.ADD_PLAN')}
+
+ )}
+ {managementPlanCardContents && (
+
+ {filteredManagementPlanCardContents.map((managementPlan, index) => (
+
+ history.push(
+ `/crop/${variety.crop_variety_id}/management_plan/${managementPlan.management_plan_id}/tasks`,
+ location.state,
+ )
+ }
+ {...managementPlan}
+ key={index}
+ />
+ ))}
+
+ )}
+
+ );
+}
+
+PureCropManagement.propTypes = {
+ managementPlanCardContents: PropTypes.arrayOf(
+ PropTypes.shape({
+ managementPlanName: PropTypes.string,
+ locationName: PropTypes.string,
+ notes: PropTypes.string,
+ startDate: PropTypes.any,
+ endDate: PropTypes.any,
+ numberOfPendingTask: PropTypes.number,
+ status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
+ management_plan_id: PropTypes.number,
+ }),
+ ),
+ history: PropTypes.object,
+ match: PropTypes.object,
+ onBack: PropTypes.func,
+ variety: PropTypes.object,
+ onAddManagementPlan: PropTypes.func,
+ isAdmin: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.js b/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.js
deleted file mode 100644
index 5cbeaf8ff7..0000000000
--- a/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.js
+++ /dev/null
@@ -1,117 +0,0 @@
-import React from 'react';
-import CropHeader from '../cropHeader';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import { Info, Label } from '../../Typography';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import { useForm } from 'react-hook-form';
-import { seedYield } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import InputAutoSize from '../../Form/InputAutoSize';
-import Input, { getInputErrors } from '../../Form/Input';
-import Form from '../../Form';
-
-export default function PureEditManagementDetail({ onBack, variety, plan, system, onSubmit }) {
- const { t } = useTranslation();
-
- const title = plan.name;
-
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- defaultValues: {
- notes: plan.notes,
- name: plan.name,
- crop_management_plan: {
- estimated_yield: plan.estimated_yield,
- estimated_yield_unit: plan.estimated_yield_unit,
- },
- },
- shouldUnregister: false,
- mode: 'onChange',
- });
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
- const NOTES = 'notes';
- const NAME = 'name';
-
- return (
-
- );
-}
-
-PureEditManagementDetail.prototype = {
- onBack: PropTypes.func,
- variety: PropTypes.object,
- plan: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
- onSubmit: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.jsx b/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.jsx
new file mode 100644
index 0000000000..b1a586abdc
--- /dev/null
+++ b/packages/webapp/src/components/Crop/ManagementDetail/EditManagementPlanDetail.jsx
@@ -0,0 +1,117 @@
+import React from 'react';
+import CropHeader from '../CropHeader';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import { Info, Label } from '../../Typography';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import { useForm } from 'react-hook-form';
+import { seedYield } from '../../../util/convert-units/unit';
+import Unit from '../../Form/Unit';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Input, { getInputErrors } from '../../Form/Input';
+import Form from '../../Form';
+
+export default function PureEditManagementDetail({ onBack, variety, plan, system, onSubmit }) {
+ const { t } = useTranslation();
+
+ const title = plan.name;
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ defaultValues: {
+ notes: plan.notes,
+ name: plan.name,
+ crop_management_plan: {
+ estimated_yield: plan.estimated_yield,
+ estimated_yield_unit: plan.estimated_yield_unit,
+ },
+ },
+ shouldUnregister: false,
+ mode: 'onChange',
+ });
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+ const NOTES = 'notes';
+ const NAME = 'name';
+
+ return (
+
+ );
+}
+
+PureEditManagementDetail.prototype = {
+ onBack: PropTypes.func,
+ variety: PropTypes.object,
+ plan: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
+ onSubmit: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.js b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.js
deleted file mode 100644
index 33935d55e1..0000000000
--- a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import React from 'react';
-import CropHeader from '../cropHeader';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import { Label } from '../../Typography';
-import Layout from '../../Layout';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import RouterTab from '../../RouterTab';
-import { useForm } from 'react-hook-form';
-import { seedYield } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export default function PureManagementDetail({
- onBack,
- variety,
- plan,
- isAdmin,
- history,
- match,
- system,
-}) {
- const { t } = useTranslation();
-
- const title = plan.name;
-
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- defaultValues: {
- notes: plan.notes,
- crop_management_plan: {
- estimated_yield: plan.estimated_yield,
- estimated_yield_unit: plan.estimated_yield_unit,
- },
- },
- shouldUnregister: false,
- mode: 'onChange',
- });
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
- const NOTES = 'notes';
- return (
-
-
- history.push(
- `/crop/${match.params.variety_id}/management_plan/${match.params.management_plan_id}/edit`,
- )
- }
- >
- {t('common:EDIT')}
-
- >
- )
- }
- >
-
-
-
-
- {title}
-
-
-
-
-
-
-
-
-
- );
-}
-
-PureManagementDetail.prototype = {
- onBack: PropTypes.func,
- variety: PropTypes.object,
- plan: PropTypes.object,
- isAdmin: PropTypes.bool,
- history: PropTypes.object,
- match: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
-};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.jsx b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.jsx
new file mode 100644
index 0000000000..4bb2947d3b
--- /dev/null
+++ b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanDetail.jsx
@@ -0,0 +1,203 @@
+import React from 'react';
+import CropHeader from '../CropHeader';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import { Label } from '../../Typography';
+import Layout from '../../Layout';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import RouterTab from '../../RouterTab';
+import { useForm } from 'react-hook-form';
+import { seedYield } from '../../../util/convert-units/unit';
+import { getDateInputFormat } from '../../../util/moment';
+import Unit from '../../Form/Unit';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Rating from '../../Rating';
+
+export default function PureManagementDetail({
+ onBack,
+ variety,
+ plan,
+ isAdmin,
+ history,
+ match,
+ system,
+}) {
+ const { t } = useTranslation();
+
+ const title = plan.name;
+ const isValidDate =
+ getDateInputFormat(plan.abandon_date) !== 'Invalid date' ||
+ getDateInputFormat(plan.complete_date) !== 'Invalid date';
+ const isSomethingElse =
+ plan.abandon_reason !== 'CROP_FAILURE' &&
+ plan.abandon_reason !== 'LABOUR_ISSUE' &&
+ plan.abandon_reason !== 'MARKET_PROBLEM' &&
+ plan.abandon_reason !== 'WEATHER' &&
+ plan.abandon_reason !== 'MACHINERY_ISSUE' &&
+ plan.abandon_reason !== 'SCHEDULING_ISSUE';
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ defaultValues: {
+ abandon_date: isValidDate ? getDateInputFormat(plan.abandon_date) : '',
+ abandon_reason: isSomethingElse
+ ? plan.abandon_reason
+ : t(`MANAGEMENT_PLAN.COMPLETE_PLAN.REASON.${plan.abandon_reason}`),
+ complete_date: isValidDate ? getDateInputFormat(plan.complete_date) : '',
+ complete_notes: plan.complete_notes,
+ notes: plan.notes,
+ crop_management_plan: {
+ estimated_yield: plan.estimated_yield,
+ estimated_yield_unit: plan.estimated_yield_unit,
+ },
+ },
+ shouldUnregister: false,
+ mode: 'onChange',
+ });
+
+ const isAbandoned = plan.abandon_date ? true : false;
+ const DATE_OF_STATUS_CHANGE = isAbandoned ? 'abandon_date' : 'complete_date';
+ const ABANDON_REASON = 'abandon_reason';
+ const DATE = isAbandoned ? 'ABANDON_DATE' : 'COMPLETE_DATE';
+ const COMPLETE_NOTES = 'complete_notes';
+ const PLAN_NOTES = 'notes';
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+
+ return (
+
+
+ history.push(
+ `/crop/${match.params.variety_id}/management_plan/${match.params.management_plan_id}/edit`,
+ )
+ }
+ >
+ {t('common:EDIT')}
+
+ >
+ )
+ }
+ >
+ history.back()}
+ crop_translation_key={variety.crop_translation_key}
+ crop_variety_name={variety.crop_variety_name}
+ crop_variety_photo_url={variety.crop_variety_photo_url}
+ supplier={variety.supplier}
+ />
+
+
+
+ {title}
+
+
+
+
+
+
+
+ {}}
+ />
+
+ {isAbandoned && (
+
+ )}
+
+
+
+
+
+
+
+ );
+}
+
+PureManagementDetail.prototype = {
+ onBack: PropTypes.func,
+ variety: PropTypes.object,
+ plan: PropTypes.object,
+ isAdmin: PropTypes.bool,
+ history: PropTypes.object,
+ match: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
+};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.js b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.js
deleted file mode 100644
index 46628f198a..0000000000
--- a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import React, { useState } from 'react';
-import CropHeader from '../cropHeader';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import { AddLink, Label, Underlined } from '../../Typography';
-import Layout from '../../Layout';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import IncompleteTaskModal from '../../Modals/IncompleteTaskModal';
-import RouterTab from '../../RouterTab';
-
-export default function PureManagementTasks({
- onCompleted,
- onAbandon,
- onBack,
- onAddTask,
- variety,
- plan,
- isAdmin,
- hasPendingTasks,
- history,
- match,
- children,
-}) {
- const { t } = useTranslation();
-
- const title = plan.name;
-
- const [showCompleteFailModal, setShowCompleteFailModal] = useState(false);
-
- const onMarkComplete = () => {
- if (hasPendingTasks) {
- setShowCompleteFailModal(true);
- } else {
- onCompleted();
- }
- };
-
- const isActiveOrPlanned = !plan.abandon_date && !plan.complete_date;
-
- return (
-
-
- {t('common:MARK_COMPLETED')}
-
- >
- )
- }
- >
-
-
-
-
- {title}
-
-
-
-
-
- {isAdmin && isActiveOrPlanned && (
-
- {t('MANAGEMENT_DETAIL.ADD_A_TASK')}
-
- )}
- {children}
-
- {isAdmin && isActiveOrPlanned && (
-
- {t('MANAGEMENT_DETAIL.FAILED_CROP')}
-
- {t('MANAGEMENT_DETAIL.ABANDON_PLAN')}
-
-
- )}
- {showCompleteFailModal && (
- setShowCompleteFailModal(false)} />
- )}
-
- );
-}
-
-PureManagementTasks.prototype = {
- onBack: PropTypes.func,
- onCompleted: PropTypes.func,
- plan: PropTypes.object,
- isAdmin: PropTypes.bool,
- onAbandon: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.jsx b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.jsx
new file mode 100644
index 0000000000..c226762ef4
--- /dev/null
+++ b/packages/webapp/src/components/Crop/ManagementDetail/ManagementPlanTasks.jsx
@@ -0,0 +1,114 @@
+import React, { useState } from 'react';
+import CropHeader from '../CropHeader';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import { AddLink, Label, Underlined } from '../../Typography';
+import Layout from '../../Layout';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import IncompleteTaskModal from '../../Modals/IncompleteTaskModal';
+import RouterTab from '../../RouterTab';
+
+export default function PureManagementTasks({
+ onCompleted,
+ onAbandon,
+ onBack,
+ onAddTask,
+ variety,
+ plan,
+ isAdmin,
+ hasPendingTasks,
+ history,
+ match,
+ children,
+ location,
+}) {
+ const { t } = useTranslation();
+
+ const title = plan.name;
+
+ const [showCompleteFailModal, setShowCompleteFailModal] = useState(false);
+
+ const onMarkComplete = () => {
+ if (hasPendingTasks) {
+ setShowCompleteFailModal(true);
+ } else {
+ onCompleted();
+ }
+ };
+
+ const isActiveOrPlanned = !plan.abandon_date && !plan.complete_date;
+
+ return (
+
+
+ {t('common:MARK_COMPLETED')}
+
+ >
+ )
+ }
+ >
+ history.go(-1)}
+ crop_translation_key={variety.crop_translation_key}
+ crop_variety_name={variety.crop_variety_name}
+ crop_variety_photo_url={variety.crop_variety_photo_url}
+ supplier={variety.supplier}
+ />
+
+
+
+ {title}
+
+
+
+
+
+ {isAdmin && isActiveOrPlanned && (
+
+ {t('MANAGEMENT_DETAIL.ADD_A_TASK')}
+
+ )}
+ {children}
+
+ {isAdmin && isActiveOrPlanned && (
+
+ {t('MANAGEMENT_DETAIL.FAILED_CROP')}
+
+ {t('MANAGEMENT_DETAIL.ABANDON_PLAN')}
+
+
+ )}
+ {showCompleteFailModal && (
+ setShowCompleteFailModal(false)} />
+ )}
+
+ );
+}
+
+PureManagementTasks.prototype = {
+ onBack: PropTypes.func,
+ onCompleted: PropTypes.func,
+ plan: PropTypes.object,
+ isAdmin: PropTypes.bool,
+ onAbandon: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Crop/ManagementDetail/styles.module.scss b/packages/webapp/src/components/Crop/ManagementDetail/styles.module.scss
index 9d993e8705..23aee920dd 100644
--- a/packages/webapp/src/components/Crop/ManagementDetail/styles.module.scss
+++ b/packages/webapp/src/components/Crop/ManagementDetail/styles.module.scss
@@ -56,3 +56,8 @@
.bottomText {
color: var(--teal700);
}
+
+.rating {
+ display: flex;
+
+}
diff --git a/packages/webapp/src/components/Crop/ManagementPlanName/index.js b/packages/webapp/src/components/Crop/ManagementPlanName/index.js
deleted file mode 100644
index 24df8076c2..0000000000
--- a/packages/webapp/src/components/Crop/ManagementPlanName/index.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import Button from '../../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors } from '../../Form/Input';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import InputAutoSize from '../../Form/InputAutoSize';
-import { cloneObject } from '../../../util';
-
-export default function PureManagementPlanName({
- onSubmit,
- onError,
- match,
- history,
- persistedFormData,
- useHookFormPersist,
- managementPlanCount,
-}) {
- const { t } = useTranslation();
- const variety_id = match?.params?.variety_id;
-
- const NAME = 'name';
- const NOTES = 'notes';
-
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: {
- [NAME]: t('MANAGEMENT_PLAN.PLAN_AND_ID', { id: managementPlanCount }),
- ...cloneObject(persistedFormData),
- },
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const onGoBack = () => history.goBack();
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PureManagementPlanName.prototype = {
- history: PropTypes.object,
- match: PropTypes.object,
- onSubmit: PropTypes.func,
- onError: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
- managementPlanCount: PropTypes.number,
-};
diff --git a/packages/webapp/src/components/Crop/ManagementPlanName/index.jsx b/packages/webapp/src/components/Crop/ManagementPlanName/index.jsx
new file mode 100644
index 0000000000..c05d9dcfd3
--- /dev/null
+++ b/packages/webapp/src/components/Crop/ManagementPlanName/index.jsx
@@ -0,0 +1,93 @@
+import Button from '../../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors } from '../../Form/Input';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { cloneObject } from '../../../util';
+
+export default function PureManagementPlanName({
+ onSubmit,
+ onError,
+ match,
+ history,
+ persistedFormData,
+ useHookFormPersist,
+ managementPlanCount,
+}) {
+ const { t } = useTranslation();
+ const variety_id = match?.params?.variety_id;
+
+ const NAME = 'name';
+ const NOTES = 'notes';
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: {
+ [NAME]: t('MANAGEMENT_PLAN.PLAN_AND_ID', { id: managementPlanCount }),
+ ...cloneObject(persistedFormData),
+ },
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const onGoBack = () => history.back();
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PureManagementPlanName.prototype = {
+ history: PropTypes.object,
+ match: PropTypes.object,
+ onSubmit: PropTypes.func,
+ onError: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+ managementPlanCount: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.js b/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.js
deleted file mode 100644
index f456c9e670..0000000000
--- a/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.js
+++ /dev/null
@@ -1,275 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
-import RadioGroup from '../../Form/RadioGroup';
-import Unit from '../../Form/Unit';
-import { container_plant_spacing, container_planting_depth, seedYield } from '../../../util/unit';
-import styles from './styles.module.scss';
-import { isNonNegativeNumber } from '../../Form/validations';
-import { hookFormMaxLengthValidation, hookFormMaxValidation } from '../../Form/hookformValidationUtils';
-import clsx from 'clsx';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export default function PureContainerForm({
- system,
- crop_variety,
- isFinalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- register,
- getValues,
- watch,
- control,
- setValue,
- errors,
- disabled,
-}) {
- const { t } = useTranslation();
- const IN_GROUND = `${prefix}.container_method.in_ground`;
- const NUMBER_OF_CONTAINERS = `${prefix}.container_method.number_of_containers`;
- const PLANTS_PER_CONTAINER = `${prefix}.container_method.plants_per_container`;
- const PLANT_SPACING = `${prefix}.container_method.plant_spacing`;
- const PLANT_SPACING_UNIT = `${prefix}.container_method.plant_spacing_unit`;
- const TOTAL_PLANTS = `${prefix}.container_method.total_plants`;
- const PLANTING_DEPTH = `${prefix}.container_method.planting_depth`;
- const PLANTING_DEPTH_UNIT = `${prefix}.container_method.planting_depth_unit`;
- const PLANTING_SOIL = `${prefix}.container_method.planting_soil`;
- const CONTAINER_TYPE = `${prefix}.container_method.container_type`;
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
- const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
- const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
- const NOTES = `${prefix}.notes`;
-
- const in_ground = watch(IN_GROUND);
- const number_of_container = watch(NUMBER_OF_CONTAINERS);
- const plants_per_container = watch(PLANTS_PER_CONTAINER);
- const total_plants = watch(TOTAL_PLANTS);
- const plant_spacing = watch(PLANT_SPACING);
-
- const isPlantSpacingRequired = ![1, 0].includes(total_plants);
-
- const [showEstimatedValue, setShowEstimatedValue] = useState(false);
- const shouldSkipEstimatedValueCalculationRef = useRef(true);
- useEffect(() => {
- const { average_seed_weight = 0, yield_per_plant = 0 } = crop_variety;
- const shouldCalculateInGroundEstimatedValues =
- in_ground && isNonNegativeNumber(total_plants) && isNonNegativeNumber(plant_spacing);
- const shouldCalculateContainerEstimatedValues =
- !in_ground &&
- isNonNegativeNumber(number_of_container) &&
- isNonNegativeNumber(plants_per_container);
- if (shouldSkipEstimatedValueCalculationRef.current) {
- shouldSkipEstimatedValueCalculationRef.current = false;
- setShowEstimatedValue(
- shouldCalculateInGroundEstimatedValues || shouldCalculateContainerEstimatedValues,
- );
- } else if (shouldCalculateInGroundEstimatedValues) {
- const required_seeds = total_plants * average_seed_weight;
- const estimated_yield = total_plants * yield_per_plant;
- average_seed_weight && setValue(ESTIMATED_SEED, required_seeds);
- yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
- setShowEstimatedValue(true);
- } else if (shouldCalculateContainerEstimatedValues) {
- const required_seeds = number_of_container * plants_per_container * average_seed_weight;
- const estimated_yield = number_of_container * plants_per_container * yield_per_plant;
- average_seed_weight && setValue(ESTIMATED_SEED, required_seeds);
- yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
- setShowEstimatedValue(true);
- } else {
- setShowEstimatedValue(false);
- }
- }, [in_ground, number_of_container, plants_per_container, total_plants, plant_spacing]);
- const showEstimatedYield = prefix.endsWith('final');
-
- return (
- <>
-
- {(in_ground === true || in_ground === false) && (
- <>
- {!in_ground && (
-
-
-
-
- )}
- {in_ground && (
-
- )}
-
-
-
- {in_ground && (
-
- )}
-
-
- {!in_ground && (
- <>
-
-
- >
- )}
- {showEstimatedValue && (
-
-
- {showEstimatedYield && (
-
- )}
-
- )}
-
-
- >
- )}
- >
- );
-}
-
-PureContainerForm.prototype = {
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- prefix: PropTypes.string,
- register: PropTypes.func,
- getValues: PropTypes.func,
- watch: PropTypes.func,
- control: PropTypes.any,
- setValue: PropTypes.func,
- errors: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.jsx b/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.jsx
new file mode 100644
index 0000000000..15b4976229
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantInContainer/PureContainerForm.jsx
@@ -0,0 +1,288 @@
+import React, { useEffect, useRef, useState } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
+import RadioGroup from '../../Form/RadioGroup';
+import Unit from '../../Form/Unit';
+import {
+ container_plant_spacing,
+ container_planting_depth,
+ seedYield,
+} from '../../../util/convert-units/unit';
+import styles from './styles.module.scss';
+import { isNonNegativeNumber } from '../../Form/validations';
+import {
+ hookFormMaxLengthValidation,
+ hookFormMaxValidation,
+} from '../../Form/hookformValidationUtils';
+import clsx from 'clsx';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { get } from 'react-hook-form';
+
+export default function PureContainerForm({
+ system,
+ crop_variety,
+ isFinalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ register,
+ getValues,
+ watch,
+ control,
+ setValue,
+ errors,
+ disabled,
+ clearErrors,
+}) {
+ const { t } = useTranslation();
+ const IN_GROUND = `${prefix}.container_method.in_ground`;
+ const NUMBER_OF_CONTAINERS = `${prefix}.container_method.number_of_containers`;
+ const PLANTS_PER_CONTAINER = `${prefix}.container_method.plants_per_container`;
+ const PLANT_SPACING = `${prefix}.container_method.plant_spacing`;
+ const PLANT_SPACING_UNIT = `${prefix}.container_method.plant_spacing_unit`;
+ const TOTAL_PLANTS = `${prefix}.container_method.total_plants`;
+ const PLANTING_DEPTH = `${prefix}.container_method.planting_depth`;
+ const PLANTING_DEPTH_UNIT = `${prefix}.container_method.planting_depth_unit`;
+ const PLANTING_SOIL = `${prefix}.container_method.planting_soil`;
+ const CONTAINER_TYPE = `${prefix}.container_method.container_type`;
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+ const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
+ const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
+ const NOTES = `${prefix}.notes`;
+
+ const in_ground = watch(IN_GROUND);
+ const number_of_container = watch(NUMBER_OF_CONTAINERS);
+ const plants_per_container = watch(PLANTS_PER_CONTAINER);
+ const total_plants = watch(TOTAL_PLANTS);
+ const plant_spacing = watch(PLANT_SPACING);
+
+ const isPlantSpacingRequired = ![1, 0].includes(total_plants);
+
+ const [showEstimatedValue, setShowEstimatedValue] = useState(false);
+ const shouldSkipEstimatedValueCalculationRef = useRef(true);
+ useEffect(() => {
+ const { average_seed_weight = 0, yield_per_plant = 0 } = crop_variety;
+ const shouldCalculateInGroundEstimatedValues =
+ in_ground &&
+ isNonNegativeNumber(total_plants) &&
+ (isNonNegativeNumber(plant_spacing) || total_plants === 1);
+ const shouldCalculateContainerEstimatedValues =
+ !in_ground &&
+ isNonNegativeNumber(number_of_container) &&
+ isNonNegativeNumber(plants_per_container);
+ if (shouldSkipEstimatedValueCalculationRef.current) {
+ shouldSkipEstimatedValueCalculationRef.current = false;
+ setShowEstimatedValue(
+ shouldCalculateInGroundEstimatedValues || shouldCalculateContainerEstimatedValues,
+ );
+ } else if (shouldCalculateInGroundEstimatedValues) {
+ get(errors, PLANT_SPACING)?.type === 'required' && clearErrors(PLANT_SPACING);
+ const required_seeds = total_plants * average_seed_weight;
+ const estimated_yield = total_plants * yield_per_plant;
+ average_seed_weight && setValue(ESTIMATED_SEED, required_seeds);
+ yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
+ setShowEstimatedValue(true);
+ } else if (shouldCalculateContainerEstimatedValues) {
+ const required_seeds = number_of_container * plants_per_container * average_seed_weight;
+ const estimated_yield = number_of_container * plants_per_container * yield_per_plant;
+ average_seed_weight && setValue(ESTIMATED_SEED, required_seeds);
+ yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
+ setShowEstimatedValue(true);
+ } else {
+ setShowEstimatedValue(false);
+ }
+ }, [in_ground, number_of_container, plants_per_container, total_plants, plant_spacing]);
+ const showEstimatedYield = prefix.endsWith('final');
+
+ return (
+ <>
+
+ {(in_ground === true || in_ground === false) && (
+ <>
+ {!in_ground && (
+
+
+
+
+ )}
+ {in_ground && (
+
+ )}
+
+
+
+ {in_ground && (
+
+ )}
+
+
+ {!in_ground && (
+ <>
+
+
+ >
+ )}
+ {showEstimatedValue && (
+
+
+ {showEstimatedYield && (
+
+ )}
+
+ )}
+
+
+ >
+ )}
+ >
+ );
+}
+
+PureContainerForm.prototype = {
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ register: PropTypes.func,
+ getValues: PropTypes.func,
+ watch: PropTypes.func,
+ control: PropTypes.any,
+ setValue: PropTypes.func,
+ errors: PropTypes.object,
+ clearErrors: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Crop/PlantInContainer/index.js b/packages/webapp/src/components/Crop/PlantInContainer/index.js
deleted file mode 100644
index e95f4a4f17..0000000000
--- a/packages/webapp/src/components/Crop/PlantInContainer/index.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import Button from '../../Form/Button';
-import React, { useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import PureContainerForm from './PureContainerForm';
-
-export default function PurePlantInContainer({
- useHookFormPersist,
- persistedFormData,
- system,
- history,
- crop_variety,
- isFinalPage,
- isHistorical,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- submitPath,
- onSubmit = () => history.push(submitPath),
- onGoBack = () => history.goBack(),
-}) {
- const progress = useMemo(() => {
- if (isHistorical && !isFinalPage) return 55;
- if (isFinalPage) return 75;
- return 50;
- }, []);
-
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const onError = () => {};
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PurePlantInContainer.prototype = {
- history: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
-};
diff --git a/packages/webapp/src/components/Crop/PlantInContainer/index.jsx b/packages/webapp/src/components/Crop/PlantInContainer/index.jsx
new file mode 100644
index 0000000000..c17b817564
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantInContainer/index.jsx
@@ -0,0 +1,102 @@
+import Button from '../../Form/Button';
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import PureContainerForm from './PureContainerForm';
+
+export default function PurePlantInContainer({
+ useHookFormPersist,
+ persistedFormData,
+ system,
+ history,
+ crop_variety,
+ isFinalPage,
+ isHistorical,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ submitPath,
+ location,
+ onSubmit = () => history.push(submitPath, location?.state),
+ onGoBack = () => history.back(),
+}) {
+ const progress = useMemo(() => {
+ if (isHistorical && !isFinalPage) return 55;
+ if (isFinalPage) return 75;
+ return 50;
+ }, []);
+
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ clearErrors,
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const onError = () => {};
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PurePlantInContainer.prototype = {
+ history: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+};
diff --git a/packages/webapp/src/components/Crop/PlantedAlready/index.js b/packages/webapp/src/components/Crop/PlantedAlready/index.js
deleted file mode 100644
index 711c4397f9..0000000000
--- a/packages/webapp/src/components/Crop/PlantedAlready/index.js
+++ /dev/null
@@ -1,243 +0,0 @@
-import React, { useEffect, useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import { get, useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import RadioGroup from '../../Form/RadioGroup';
-import Button from '../../Form/Button';
-import Unit from '../../Form/Unit';
-import { Label } from '../../Typography';
-import { crop_age, getDurationInDaysDefaultUnit } from '../../../util/unit';
-import styles from './styles.module.scss';
-import { cloneObject } from '../../../util';
-import { getDateDifference, getDateInputFormat } from '../../../util/moment';
-import { getPlantedAlreadyPaths } from '../getAddManagementPlanPath';
-
-export default function PurePlantedAlready({
- history,
- useHookFormPersist,
- persistedFormData,
- system,
- cropVariety,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const progress = 12.5;
-
- const ALREADY_IN_GROUND = 'crop_management_plan.already_in_ground';
- const AGE = 'crop_management_plan.crop_age';
- const AGE_UNIT = 'crop_management_plan.crop_age_unit';
- //TODO: remove duplicate
- const SEEDLING_AGE = AGE;
- const SEEDLING_AGE_UNIT = AGE_UNIT;
-
- const IS_SEED = 'crop_management_plan.is_seed';
- const IS_WILD = 'crop_management_plan.is_wild';
-
- const MAX_AGE = 99999;
- const MAX_SEEDLING_AGE = 999;
-
- useEffect(() => {
- if (persistedFormData.crop_management_plan.seed_date) {
- const currentDate = getDateInputFormat(new Date());
- const newAge = getDateDifference(
- persistedFormData.crop_management_plan.seed_date,
- currentDate,
- );
- setValue(AGE, newAge);
- setValue(AGE_UNIT, getDurationInDaysDefaultUnit(newAge));
- }
- }, []);
-
- const { submitPath } = useMemo(
- () => getPlantedAlreadyPaths(cropVariety.crop_variety_id),
- [],
- );
-
- const onSubmit = () => {
- const age = getValues(AGE);
- if ((already_in_ground || !is_seed) && age !== get(persistedFormData, AGE)) {
- const SEED_DATE = 'crop_management_plan.seed_date';
- if (age === 0 || age > 0) {
- const seedDate = new Date();
- seedDate.setDate(seedDate.getDate() - getValues(AGE));
- setValue(SEED_DATE, getDateInputFormat(seedDate));
- } else {
- setValue(SEED_DATE, undefined);
- }
- }
-
- const NEEDS_TRANSPLANT = 'crop_management_plan.needs_transplant';
- if (get(persistedFormData, NEEDS_TRANSPLANT) === undefined) {
- if (getValues(ALREADY_IN_GROUND)) {
- setValue(NEEDS_TRANSPLANT, false);
- } else if (getValues(IS_SEED) === false) {
- setValue(NEEDS_TRANSPLANT, true);
- } else {
- setValue(NEEDS_TRANSPLANT, cropVariety.needs_transplant);
- }
- }
-
- const FOR_COVER = 'crop_management_plan.for_cover';
- if (cropVariety.can_be_cover_crop && get(persistedFormData, FOR_COVER) === undefined) {
- setValue(FOR_COVER, true);
- } else if (!cropVariety.can_be_cover_crop) {
- setValue(FOR_COVER, false);
- }
- history.push(submitPath);
- };
- const onGoBack = () => history.goBack();
-
- const already_in_ground = watch(ALREADY_IN_GROUND);
- const is_seed = watch(IS_SEED);
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PurePlantedAlready.prototype = {
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- cropVariety: PropTypes.shape({
- needs_transplant: PropTypes.bool,
- can_be_cover_crop: PropTypes.bool,
- crop_variety_id: PropTypes.string,
- }),
-};
diff --git a/packages/webapp/src/components/Crop/PlantedAlready/index.jsx b/packages/webapp/src/components/Crop/PlantedAlready/index.jsx
new file mode 100644
index 0000000000..7f7e137b91
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantedAlready/index.jsx
@@ -0,0 +1,248 @@
+import React, { useEffect, useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import { get, useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import RadioGroup from '../../Form/RadioGroup';
+import Button from '../../Form/Button';
+import Unit from '../../Form/Unit';
+import { Label } from '../../Typography';
+import { crop_age, getDurationInDaysDefaultUnit } from '../../../util/convert-units/unit';
+import styles from './styles.module.scss';
+import { cloneObject } from '../../../util';
+import { getDateDifference, getDateInputFormat } from '../../../util/moment';
+import { getPlantedAlreadyPaths } from '../getAddManagementPlanPath';
+
+export default function PurePlantedAlready({
+ history,
+ useHookFormPersist,
+ persistedFormData,
+ system,
+ cropVariety,
+ location,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const progress = 12.5;
+
+ const ALREADY_IN_GROUND = 'crop_management_plan.already_in_ground';
+ const AGE = 'crop_management_plan.crop_age';
+ const AGE_UNIT = 'crop_management_plan.crop_age_unit';
+ //TODO: remove duplicate
+ const SEEDLING_AGE = AGE;
+ const SEEDLING_AGE_UNIT = AGE_UNIT;
+
+ const IS_SEED = 'crop_management_plan.is_seed';
+ const IS_WILD = 'crop_management_plan.is_wild';
+
+ const MAX_AGE = 99999;
+ const MAX_SEEDLING_AGE = 999;
+
+ useEffect(() => {
+ if (persistedFormData.crop_management_plan.seed_date) {
+ const currentDate = getDateInputFormat(new Date());
+ const newAge = getDateDifference(
+ persistedFormData.crop_management_plan.seed_date,
+ currentDate,
+ );
+ setValue(AGE, newAge);
+ setValue(AGE_UNIT, getDurationInDaysDefaultUnit(newAge));
+ }
+ }, []);
+
+ const { submitPath } = useMemo(() => getPlantedAlreadyPaths(cropVariety.crop_variety_id), []);
+
+ const onSubmit = () => {
+ const age = getValues(AGE);
+ if ((already_in_ground || !is_seed) && age !== get(persistedFormData, AGE)) {
+ const SEED_DATE = 'crop_management_plan.seed_date';
+ if (age === 0 || age > 0) {
+ const seedDate = new Date();
+ seedDate.setDate(seedDate.getDate() - getValues(AGE));
+ setValue(SEED_DATE, getDateInputFormat(seedDate));
+ } else {
+ setValue(SEED_DATE, undefined);
+ }
+ }
+
+ const NEEDS_TRANSPLANT = 'crop_management_plan.needs_transplant';
+ if (get(persistedFormData, NEEDS_TRANSPLANT) === undefined) {
+ if (getValues(ALREADY_IN_GROUND)) {
+ setValue(NEEDS_TRANSPLANT, false);
+ } else if (getValues(IS_SEED) === false) {
+ setValue(NEEDS_TRANSPLANT, true);
+ } else {
+ setValue(NEEDS_TRANSPLANT, cropVariety.needs_transplant);
+ }
+ }
+
+ const FOR_COVER = 'crop_management_plan.for_cover';
+ if (cropVariety.can_be_cover_crop && get(persistedFormData, FOR_COVER) === undefined) {
+ setValue(FOR_COVER, true);
+ } else if (!cropVariety.can_be_cover_crop) {
+ setValue(FOR_COVER, false);
+ }
+ history.push(submitPath, location?.state);
+ };
+ const onGoBack = () => history.back();
+
+ const already_in_ground = watch(ALREADY_IN_GROUND);
+ const is_seed = watch(IS_SEED);
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PurePlantedAlready.prototype = {
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ cropVariety: PropTypes.shape({
+ needs_transplant: PropTypes.bool,
+ can_be_cover_crop: PropTypes.bool,
+ crop_variety_id: PropTypes.string,
+ }),
+};
diff --git a/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.js b/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.js
deleted file mode 100644
index ad3ad4402e..0000000000
--- a/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import React, { useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import Button from '../../Form/Button';
-import Unit from '../../Form/Unit';
-import { Label } from '../../Typography';
-import Input from '../../Form/Input';
-import { seedYield } from '../../../util/unit';
-import { cloneObject } from '../../../util';
-import styles from './styles.module.scss';
-import { getNextHarvestPaths } from '../getAddManagementPlanPath';
-
-export default function PureNextHarvest({
- system,
- persistedFormData,
- useHookFormPersist,
- crop_variety,
- history,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- setError,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const progress = 37.5;
-
- const HARVEST_DATE = 'crop_management_plan.harvest_date';
- const TERMINATION_DATE = 'crop_management_plan.termination_date';
- const [MAIN_DATE, title] = useMemo(() => {
- if (persistedFormData.crop_management_plan.for_cover) {
- return [TERMINATION_DATE, t('MANAGEMENT_PLAN.TERMINATION_DATE')];
- } else {
- return [HARVEST_DATE, t('MANAGEMENT_PLAN.NEXT_HARVEST')];
- }
- }, []);
-
- const ESTIMATED_YIELD = 'crop_management_plan.estimated_yield';
- const ESTIMATED_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
-
- const { submitPath } = useMemo(
- () => getNextHarvestPaths(crop_variety.crop_variety_id, persistedFormData),
- [],
- );
- const onSubmit = () => history.push(submitPath);
- const onGoBack = () => history.goBack();
-
- const showEstimatedYield = !persistedFormData.crop_management_plan.for_cover;
-
- const todayStr = new Date().toISOString().substring(0, 10);
-
- return (
-
- );
-}
-
-PureNextHarvest.prototype = {
- system: PropTypes.string,
- persistedFormData: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- crop_variety: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.jsx b/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.jsx
new file mode 100644
index 0000000000..852a7470a5
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantingDate/NextHarvest.jsx
@@ -0,0 +1,128 @@
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import Button from '../../Form/Button';
+import Unit from '../../Form/Unit';
+import { Label } from '../../Typography';
+import Input from '../../Form/Input';
+import { seedYield } from '../../../util/convert-units/unit';
+import { cloneObject } from '../../../util';
+import styles from './styles.module.scss';
+import { getNextHarvestPaths } from '../getAddManagementPlanPath';
+
+export default function PureNextHarvest({
+ system,
+ persistedFormData,
+ useHookFormPersist,
+ crop_variety,
+ history,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ setError,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const progress = 37.5;
+
+ const HARVEST_DATE = 'crop_management_plan.harvest_date';
+ const TERMINATION_DATE = 'crop_management_plan.termination_date';
+ const [MAIN_DATE, title] = useMemo(() => {
+ if (persistedFormData.crop_management_plan.for_cover) {
+ return [TERMINATION_DATE, t('MANAGEMENT_PLAN.TERMINATION_DATE')];
+ } else {
+ return [HARVEST_DATE, t('MANAGEMENT_PLAN.NEXT_HARVEST')];
+ }
+ }, []);
+
+ const ESTIMATED_YIELD = 'crop_management_plan.estimated_yield';
+ const ESTIMATED_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
+
+ const { submitPath } = useMemo(
+ () => getNextHarvestPaths(crop_variety.crop_variety_id, persistedFormData),
+ [],
+ );
+ const onSubmit = () => history.push(submitPath);
+ const onGoBack = () => history.back();
+
+ const showEstimatedYield = !persistedFormData.crop_management_plan.for_cover;
+
+ const todayStr = new Date().toISOString().substring(0, 10);
+
+ return (
+
+ );
+}
+
+PureNextHarvest.prototype = {
+ system: PropTypes.string,
+ persistedFormData: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ crop_variety: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.js b/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.js
deleted file mode 100644
index 023387d5ea..0000000000
--- a/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.js
+++ /dev/null
@@ -1,433 +0,0 @@
-import Button from '../../Form/Button';
-import React, { useEffect, useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Info, Main } from '../../Typography';
-import Input, { getInputErrors } from '../../Form/Input';
-import Form from '../../Form';
-import { get, useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import InputDuration from '../../Form/InputDuration';
-import FullYearCalendarView from '../../FullYearCalendar';
-import { cloneObject } from '../../../util';
-import FullMonthCalendarView from '../../MonthCalendar';
-import { getDateDifference, getDateInputFormat, getLocalizedDateString } from '../../../util/moment';
-import { isNonNegativeNumber } from '../../Form/validations';
-import { getPlantingDatePaths } from '../getAddManagementPlanPath';
-import Unit from '../../Form/Unit';
-import { seedYield } from '../../../util/unit';
-
-export default function PurePlantingDate({
- useHookFormPersist,
- persistedFormData,
- crop_variety,
- history,
- system,
- language,
-}) {
- const { t } = useTranslation();
-
- const SEED_DATE = 'crop_management_plan.seed_date';
- const PLANT_DATE = 'crop_management_plan.plant_date';
- const GERMINATION_DATE = 'crop_management_plan.germination_date';
- const HARVEST_DATE = 'crop_management_plan.harvest_date';
- const TERMINATION_DATE = 'crop_management_plan.termination_date';
- const TRANSPLANT_DATE = 'crop_management_plan.transplant_date';
- const GERMINATION_DAYS = 'crop_management_plan.germination_days';
- const HARVEST_DAYS = 'crop_management_plan.harvest_days';
- const TRANSPLANT_DAYS = 'crop_management_plan.transplant_days';
- const TERMINATION_DAYS = 'crop_management_plan.termination_days';
- const ESTIMATED_YIELD = 'crop_management_plan.estimated_yield';
- const ESTIMATED_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
-
- const {
- already_in_ground,
- is_wild,
- for_cover,
- needs_transplant,
- is_seed,
- } = persistedFormData.crop_management_plan;
-
- const {
- harvestIsMain,
- terminationIsMain,
- transplantIsMain,
- seedIsMain,
- plantingIsMain,
- } = useMemo(
- () => ({
- seedIsMain: !already_in_ground && is_seed,
- plantingIsMain: !already_in_ground && !is_seed,
- transplantIsMain: already_in_ground && needs_transplant,
- harvestIsMain: already_in_ground && !needs_transplant && !is_wild && !for_cover,
- terminationIsMain: already_in_ground && !needs_transplant && !is_wild && for_cover,
- }),
- [],
- );
-
- const MAIN_DATE = useMemo(
- () =>
- seedIsMain
- ? SEED_DATE
- : plantingIsMain
- ? PLANT_DATE
- : transplantIsMain
- ? TRANSPLANT_DATE
- : harvestIsMain
- ? HARVEST_DATE
- : terminationIsMain
- ? TERMINATION_DATE
- : SEED_DATE,
- [],
- );
-
- const { dateTitle, dateLabel, dateOffsetTitle } = useMemo(() => {
- const titleMap = {
- [SEED_DATE]: t('MANAGEMENT_PLAN.SEED_DATE'),
- [PLANT_DATE]: t('MANAGEMENT_PLAN.PLANTING_DATE'),
- [TRANSPLANT_DATE]: t('MANAGEMENT_PLAN.TRANSPLANT_DATE'),
- [HARVEST_DATE]: t('MANAGEMENT_PLAN.HARVEST_DATE'),
- [TERMINATION_DATE]: t('MANAGEMENT_PLAN.TERMINATION_DATE'),
- };
- const dateTitle = titleMap[MAIN_DATE];
- const dateLabel = seedIsMain
- ? t('MANAGEMENT_PLAN.SEEDING_DATE')
- : plantingIsMain
- ? t('MANAGEMENT_PLAN.PLANTING_DATE_LABEL')
- : t('common:DATE');
-
- const subtitleMap = {
- [SEED_DATE]: t('MANAGEMENT_PLAN.DAYS_FROM_SEEDING'),
- [PLANT_DATE]: persistedFormData.crop_management_plan.seed_date
- ? t('MANAGEMENT_PLAN.DAYS_FROM_SEEDING')
- : t('MANAGEMENT_PLAN.DAYS_FROM_PLANTING'),
- [TRANSPLANT_DATE]: for_cover
- ? t('MANAGEMENT_PLAN.DAYS_TO_TERMINATION')
- : t('MANAGEMENT_PLAN.DAYS_TO_HARVEST'),
- };
- const dateOffsetTitle = subtitleMap[MAIN_DATE];
-
- return {
- dateTitle,
- dateLabel,
- dateOffsetTitle,
- };
- }, []);
-
- const {
- showGerminationOffset,
- showTransplantOffset,
- showHarvestTerminationOffset,
- showHarvestOffset,
- showTerminationOffset,
- showEstimatedYield,
- } = useMemo(
- () => ({
- // showGerminationOffset: !already_in_ground && (is_seed || (!for_cover && needs_transplant)),
- showGerminationOffset: !already_in_ground && is_seed,
- showTransplantOffset: needs_transplant && !transplantIsMain,
- showHarvestTerminationOffset: !harvestIsMain && !terminationIsMain,
- showHarvestOffset: !for_cover && !harvestIsMain && !terminationIsMain,
- showTerminationOffset: for_cover && !harvestIsMain && !terminationIsMain,
- showEstimatedYield: already_in_ground && is_wild && needs_transplant,
- }),
- [],
- );
-
- useEffect(() => {
- if (
- MAIN_DATE === SEED_DATE ||
- (MAIN_DATE === PLANT_DATE && persistedFormData.crop_management_plan.seed_date)
- ) {
- showGerminationOffset &&
- !germination_days &&
- crop_variety.germination_days &&
- setValue(GERMINATION_DAYS, crop_variety.germination_days);
- showTransplantOffset &&
- !transplant_days &&
- crop_variety.transplant_days &&
- setValue(TRANSPLANT_DAYS, crop_variety.transplant_days);
- showHarvestOffset &&
- !harvest_days &&
- crop_variety.harvest_days &&
- setValue(HARVEST_DAYS, crop_variety.harvest_days);
- showTerminationOffset &&
- !termination_days &&
- crop_variety.termination_days &&
- setValue(TERMINATION_DAYS, crop_variety.termination_days);
- }
- }, []);
-
- const {
- register,
- handleSubmit,
- getValues,
- setValue,
- watch,
- trigger,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const seed_date = watch(SEED_DATE);
- const plant_date = watch(PLANT_DATE);
- const main_date = watch(MAIN_DATE);
- const germination_date = watch(GERMINATION_DATE);
- const harvest_date = watch(HARVEST_DATE);
- const transplant_date = watch(TRANSPLANT_DATE);
- const termination_date = watch(TERMINATION_DATE);
- const germination_days = watch(GERMINATION_DAYS);
- const transplant_days = watch(TRANSPLANT_DAYS);
- const harvest_days = watch(HARVEST_DAYS);
- const termination_days = watch(TERMINATION_DAYS);
- const startDate = plantingIsMain && seed_date ? seed_date : main_date;
-
- const min = useMemo(() => {
- return plantingIsMain && seed_date ? getDateDifference(seed_date, plant_date) : 0;
- }, [plant_date]);
- const germinationDaysMax = needs_transplant ? 9997 : 9998;
- const transplantDaysMax = 9998;
- const harvestDaysMax = 9999;
- const transplantDaysMin = useMemo(() => {
- if (!showGerminationOffset) return min;
- return germination_days > germinationDaysMax ? germinationDaysMax : germination_days;
- }, [germination_days, min]);
- const harvestDaysMin = useMemo(() => {
- if (!showGerminationOffset && !showTransplantOffset) return min;
- const harvestDaysMin = (needs_transplant && transplant_days) || germination_days;
- return harvestDaysMin > transplantDaysMax ? transplantDaysMax : harvestDaysMin;
- }, [transplant_days, germination_days, needs_transplant, min]);
-
- useEffect(() => {
- if (showTransplantOffset && isNonNegativeNumber(transplant_days)) trigger(TRANSPLANT_DAYS);
- if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
- if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
- }, [germination_days]);
-
- useEffect(() => {
- if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
- if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
- }, [transplant_days]);
-
- useEffect(() => {
- if (plantingIsMain && seed_date && plant_date) {
- if (showGerminationOffset && isNonNegativeNumber(germination_days)) trigger(GERMINATION_DAYS);
- if (showTransplantOffset && isNonNegativeNumber(transplant_days)) trigger(TRANSPLANT_DAYS);
- if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
- if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
- }
- }, [plant_date]);
-
- useEffect(() => {
- if (plantingIsMain && seed_date && plant_date) {
- trigger(PLANT_DATE);
- }
- }, []);
-
- const getErrorMessage = (error, min, max) => {
- if (error?.type === 'isRequired') return t('common:REQUIRED');
- if (error?.type === 'max') return t('common:MAX_ERROR', { value: max });
- if (error?.type === 'min') return t('common:MIN_ERROR', { value: min });
- };
-
- const { submitPath } = useMemo(
- () => getPlantingDatePaths(crop_variety.crop_variety_id, persistedFormData),
- [],
- );
- const onSubmit = () => history.push(submitPath);
- const onGoBack = () => history.goBack();
-
- const onError = () => {};
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PurePlantingDate.prototype = {
- history: PropTypes.object,
- crop_variety: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.shape({
- crop_management_plan: PropTypes.shape({
- already_in_ground: PropTypes.bool,
- is_wild: PropTypes.bool,
- for_cover: PropTypes.bool,
- needs_transplant: PropTypes.bool,
- is_seed: PropTypes.bool,
- seed_date: PropTypes.string,
- plant_date: PropTypes.string,
- germination_date: PropTypes.string,
- transplant_date: PropTypes.string,
- termination_date: PropTypes.string,
- harvest_date: PropTypes.string,
- germination_days: PropTypes.number,
- transplant_days: PropTypes.number,
- termination_days: PropTypes.number,
- harvest_days: PropTypes.number,
- }),
- }),
-};
diff --git a/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.jsx b/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.jsx
new file mode 100644
index 0000000000..f262c92927
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantingDate/PurePlantingDate.jsx
@@ -0,0 +1,439 @@
+import Button from '../../Form/Button';
+import React, { useEffect, useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Info, Main } from '../../Typography';
+import Input, { getInputErrors } from '../../Form/Input';
+import Form from '../../Form';
+import { get, useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import InputDuration from '../../Form/InputDuration';
+import FullYearCalendarView from '../../FullYearCalendar';
+import { cloneObject } from '../../../util';
+import FullMonthCalendarView from '../../MonthCalendar';
+import {
+ getDateDifference,
+ getDateInputFormat,
+ getLocalizedDateString,
+} from '../../../util/moment';
+import { isNonNegativeNumber } from '../../Form/validations';
+import { getPlantingDatePaths } from '../getAddManagementPlanPath';
+import Unit from '../../Form/Unit';
+import { seedYield } from '../../../util/convert-units/unit';
+
+export default function PurePlantingDate({
+ useHookFormPersist,
+ persistedFormData,
+ crop_variety,
+ history,
+ system,
+ language,
+}) {
+ const { t } = useTranslation();
+
+ const SEED_DATE = 'crop_management_plan.seed_date';
+ const PLANT_DATE = 'crop_management_plan.plant_date';
+ const GERMINATION_DATE = 'crop_management_plan.germination_date';
+ const HARVEST_DATE = 'crop_management_plan.harvest_date';
+ const TERMINATION_DATE = 'crop_management_plan.termination_date';
+ const TRANSPLANT_DATE = 'crop_management_plan.transplant_date';
+ const GERMINATION_DAYS = 'crop_management_plan.germination_days';
+ const HARVEST_DAYS = 'crop_management_plan.harvest_days';
+ const TRANSPLANT_DAYS = 'crop_management_plan.transplant_days';
+ const TERMINATION_DAYS = 'crop_management_plan.termination_days';
+ const ESTIMATED_YIELD = 'crop_management_plan.estimated_yield';
+ const ESTIMATED_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
+
+ const { already_in_ground, is_wild, for_cover, needs_transplant, is_seed } =
+ persistedFormData.crop_management_plan;
+
+ const { harvestIsMain, terminationIsMain, transplantIsMain, seedIsMain, plantingIsMain } =
+ useMemo(
+ () => ({
+ seedIsMain: !already_in_ground && is_seed,
+ plantingIsMain: !already_in_ground && !is_seed,
+ transplantIsMain: already_in_ground && needs_transplant,
+ harvestIsMain: already_in_ground && !needs_transplant && !is_wild && !for_cover,
+ terminationIsMain: already_in_ground && !needs_transplant && !is_wild && for_cover,
+ }),
+ [],
+ );
+
+ const MAIN_DATE = useMemo(
+ () =>
+ seedIsMain
+ ? SEED_DATE
+ : plantingIsMain
+ ? PLANT_DATE
+ : transplantIsMain
+ ? TRANSPLANT_DATE
+ : harvestIsMain
+ ? HARVEST_DATE
+ : terminationIsMain
+ ? TERMINATION_DATE
+ : SEED_DATE,
+ [],
+ );
+
+ const { dateTitle, dateLabel, dateOffsetTitle } = useMemo(() => {
+ const titleMap = {
+ [SEED_DATE]: t('MANAGEMENT_PLAN.SEED_DATE'),
+ [PLANT_DATE]: t('MANAGEMENT_PLAN.PLANTING_DATE'),
+ [TRANSPLANT_DATE]: t('MANAGEMENT_PLAN.TRANSPLANT_DATE'),
+ [HARVEST_DATE]: t('MANAGEMENT_PLAN.HARVEST_DATE'),
+ [TERMINATION_DATE]: t('MANAGEMENT_PLAN.TERMINATION_DATE'),
+ };
+ const dateTitle = titleMap[MAIN_DATE];
+ const dateLabel = seedIsMain
+ ? t('MANAGEMENT_PLAN.SEEDING_DATE')
+ : plantingIsMain
+ ? t('MANAGEMENT_PLAN.PLANTING_DATE_LABEL')
+ : t('common:DATE');
+
+ const subtitleMap = {
+ [SEED_DATE]: t('MANAGEMENT_PLAN.DAYS_FROM_SEEDING'),
+ [PLANT_DATE]: persistedFormData.crop_management_plan.seed_date
+ ? t('MANAGEMENT_PLAN.DAYS_FROM_SEEDING')
+ : t('MANAGEMENT_PLAN.DAYS_FROM_PLANTING'),
+ [TRANSPLANT_DATE]: for_cover
+ ? t('MANAGEMENT_PLAN.DAYS_TO_TERMINATION')
+ : t('MANAGEMENT_PLAN.DAYS_TO_HARVEST'),
+ };
+ const dateOffsetTitle = subtitleMap[MAIN_DATE];
+
+ return {
+ dateTitle,
+ dateLabel,
+ dateOffsetTitle,
+ };
+ }, []);
+
+ const {
+ showGerminationOffset,
+ showTransplantOffset,
+ showHarvestTerminationOffset,
+ showHarvestOffset,
+ showTerminationOffset,
+ showEstimatedYield,
+ } = useMemo(
+ () => ({
+ // showGerminationOffset: !already_in_ground && (is_seed || (!for_cover && needs_transplant)),
+ showGerminationOffset: !already_in_ground && is_seed,
+ showTransplantOffset: needs_transplant && !transplantIsMain,
+ showHarvestTerminationOffset: !harvestIsMain && !terminationIsMain,
+ showHarvestOffset: !for_cover && !harvestIsMain && !terminationIsMain,
+ showTerminationOffset: for_cover && !harvestIsMain && !terminationIsMain,
+ showEstimatedYield: already_in_ground && is_wild && needs_transplant,
+ }),
+ [],
+ );
+
+ useEffect(() => {
+ if (
+ MAIN_DATE === SEED_DATE ||
+ (MAIN_DATE === PLANT_DATE && persistedFormData.crop_management_plan.seed_date)
+ ) {
+ showGerminationOffset &&
+ !germination_days &&
+ crop_variety.germination_days &&
+ setValue(GERMINATION_DAYS, crop_variety.germination_days);
+ showTransplantOffset &&
+ !transplant_days &&
+ crop_variety.transplant_days &&
+ setValue(TRANSPLANT_DAYS, crop_variety.transplant_days);
+ showHarvestOffset &&
+ !harvest_days &&
+ crop_variety.harvest_days &&
+ setValue(HARVEST_DAYS, crop_variety.harvest_days);
+ showTerminationOffset &&
+ !termination_days &&
+ crop_variety.termination_days &&
+ setValue(TERMINATION_DAYS, crop_variety.termination_days);
+ }
+ }, []);
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ setValue,
+ watch,
+ trigger,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const seed_date = watch(SEED_DATE);
+ const plant_date = watch(PLANT_DATE);
+ const main_date = watch(MAIN_DATE);
+ const germination_date = watch(GERMINATION_DATE);
+ const harvest_date = watch(HARVEST_DATE);
+ const transplant_date = watch(TRANSPLANT_DATE);
+ const termination_date = watch(TERMINATION_DATE);
+ const germination_days = watch(GERMINATION_DAYS);
+ const transplant_days = watch(TRANSPLANT_DAYS);
+ const harvest_days = watch(HARVEST_DAYS);
+ const termination_days = watch(TERMINATION_DAYS);
+ const startDate = plantingIsMain && seed_date ? seed_date : main_date;
+
+ const min = useMemo(() => {
+ return plantingIsMain && seed_date ? getDateDifference(seed_date, plant_date) : 0;
+ }, [plant_date]);
+ const germinationDaysMax = needs_transplant ? 9997 : 9998;
+ const transplantDaysMax = 9998;
+ const harvestDaysMax = 9999;
+ const transplantDaysMin = useMemo(() => {
+ if (!showGerminationOffset) return min;
+ return germination_days > germinationDaysMax ? germinationDaysMax : germination_days;
+ }, [germination_days, min]);
+ const harvestDaysMin = useMemo(() => {
+ if (!showGerminationOffset && !showTransplantOffset) return min;
+ const harvestDaysMin = (needs_transplant && transplant_days) || germination_days;
+ return harvestDaysMin > transplantDaysMax ? transplantDaysMax : harvestDaysMin;
+ }, [transplant_days, germination_days, needs_transplant, min]);
+
+ useEffect(() => {
+ if (showTransplantOffset && isNonNegativeNumber(transplant_days)) trigger(TRANSPLANT_DAYS);
+ if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
+ if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
+ }, [germination_days]);
+
+ useEffect(() => {
+ if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
+ if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
+ }, [transplant_days]);
+
+ useEffect(() => {
+ if (plantingIsMain && seed_date && plant_date) {
+ if (showGerminationOffset && isNonNegativeNumber(germination_days)) trigger(GERMINATION_DAYS);
+ if (showTransplantOffset && isNonNegativeNumber(transplant_days)) trigger(TRANSPLANT_DAYS);
+ if (showHarvestOffset && isNonNegativeNumber(harvest_days)) trigger(HARVEST_DAYS);
+ if (showTerminationOffset && isNonNegativeNumber(termination_days)) trigger(TERMINATION_DAYS);
+ }
+ }, [plant_date]);
+
+ useEffect(() => {
+ if (plantingIsMain && seed_date && plant_date) {
+ trigger(PLANT_DATE);
+ }
+ }, []);
+
+ const getErrorMessage = (error, min, max) => {
+ if (error?.type === 'isRequired') return t('common:REQUIRED');
+ if (error?.type === 'max') return t('common:MAX_ERROR', { value: max });
+ if (error?.type === 'min') return t('common:MIN_ERROR', { value: min });
+ };
+
+ const { submitPath } = useMemo(
+ () => getPlantingDatePaths(crop_variety.crop_variety_id, persistedFormData),
+ [],
+ );
+ const onSubmit = () => history.push(submitPath);
+ const onGoBack = () => history.back();
+
+ const onError = () => {};
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PurePlantingDate.prototype = {
+ history: PropTypes.object,
+ crop_variety: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.shape({
+ crop_management_plan: PropTypes.shape({
+ already_in_ground: PropTypes.bool,
+ is_wild: PropTypes.bool,
+ for_cover: PropTypes.bool,
+ needs_transplant: PropTypes.bool,
+ is_seed: PropTypes.bool,
+ seed_date: PropTypes.string,
+ plant_date: PropTypes.string,
+ germination_date: PropTypes.string,
+ transplant_date: PropTypes.string,
+ termination_date: PropTypes.string,
+ harvest_date: PropTypes.string,
+ germination_days: PropTypes.number,
+ transplant_days: PropTypes.number,
+ termination_days: PropTypes.number,
+ harvest_days: PropTypes.number,
+ }),
+ }),
+};
diff --git a/packages/webapp/src/components/Crop/PlantingDate/PurePlantingOrHarvestDate.js b/packages/webapp/src/components/Crop/PlantingDate/PurePlantingOrHarvestDate.jsx
similarity index 100%
rename from packages/webapp/src/components/Crop/PlantingDate/PurePlantingOrHarvestDate.js
rename to packages/webapp/src/components/Crop/PlantingDate/PurePlantingOrHarvestDate.jsx
diff --git a/packages/webapp/src/components/Crop/PlantingLocation/index.js b/packages/webapp/src/components/Crop/PlantingLocation/index.js
deleted file mode 100644
index ff94332dd3..0000000000
--- a/packages/webapp/src/components/Crop/PlantingLocation/index.js
+++ /dev/null
@@ -1,190 +0,0 @@
-import styles from './styles.module.scss';
-import React, { useEffect, useMemo, useState } from 'react';
-import PropTypes from 'prop-types';
-import Button from '../../Form/Button';
-import LocationPicker from '../../LocationPicker/SingleLocationPicker';
-import { useTranslation } from 'react-i18next';
-import Layout from '../../Layout';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { ReactComponent as Cross } from '../../../assets/images/map/cross.svg';
-import { ReactComponent as LocationPin } from '../../../assets/images/map/location.svg';
-import Checkbox from '../../Form/Checkbox';
-import { useForm } from 'react-hook-form';
-import { cloneObject } from '../../../util';
-import { getPlantingLocationPaths } from '../getAddManagementPlanPath';
-
-export default function PurePlantingLocation({
- persistedFormData,
- useHookFormPersist,
- isFinalLocationPage,
- variety_id,
- history,
- cropLocations,
- default_initial_location_id,
- farmCenterCoordinate,
-}) {
- const { t } = useTranslation(['translation', 'common', 'crop']);
- const { getValues, watch, setValue } = useForm({
- defaultValues: cloneObject(persistedFormData),
- shouldUnregister: false,
- });
- const { historyCancel } = useHookFormPersist(getValues);
-
- const {
- crop_management_plan: { needs_transplant, is_seed, is_wild, already_in_ground },
- } = persistedFormData;
- const showInitialLocationCheckbox = !isFinalLocationPage;
- const showPinButton = already_in_ground && is_wild && (!isFinalLocationPage || !needs_transplant);
- useEffect(() => {
- if (!already_in_ground || !is_wild) {
- setPinLocation(undefined);
- }
- }, []);
-
- const locationPrefix = isFinalLocationPage ? 'final' : 'initial';
- const LOCATION_ID = `crop_management_plan.planting_management_plans.${locationPrefix}.location_id`;
- const PIN_COORDINATE = `crop_management_plan.planting_management_plans.${locationPrefix}.pin_coordinate`;
- const DEFAULT_INITIAL_LOCATION_ID = 'farm.default_initial_location_id';
-
- const selectedLocationId = watch(LOCATION_ID);
- const pinCoordinate = watch(PIN_COORDINATE);
- const defaultInitialLocationId = watch(DEFAULT_INITIAL_LOCATION_ID);
-
- const setLocationId = (location_id) => {
- if (selectedLocationId === location_id) {
- setValue(LOCATION_ID, null);
- } else {
- setValue(LOCATION_ID, location_id);
- }
- if (showInitialLocationCheckbox && defaultInitialLocationId) {
- setValue(DEFAULT_INITIAL_LOCATION_ID, location_id);
- }
- };
- useEffect(() => {
- if (!(already_in_ground && is_wild) && !isFinalLocationPage && !selectedLocationId) {
- setLocationId(default_initial_location_id);
- setValue(DEFAULT_INITIAL_LOCATION_ID, default_initial_location_id);
- }
- }, []);
-
- const setPinLocation = (coordinate) => setValue(PIN_COORDINATE, coordinate);
- const defaultLocationCheckboxOnChange = () => {
- if (defaultInitialLocationId) {
- setValue(DEFAULT_INITIAL_LOCATION_ID, undefined);
- } else {
- setValue(DEFAULT_INITIAL_LOCATION_ID, selectedLocationId);
- }
- };
-
- const plantingLabel = useMemo(() => {
- if (needs_transplant && isFinalLocationPage) {
- return t('MANAGEMENT_PLAN.WHERE_TRANSPLANT_LOCATION');
- } else if (already_in_ground && (!needs_transplant || !isFinalLocationPage)) {
- return t('MANAGEMENT_PLAN.SELECT_CURRENT_LOCATION');
- } else if (needs_transplant && !isFinalLocationPage) {
- return t('MANAGEMENT_PLAN.WHERE_START_LOCATION');
- } else if (is_seed) {
- return t('MANAGEMENT_PLAN.SELECT_A_SEEDING_LOCATION');
- } else {
- return t('MANAGEMENT_PLAN.SELECT_A_PLANTING_LOCATION');
- }
- }, [needs_transplant, isFinalLocationPage]);
-
- const [pinToggle, setPinToggle] = useState(!!pinCoordinate && showPinButton);
- useEffect(() => {
- setPinToggle(!!pinCoordinate && showPinButton);
- }, [showPinButton]);
-
- const handlePinMode = () => {
- setPinToggle((pinToggle) => !pinToggle);
- };
-
- const onSubmit = () =>
- history.push(
- getPlantingLocationPaths(variety_id, persistedFormData, isFinalLocationPage).submitPath,
- );
- const onGoBack = () =>
- history.goBack();
-
-
- return (
- <>
-
-
- {t('common:CONTINUE')}
-
- >
- }
- >
-
-
- {plantingLabel}
-
-
-
-
-
{t('MANAGEMENT_PLAN.LOCATION_SUBTEXT')}
-
-
- {showPinButton && pinToggle && (
-
-
- {t('MANAGEMENT_PLAN.REMOVE_PIN')}
-
- )}
- {showPinButton && !pinToggle && (
-
-
- {t('MANAGEMENT_PLAN.DROP_PIN')}
-
- )}
-
- {showInitialLocationCheckbox && !!selectedLocationId && (
-
- )}
-
- >
- );
-}
-
-PurePlantingLocation.prototype = {
- persistedFormData: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- isFinalLocationPage: PropTypes.bool,
- variety_id: PropTypes.string,
- history: PropTypes.object,
- locations: PropTypes.object,
- farmCenterCoordinate: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/PlantingLocation/index.jsx b/packages/webapp/src/components/Crop/PlantingLocation/index.jsx
new file mode 100644
index 0000000000..18b69ac715
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantingLocation/index.jsx
@@ -0,0 +1,197 @@
+import styles from './styles.module.scss';
+import React, { useEffect, useMemo, useState } from 'react';
+import PropTypes from 'prop-types';
+import Button from '../../Form/Button';
+import LocationPicker from '../../LocationPicker/SingleLocationPicker';
+import { useTranslation } from 'react-i18next';
+import Layout from '../../Layout';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { ReactComponent as Cross } from '../../../assets/images/map/cross.svg';
+import { ReactComponent as LocationPin } from '../../../assets/images/map/location.svg';
+import Checkbox from '../../Form/Checkbox';
+import { useForm } from 'react-hook-form';
+import { cloneObject } from '../../../util';
+import { getPlantingLocationPaths } from '../getAddManagementPlanPath';
+
+export default function PurePlantingLocation({
+ persistedFormData,
+ useHookFormPersist,
+ isFinalLocationPage,
+ variety_id,
+ history,
+ cropLocations,
+ default_initial_location_id,
+ farmCenterCoordinate,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'crop']);
+ const { getValues, watch, setValue } = useForm({
+ defaultValues: cloneObject(persistedFormData),
+ shouldUnregister: false,
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const {
+ crop_management_plan: { needs_transplant, is_seed, is_wild, already_in_ground },
+ } = persistedFormData;
+ const showInitialLocationCheckbox = !isFinalLocationPage;
+ const showPinButton = already_in_ground && is_wild && (!isFinalLocationPage || !needs_transplant);
+ useEffect(() => {
+ if (!already_in_ground || !is_wild) {
+ setPinLocation(undefined);
+ }
+ }, []);
+
+ const locationPrefix = isFinalLocationPage ? 'final' : 'initial';
+ const LOCATION_ID = `crop_management_plan.planting_management_plans.${locationPrefix}.location_id`;
+ const PIN_COORDINATE = `crop_management_plan.planting_management_plans.${locationPrefix}.pin_coordinate`;
+ const DEFAULT_INITIAL_LOCATION_ID = 'farm.default_initial_location_id';
+
+ const selectedLocationId = watch(LOCATION_ID);
+ const pinCoordinate = watch(PIN_COORDINATE);
+ const defaultInitialLocationId = watch(DEFAULT_INITIAL_LOCATION_ID);
+
+ const setLocationId = (location_id) => {
+ if (selectedLocationId === location_id) {
+ setValue(LOCATION_ID, null);
+ } else {
+ setValue(LOCATION_ID, location_id);
+ }
+ if (showInitialLocationCheckbox && defaultInitialLocationId) {
+ setValue(DEFAULT_INITIAL_LOCATION_ID, location_id);
+ }
+ };
+ useEffect(() => {
+ if (!(already_in_ground && is_wild) && !isFinalLocationPage && !selectedLocationId) {
+ setLocationId(default_initial_location_id);
+ setValue(DEFAULT_INITIAL_LOCATION_ID, default_initial_location_id);
+ }
+ }, []);
+
+ const setPinLocation = (coordinate) => setValue(PIN_COORDINATE, coordinate);
+ const defaultLocationCheckboxOnChange = () => {
+ if (defaultInitialLocationId) {
+ setValue(DEFAULT_INITIAL_LOCATION_ID, undefined);
+ } else {
+ setValue(DEFAULT_INITIAL_LOCATION_ID, selectedLocationId);
+ }
+ };
+
+ const plantingLabel = useMemo(() => {
+ if (needs_transplant && isFinalLocationPage) {
+ return t('MANAGEMENT_PLAN.WHERE_TRANSPLANT_LOCATION');
+ } else if (already_in_ground && (!needs_transplant || !isFinalLocationPage)) {
+ return t('MANAGEMENT_PLAN.SELECT_CURRENT_LOCATION');
+ } else if (needs_transplant && !isFinalLocationPage) {
+ return t('MANAGEMENT_PLAN.WHERE_START_LOCATION');
+ } else if (is_seed) {
+ return t('MANAGEMENT_PLAN.SELECT_A_SEEDING_LOCATION');
+ } else {
+ return t('MANAGEMENT_PLAN.SELECT_A_PLANTING_LOCATION');
+ }
+ }, [needs_transplant, isFinalLocationPage]);
+
+ const [pinToggle, setPinToggle] = useState(!!pinCoordinate && showPinButton);
+ useEffect(() => {
+ setPinToggle(!!pinCoordinate && showPinButton);
+ }, [showPinButton]);
+
+ const handlePinMode = () => {
+ setPinToggle((pinToggle) => !pinToggle);
+ };
+
+ const onSubmit = () =>
+ history.push(
+ getPlantingLocationPaths(variety_id, persistedFormData, isFinalLocationPage).submitPath,
+ );
+ const onGoBack = () => {
+ history.back();
+ ``;
+ };
+
+ return (
+ <>
+
+
+ {t('common:CONTINUE')}
+
+ >
+ }
+ >
+
+
+ {plantingLabel}
+
+
+
+
+
{t('MANAGEMENT_PLAN.LOCATION_SUBTEXT')}
+
+
+ {showPinButton && pinToggle && (
+
+
+ {t('MANAGEMENT_PLAN.REMOVE_PIN')}
+
+ )}
+ {showPinButton && !pinToggle && (
+
+
+ {t('MANAGEMENT_PLAN.DROP_PIN')}
+
+ )}
+
+ {showInitialLocationCheckbox && !!selectedLocationId && (
+
+ )}
+
+ >
+ );
+}
+
+PurePlantingLocation.prototype = {
+ persistedFormData: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ isFinalLocationPage: PropTypes.bool,
+ variety_id: PropTypes.string,
+ history: PropTypes.object,
+ locations: PropTypes.object,
+ farmCenterCoordinate: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.js b/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.js
deleted file mode 100644
index 06c18d366d..0000000000
--- a/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.js
+++ /dev/null
@@ -1,165 +0,0 @@
-import Button from '../../Form/Button';
-import React, { useMemo } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import RadioGroup from '../../Form/RadioGroup';
-import { cloneObject } from '../../../util';
-import Unit from '../../Form/Unit';
-import { seedYield } from '../../../util/unit';
-import { getPlantingMethodPaths } from '../getAddManagementPlanPath';
-import { PurePlantingMethod } from './PurePlantingMethod';
-
-export default function PureManagementPlanPlantingMethod({
- useHookFormPersist,
- persistedFormData,
- match,
- history,
- isFinalPlantingMethod,
- system,
-}) {
- const { t } = useTranslation();
- const variety_id = match?.params?.variety_id;
-
- const { showBroadcast, showIsPlantingMethodKnown } = useMemo(() => {
- const {
- already_in_ground,
- is_wild,
- for_cover,
- needs_transplant,
- is_seed,
- } = persistedFormData.crop_management_plan;
- const showIsPlantingMethodKnown =
- (already_in_ground && !is_wild && for_cover && !needs_transplant && isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && !for_cover && !needs_transplant && isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && for_cover && needs_transplant && !isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && !for_cover && needs_transplant && !isFinalPlantingMethod);
- const showBroadcast =
- (!already_in_ground && is_seed && needs_transplant && !isFinalPlantingMethod) ||
- (!already_in_ground && is_seed && !needs_transplant && isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && !for_cover && needs_transplant && !isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && for_cover && needs_transplant && !isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && !for_cover && !needs_transplant && isFinalPlantingMethod) ||
- (already_in_ground && !is_wild && for_cover && !needs_transplant && isFinalPlantingMethod);
- return { showBroadcast, showIsPlantingMethodKnown };
- }, []);
-
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- setError,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
- const plantingMethodPrefix = `crop_management_plan.planting_management_plans.${
- isFinalPlantingMethod ? 'final' : 'initial'
- }`;
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
- const PLANTING_METHOD = `${plantingMethodPrefix}.planting_method`;
- const planting_method = watch(PLANTING_METHOD);
- const IS_PLANTING_METHOD_KNOWN = `${plantingMethodPrefix}.is_planting_method_known`;
- const is_planting_method_known = watch(IS_PLANTING_METHOD_KNOWN);
- const { historyCancel } = useHookFormPersist(getValues);
-
- const onError = () => {};
-
- const onSubmit = () =>
- history.push(
- getPlantingMethodPaths(
- variety_id,
- persistedFormData,
- isFinalPlantingMethod,
- planting_method,
- is_planting_method_known,
- ).submitPath,
- );
- const onGoBack = () =>
- history.goBack();
-
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PureManagementPlanPlantingMethod.prototype = {
- history: PropTypes.object,
- match: PropTypes.object,
- onSubmit: PropTypes.func,
- onError: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.shape({
- crop_management_plan: PropTypes.shape({
- already_in_ground: PropTypes.bool,
- is_wild: PropTypes.bool,
- for_cover: PropTypes.bool,
- needs_transplant: PropTypes.bool,
- is_seed: PropTypes.bool,
- }),
- }),
-};
diff --git a/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.jsx b/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.jsx
new file mode 100644
index 0000000000..869ac01245
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantingMethod/PureManagementPlanPlantingMethod.jsx
@@ -0,0 +1,158 @@
+import Button from '../../Form/Button';
+import React, { useMemo } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import RadioGroup from '../../Form/RadioGroup';
+import { cloneObject } from '../../../util';
+import Unit from '../../Form/Unit';
+import { seedYield } from '../../../util/convert-units/unit';
+import { getPlantingMethodPaths } from '../getAddManagementPlanPath';
+import { PurePlantingMethod } from './PurePlantingMethod';
+
+export default function PureManagementPlanPlantingMethod({
+ useHookFormPersist,
+ persistedFormData,
+ match,
+ history,
+ isFinalPlantingMethod,
+ system,
+}) {
+ const { t } = useTranslation();
+ const variety_id = match?.params?.variety_id;
+
+ const { showBroadcast, showIsPlantingMethodKnown } = useMemo(() => {
+ const { already_in_ground, is_wild, for_cover, needs_transplant, is_seed } =
+ persistedFormData.crop_management_plan;
+ const showIsPlantingMethodKnown =
+ (already_in_ground && !is_wild && for_cover && !needs_transplant && isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && !for_cover && !needs_transplant && isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && for_cover && needs_transplant && !isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && !for_cover && needs_transplant && !isFinalPlantingMethod);
+ const showBroadcast =
+ (!already_in_ground && is_seed && needs_transplant && !isFinalPlantingMethod) ||
+ (!already_in_ground && is_seed && !needs_transplant && isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && !for_cover && needs_transplant && !isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && for_cover && needs_transplant && !isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && !for_cover && !needs_transplant && isFinalPlantingMethod) ||
+ (already_in_ground && !is_wild && for_cover && !needs_transplant && isFinalPlantingMethod);
+ return { showBroadcast, showIsPlantingMethodKnown };
+ }, []);
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ setError,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+ const plantingMethodPrefix = `crop_management_plan.planting_management_plans.${
+ isFinalPlantingMethod ? 'final' : 'initial'
+ }`;
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+ const PLANTING_METHOD = `${plantingMethodPrefix}.planting_method`;
+ const planting_method = watch(PLANTING_METHOD);
+ const IS_PLANTING_METHOD_KNOWN = `${plantingMethodPrefix}.is_planting_method_known`;
+ const is_planting_method_known = watch(IS_PLANTING_METHOD_KNOWN);
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const onError = () => {};
+
+ const onSubmit = () =>
+ history.push(
+ getPlantingMethodPaths(
+ variety_id,
+ persistedFormData,
+ isFinalPlantingMethod,
+ planting_method,
+ is_planting_method_known,
+ ).submitPath,
+ );
+ const onGoBack = () => history.back();
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PureManagementPlanPlantingMethod.prototype = {
+ history: PropTypes.object,
+ match: PropTypes.object,
+ onSubmit: PropTypes.func,
+ onError: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.shape({
+ crop_management_plan: PropTypes.shape({
+ already_in_ground: PropTypes.bool,
+ is_wild: PropTypes.bool,
+ for_cover: PropTypes.bool,
+ needs_transplant: PropTypes.bool,
+ is_seed: PropTypes.bool,
+ }),
+ }),
+};
diff --git a/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.js b/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.js
deleted file mode 100644
index 727a0a494d..0000000000
--- a/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import RadioGroup from '../../Form/RadioGroup';
-import styles from './styles.module.scss';
-import { ReactComponent as Individual } from '../../../assets/images/plantingMethod/Individual.svg';
-import { ReactComponent as Rows } from '../../../assets/images/plantingMethod/Rows.svg';
-
-import { ReactComponent as Beds } from '../../../assets/images/plantingMethod/Beds.svg';
-import { ReactComponent as Monocrop } from '../../../assets/images/plantingMethod/Monocrop.svg';
-import { DO_CDN_URL } from '../../../util/constants';
-import ImageModal from '../../Modals/ImageModal';
-
-const BROADCAST = 'BROADCAST_METHOD';
-const CONTAINER = 'CONTAINER_METHOD';
-const BEDS = 'BED_METHOD';
-const ROWS = 'ROW_METHOD';
-const images = {
- [BROADCAST]: [
- `${DO_CDN_URL}/planting_method/Broadcast_1.webp`,
- `${DO_CDN_URL}/planting_method/Broadcast_2.webp`,
- `${DO_CDN_URL}/planting_method/Broadcast_3.webp`,
- ],
- [CONTAINER]: [
- `${DO_CDN_URL}/planting_method/Individual_1.webp`,
- `${DO_CDN_URL}/planting_method/Individual_2.webp`,
- `${DO_CDN_URL}/planting_method/Individual_3.webp`,
- ],
- [BEDS]: [
- `${DO_CDN_URL}/planting_method/Bed_1.webp`,
- `${DO_CDN_URL}/planting_method/Bed_2.webp`,
- `${DO_CDN_URL}/planting_method/Bed_3.webp`,
- ],
- [ROWS]: [
- `${DO_CDN_URL}/planting_method/Rows_1.webp`,
- `${DO_CDN_URL}/planting_method/Rows_2.webp`,
- `${DO_CDN_URL}/planting_method/Rows_3.webp`,
- ],
-};
-
-export function PurePlantingMethod({
- showBroadcast,
- planting_method,
- PLANTING_METHOD,
- control,
- title,
-}) {
- const { t } = useTranslation();
-
- const [{ imageModalSrc, imageModalAlt }, setSelectedImage] = useState({});
- const onImageSelect = (src, alt) => setSelectedImage({ imageModalSrc: src, imageModalAlt: alt });
- const dismissModal = () => setSelectedImage({});
-
- return (
- <>
-
- {title}
-
-
-
-
-
-
-
- {showBroadcast && }
-
-
- {planting_method && (
-
- {images[planting_method].map((url, index) => (
-
onImageSelect(url, planting_method)}
- />
- ))}
-
- )}
- {imageModalSrc && (
-
- )}
- >
- );
-}
-
-PurePlantingMethod.prototype = {
- showBroadcast: PropTypes.bool,
- planting_method: PropTypes.string,
- PLANTING_METHOD: PropTypes.string,
- control: PropTypes.any,
- plantingMethodPrefix: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.jsx b/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.jsx
new file mode 100644
index 0000000000..d7c106c456
--- /dev/null
+++ b/packages/webapp/src/components/Crop/PlantingMethod/PurePlantingMethod.jsx
@@ -0,0 +1,114 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import RadioGroup from '../../Form/RadioGroup';
+import styles from './styles.module.scss';
+import { ReactComponent as Individual } from '../../../assets/images/plantingMethod/Individual.svg';
+import { ReactComponent as Rows } from '../../../assets/images/plantingMethod/Rows.svg';
+
+import { ReactComponent as Beds } from '../../../assets/images/plantingMethod/Beds.svg';
+import { ReactComponent as Monocrop } from '../../../assets/images/plantingMethod/Monocrop.svg';
+import { DO_CDN_URL } from '../../../util/constants';
+import ImageModal from '../../Modals/ImageModal';
+
+const BROADCAST = 'BROADCAST_METHOD';
+const CONTAINER = 'CONTAINER_METHOD';
+const BEDS = 'BED_METHOD';
+const ROWS = 'ROW_METHOD';
+const images = {
+ [BROADCAST]: [
+ `${DO_CDN_URL}/planting_method/Broadcast_1.webp`,
+ `${DO_CDN_URL}/planting_method/Broadcast_2.webp`,
+ `${DO_CDN_URL}/planting_method/Broadcast_3.webp`,
+ ],
+ [CONTAINER]: [
+ `${DO_CDN_URL}/planting_method/Individual_1.webp`,
+ `${DO_CDN_URL}/planting_method/Individual_2.webp`,
+ `${DO_CDN_URL}/planting_method/Individual_3.webp`,
+ ],
+ [BEDS]: [
+ `${DO_CDN_URL}/planting_method/Bed_1.webp`,
+ `${DO_CDN_URL}/planting_method/Bed_2.webp`,
+ `${DO_CDN_URL}/planting_method/Bed_3.webp`,
+ ],
+ [ROWS]: [
+ `${DO_CDN_URL}/planting_method/Rows_1.webp`,
+ `${DO_CDN_URL}/planting_method/Rows_2.webp`,
+ `${DO_CDN_URL}/planting_method/Rows_3.webp`,
+ ],
+};
+
+export function PurePlantingMethod({
+ showBroadcast,
+ planting_method,
+ PLANTING_METHOD,
+ control,
+ title,
+}) {
+ const { t } = useTranslation();
+
+ const [{ imageModalSrc, imageModalAlt }, setSelectedImage] = useState({});
+ const onImageSelect = (src, alt) => setSelectedImage({ imageModalSrc: src, imageModalAlt: alt });
+ const dismissModal = () => setSelectedImage({});
+
+ return (
+ <>
+
+ {title}
+
+
+
+
+
+
+
+ {showBroadcast && }
+
+
+ {planting_method && (
+
+ {images[planting_method].map((url, index) => (
+
onImageSelect(url, planting_method)}
+ />
+ ))}
+
+ )}
+ {imageModalSrc && (
+
+ )}
+ >
+ );
+}
+
+PurePlantingMethod.prototype = {
+ showBroadcast: PropTypes.bool,
+ planting_method: PropTypes.string,
+ PLANTING_METHOD: PropTypes.string,
+ control: PropTypes.any,
+ plantingMethodPrefix: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Crop/RowMethod/PureRowForm.js b/packages/webapp/src/components/Crop/RowMethod/PureRowForm.js
deleted file mode 100644
index 38af49cc6a..0000000000
--- a/packages/webapp/src/components/Crop/RowMethod/PureRowForm.js
+++ /dev/null
@@ -1,220 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
-import { container_plant_spacing, length_of_bed_or_row, seedYield } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import RadioGroup from '../../Form/RadioGroup';
-import PropTypes from 'prop-types';
-import clsx from 'clsx';
-import { Main } from '../../Typography';
-
-export default function PureRowForm({
- system,
- crop_variety,
- isFinalPage,
- isHistoricalPage,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- register,
- getValues,
- watch,
- control,
- setValue,
- errors,
- disabled,
-}) {
- const { t } = useTranslation(['translation']);
-
- const SAME_LENGTH = `${prefix}.row_method.same_length`;
- const NUMBER_OF_ROWS = `${prefix}.row_method.number_of_rows`;
- const LENGTH_OF_ROW = `${prefix}.row_method.row_length`;
- const LENGTH_OF_ROW_UNIT = `${prefix}.row_method.row_length_unit`;
- const PLANT_SPACING = `${prefix}.row_method.plant_spacing`;
- const PLANT_SPACING_UNIT = `${prefix}.row_method.plant_spacing_unit`;
- const TOTAL_LENGTH = `${prefix}.row_method.total_rows_length`;
- const TOTAL_LENGTH_UNIT = `${prefix}.row_method.total_rows_length_unit`;
- const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
- const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
- const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
- const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
-
- const same_length = watch(SAME_LENGTH);
- const num_of_rows = watch(NUMBER_OF_ROWS);
- const length_of_row = watch(LENGTH_OF_ROW);
- const total_length = watch(TOTAL_LENGTH);
- const plant_spacing = watch(PLANT_SPACING);
-
- const IsValidNumberInput = (number) => number === 0 || number > 0;
-
- const [showEstimatedValue, setShowEstimatedValue] = useState(false);
- const shouldSkipEstimatedValueCalculationRef = useRef(true);
-
- useEffect(() => {
- const { average_seed_weight = 0, yield_per_plant = 0 } = crop_variety;
- const shouldCalculatedSameLengthEstimatedValues =
- same_length &&
- IsValidNumberInput(num_of_rows) &&
- IsValidNumberInput(length_of_row) &&
- IsValidNumberInput(plant_spacing);
- const shouldCalculateDifferentLengthEstimatedValues =
- !same_length && IsValidNumberInput(total_length) && IsValidNumberInput(plant_spacing);
- if (shouldSkipEstimatedValueCalculationRef.current) {
- shouldSkipEstimatedValueCalculationRef.current = false;
- setShowEstimatedValue(
- shouldCalculatedSameLengthEstimatedValues || shouldCalculateDifferentLengthEstimatedValues,
- );
- } else if (shouldCalculatedSameLengthEstimatedValues) {
- const estimated_seed_required =
- ((num_of_rows * length_of_row) / plant_spacing) * average_seed_weight;
- const estimated_yield = ((num_of_rows * length_of_row) / plant_spacing) * yield_per_plant;
- average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required);
- yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
- setShowEstimatedValue(true);
- } else if (shouldCalculateDifferentLengthEstimatedValues) {
- const estimated_seed_required = (total_length / plant_spacing) * average_seed_weight;
- const estimated_yield = (total_length / plant_spacing) * yield_per_plant;
- average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required);
- yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
- setShowEstimatedValue(true);
- } else {
- setShowEstimatedValue(false);
- }
- }, [num_of_rows, length_of_row, total_length, plant_spacing, same_length]);
- const showEstimatedYield = prefix.endsWith('final');
-
- return (
- <>
-
- {isHistoricalPage
- ? t('MANAGEMENT_PLAN.ROW_METHOD.HISTORICAL_SAME_LENGTH')
- : t('MANAGEMENT_PLAN.ROW_METHOD.SAME_LENGTH')}
-
-
- {(same_length === true || same_length === false) && (
- <>
- {same_length && (
- <>
-
-
-
-
- >
- )}
- {!same_length && (
-
-
-
- )}
-
-
-
- {showEstimatedValue && (
- <>
-
-
- {showEstimatedYield && (
-
- )}
-
- >
- )}
- >
- )}
- >
- );
-}
-
-PureRowForm.prototype = {
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- isHistoricalPage: PropTypes.bool,
- prefix: PropTypes.string,
- register: PropTypes.func,
- getValues: PropTypes.func,
- watch: PropTypes.func,
- control: PropTypes.any,
- setValue: PropTypes.func,
- errors: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/RowMethod/PureRowForm.jsx b/packages/webapp/src/components/Crop/RowMethod/PureRowForm.jsx
new file mode 100644
index 0000000000..66b69cd5ee
--- /dev/null
+++ b/packages/webapp/src/components/Crop/RowMethod/PureRowForm.jsx
@@ -0,0 +1,253 @@
+import React, { useEffect, useRef, useState } from 'react';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors, integerOnKeyDown } from '../../Form/Input';
+import {
+ container_plant_spacing,
+ length_of_bed_or_row,
+ seedYield,
+} from '../../../util/convert-units/unit';
+import Unit from '../../Form/Unit';
+import RadioGroup from '../../Form/RadioGroup';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import { Main } from '../../Typography';
+
+export default function PureRowForm({
+ system,
+ crop_variety,
+ isFinalPage,
+ isHistoricalPage,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ register,
+ getValues,
+ watch,
+ control,
+ setValue,
+ errors,
+ disabled,
+}) {
+ const { t } = useTranslation(['translation']);
+
+ const SAME_LENGTH = `${prefix}.row_method.same_length`;
+ const NUMBER_OF_ROWS = `${prefix}.row_method.number_of_rows`;
+ const LENGTH_OF_ROW = `${prefix}.row_method.row_length`;
+ const LENGTH_OF_ROW_UNIT = `${prefix}.row_method.row_length_unit`;
+ const PLANT_SPACING = `${prefix}.row_method.plant_spacing`;
+ const PLANT_SPACING_UNIT = `${prefix}.row_method.plant_spacing_unit`;
+ const TOTAL_LENGTH = `${prefix}.row_method.total_rows_length`;
+ const TOTAL_LENGTH_UNIT = `${prefix}.row_method.total_rows_length_unit`;
+ const ESTIMATED_SEED = `${prefix}.estimated_seeds`;
+ const ESTIMATED_SEED_UNIT = `${prefix}.estimated_seeds_unit`;
+ const ESTIMATED_YIELD = `crop_management_plan.estimated_yield`;
+ const ESTIMATED_YIELD_UNIT = `crop_management_plan.estimated_yield_unit`;
+
+ const same_length = watch(SAME_LENGTH);
+ const num_of_rows = watch(NUMBER_OF_ROWS);
+ const length_of_row = watch(LENGTH_OF_ROW);
+ const total_length = watch(TOTAL_LENGTH);
+ const plant_spacing = watch(PLANT_SPACING);
+
+ const IsValidNumberInput = (number) => number === 0 || number > 0;
+
+ /**
+ * Calculates the plant count in one row given length of the row and plant spacing.
+ * If length is perfectly divisible by spacing (i.e. 5m spacing in a 10m row),
+ * you can plant 3 crops (at 0m, 5m, and 10m).
+ * Otherwise (i.e. 6m spacing in a 10m row), you can plant only 2 crops (at 0m and 6m).
+ * @param {number} length
+ * @param {number} spacing
+ * @returns {number} plant count
+ */
+ const calculatePlantCountPerRow = (length, spacing) => {
+ if (!(length % spacing)) {
+ return (length + spacing) / spacing;
+ } else {
+ return Math.ceil(length / spacing);
+ }
+ };
+
+ const [showEstimatedValue, setShowEstimatedValue] = useState(false);
+ const shouldSkipEstimatedValueCalculationRef = useRef(true);
+
+ useEffect(() => {
+ const { average_seed_weight = 0, yield_per_plant = 0 } = crop_variety;
+ const shouldCalculatedSameLengthEstimatedValues =
+ same_length &&
+ IsValidNumberInput(num_of_rows) &&
+ IsValidNumberInput(length_of_row) &&
+ IsValidNumberInput(plant_spacing);
+ const shouldCalculateDifferentLengthEstimatedValues =
+ !same_length && IsValidNumberInput(total_length) && IsValidNumberInput(plant_spacing);
+ if (shouldSkipEstimatedValueCalculationRef.current) {
+ shouldSkipEstimatedValueCalculationRef.current = false;
+ setShowEstimatedValue(
+ shouldCalculatedSameLengthEstimatedValues || shouldCalculateDifferentLengthEstimatedValues,
+ );
+ } else if (shouldCalculatedSameLengthEstimatedValues) {
+ const plantCountPerRow = calculatePlantCountPerRow(length_of_row, plant_spacing);
+ const estimated_seed_required = plantCountPerRow * num_of_rows * average_seed_weight;
+ const estimated_yield = plantCountPerRow * num_of_rows * yield_per_plant;
+ average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required);
+ yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
+ setShowEstimatedValue(true);
+ } else if (shouldCalculateDifferentLengthEstimatedValues) {
+ const totalPlantCount = calculatePlantCountPerRow(total_length, plant_spacing);
+ const estimated_seed_required = totalPlantCount * average_seed_weight;
+ const estimated_yield = totalPlantCount * yield_per_plant;
+ average_seed_weight && setValue(ESTIMATED_SEED, estimated_seed_required);
+ yield_per_plant && setValue(ESTIMATED_YIELD, estimated_yield);
+ setShowEstimatedValue(true);
+ } else {
+ setShowEstimatedValue(false);
+ }
+ }, [num_of_rows, length_of_row, total_length, plant_spacing, same_length]);
+ const showEstimatedYield = prefix.endsWith('final');
+
+ return (
+ <>
+
+ {isHistoricalPage
+ ? t('MANAGEMENT_PLAN.ROW_METHOD.HISTORICAL_SAME_LENGTH')
+ : t('MANAGEMENT_PLAN.ROW_METHOD.SAME_LENGTH')}
+
+
+ {(same_length === true || same_length === false) && (
+ <>
+ {same_length && (
+ <>
+
+
+
+
+ >
+ )}
+ {!same_length && (
+
+
+
+ )}
+
+
+
+ {showEstimatedValue && (
+ <>
+
+
+ {showEstimatedYield && (
+
+ )}
+
+ >
+ )}
+ >
+ )}
+ >
+ );
+}
+
+PureRowForm.prototype = {
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ isHistoricalPage: PropTypes.bool,
+ prefix: PropTypes.string,
+ register: PropTypes.func,
+ getValues: PropTypes.func,
+ watch: PropTypes.func,
+ control: PropTypes.any,
+ setValue: PropTypes.func,
+ errors: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Crop/RowMethod/index.js b/packages/webapp/src/components/Crop/RowMethod/index.js
deleted file mode 100644
index 9066be4426..0000000000
--- a/packages/webapp/src/components/Crop/RowMethod/index.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import PropTypes from 'prop-types';
-import PureRowForm from './PureRowForm';
-
-export default function PureRowMethod({
- system,
- crop_variety,
- useHookFormPersist,
- persistedFormData,
- isFinalPage,
- history,
- prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
- submitPath,
- onGoBack = () => history.goBack(),
- isHistoricalPage,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- shouldUnregister: false,
- mode: 'onChange',
- defaultValues: cloneObject(persistedFormData),
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const onSubmit = () => history.push(submitPath);
-
- return (
-
- );
-}
-
-PureRowMethod.prototype = {
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
- crop_variety: PropTypes.object,
- system: PropTypes.oneOf(['imperial', 'metric']),
- isFinalPage: PropTypes.bool,
- history: PropTypes.object,
- submitPath: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/Crop/RowMethod/index.jsx b/packages/webapp/src/components/Crop/RowMethod/index.jsx
new file mode 100644
index 0000000000..97d3df3b3e
--- /dev/null
+++ b/packages/webapp/src/components/Crop/RowMethod/index.jsx
@@ -0,0 +1,89 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import PropTypes from 'prop-types';
+import PureRowForm from './PureRowForm';
+
+export default function PureRowMethod({
+ system,
+ crop_variety,
+ useHookFormPersist,
+ persistedFormData,
+ isFinalPage,
+ history,
+ prefix = `crop_management_plan.planting_management_plans.${isFinalPage ? 'final' : 'initial'}`,
+ submitPath,
+ onGoBack = () => history.back(),
+ isHistoricalPage,
+ location,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ shouldUnregister: false,
+ mode: 'onChange',
+ defaultValues: cloneObject(persistedFormData),
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const onSubmit = () => history.push(submitPath, location.state);
+
+ return (
+
+ );
+}
+
+PureRowMethod.prototype = {
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+ crop_variety: PropTypes.object,
+ system: PropTypes.oneOf(['imperial', 'metric']),
+ isFinalPage: PropTypes.bool,
+ history: PropTypes.object,
+ submitPath: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Crop/Transplant/index.js b/packages/webapp/src/components/Crop/Transplant/index.js
deleted file mode 100644
index 9c84f1c3cb..0000000000
--- a/packages/webapp/src/components/Crop/Transplant/index.js
+++ /dev/null
@@ -1,118 +0,0 @@
-import Button from '../../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Label, Main } from '../../Typography';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import RadioGroup from '../../Form/RadioGroup';
-import { cloneObject } from '../../../util';
-import { getTransplantPaths } from '../getAddManagementPlanPath';
-
-export default function PureTransplant({
- can_be_cover_crop,
- useHookFormPersist,
- persistedFormData,
- match,
- history,
-}) {
- const { t } = useTranslation();
-
- const progress = 25;
- const TRANSPLANT = 'crop_management_plan.needs_transplant';
- const FOR_COVER = 'crop_management_plan.for_cover';
-
- const {
- handleSubmit,
- getValues,
- control,
- setValue,
- formState: { isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const variety_id = match?.params?.variety_id;
- const { submitPath } = getTransplantPaths(variety_id);
- const onSubmit = () => {
- history?.push(submitPath);
- };
- const onGoBack = () => history.goBack();
-
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PureTransplant.prototype = {
- can_be_cover_crop: PropTypes.bool,
- onGoBack: PropTypes.func,
- onCancel: PropTypes.func,
- persistedFormData: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- match: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Crop/Transplant/index.jsx b/packages/webapp/src/components/Crop/Transplant/index.jsx
new file mode 100644
index 0000000000..3bd684e881
--- /dev/null
+++ b/packages/webapp/src/components/Crop/Transplant/index.jsx
@@ -0,0 +1,122 @@
+import Button from '../../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Label, Main } from '../../Typography';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import RadioGroup from '../../Form/RadioGroup';
+import { cloneObject } from '../../../util';
+import { getTransplantPaths } from '../getAddManagementPlanPath';
+
+export default function PureTransplant({
+ can_be_cover_crop,
+ useHookFormPersist,
+ persistedFormData,
+ match,
+ history,
+}) {
+ const { t } = useTranslation();
+
+ const progress = 25;
+ const TRANSPLANT = 'crop_management_plan.needs_transplant';
+ const FOR_COVER = 'crop_management_plan.for_cover';
+
+ const {
+ handleSubmit,
+ getValues,
+ control,
+ setValue,
+ formState: { isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const variety_id = match?.params?.variety_id;
+ const { submitPath } = getTransplantPaths(variety_id);
+ const onSubmit = () => {
+ history?.push(submitPath);
+ };
+ const onGoBack = () => history.back();
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PureTransplant.prototype = {
+ can_be_cover_crop: PropTypes.bool,
+ onGoBack: PropTypes.func,
+ onCancel: PropTypes.func,
+ persistedFormData: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ match: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Crop/cropHeader.js b/packages/webapp/src/components/Crop/cropHeader.js
deleted file mode 100644
index fc2f83c60a..0000000000
--- a/packages/webapp/src/components/Crop/cropHeader.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import { Label, Text, Title } from '../Typography';
-import { ReactComponent as Back } from '../../assets/images/managementPlans/back.svg';
-import { useTranslation } from 'react-i18next';
-import styles from './styles.module.scss';
-
-function CropHeader({
- crop_translation_key,
- crop_variety_name,
- supplier,
- crop_variety_photo_url,
- onBackClick,
-}) {
- const { t } = useTranslation(['translation', 'crop']);
- return (
-
-
-
-
{t(`crop:${crop_translation_key}`)}
-
-
-
- {t('MANAGEMENT_PLAN.VARIETY')}:{' '}
-
- {' '}
- {crop_variety_name ?? t(`crop:${crop_translation_key}`)}{' '}
-
-
-
-
-
- {t('MANAGEMENT_PLAN.SUPPLIER')}:{' '}
- {supplier}
-
-
-
-
-
-
- );
-}
-
-export default CropHeader;
diff --git a/packages/webapp/src/components/Crop/detail.js b/packages/webapp/src/components/Crop/detail.js
deleted file mode 100644
index 5561f93dd0..0000000000
--- a/packages/webapp/src/components/Crop/detail.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import CropHeader from './cropHeader';
-import RouterTab from '../RouterTab';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import Button from '../Form/Button';
-import { ReactComponent as Leaf } from '../../assets/images/signUp/leaf.svg';
-import { Main, Title } from '../Typography';
-import { useForm } from 'react-hook-form';
-import RadioGroup from '../Form/RadioGroup';
-import styles from './styles.module.scss';
-import Layout from '../Layout';
-import Input, { integerOnKeyDown } from '../Form/Input';
-
-function PureCropDetail({
- history,
- match,
- variety,
- isEditing,
- onBack,
- isInterestedInOrganic,
- onRetire,
- onEdit,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- handleSubmit,
- register,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({ mode: 'onChange', defaultValues: { ...variety } });
- const LIFECYCLE = 'lifecycle';
- const ORGANIC = 'organic';
- const TREATED = 'treated';
- const SEARCHED = 'searched';
- const GENETICALLY_ENGINEERED = 'genetically_engineered';
- const HS_CODE_ID = 'hs_code_id';
- const isOrganic = isEditing ? watch(ORGANIC) : variety.organic;
- return (
-
- {/*TODO: LF-2003 rework task/management plan/location/crop_variety soft delete*/}
- {/**/}
- {/* {t('common:RETIRE')}*/}
- {/* */}
-
- {t('common:EDIT')}
-
- >
- )
- }
- >
-
- {!isEditing && (
- <>
-
-
- {/*
- {t('CROP_DETAIL.COMPLIANCE_DOC')}
-
- */}
- >
- )}
- {isEditing && (
- {t('CROP_DETAIL.EDIT_CROP_DETAIL')}
- )}
-
- {t('CROP_DETAIL.ANNUAL_PERENNIAL')}
-
-
- {isInterestedInOrganic && (
- <>
-
- {t('CROP_DETAIL.ORGANIC')}
-
-
-
- {!isOrganic && (
- <>
-
- {t('CROP_DETAIL.COMMERCIAL_AVAILABILITY')}
-
-
-
-
- {t('CROP_DETAIL.GENETICALLY_ENGINEERED')}
-
-
-
- >
- )}
-
- {t('CROP_DETAIL.TREATED')}
-
-
-
- >
- )}
-
-
- );
-}
-
-export default PureCropDetail;
diff --git a/packages/webapp/src/components/Crop/management.js b/packages/webapp/src/components/Crop/management.js
deleted file mode 100644
index ba56fce545..0000000000
--- a/packages/webapp/src/components/Crop/management.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import Layout from '../Layout';
-import CropHeader from './cropHeader';
-import RouterTab from '../RouterTab';
-import React, { useMemo, useState } from 'react';
-import { AddLink, Semibold } from '../Typography';
-import { useTranslation } from 'react-i18next';
-import PropTypes from 'prop-types';
-import { CardWithStatusContainer } from '../CardWithStatus/CardWithStatusContainer/CardWithStatusContainer';
-import { ManagementPlanCard } from '../CardWithStatus/ManagementPlanCard/ManagementPlanCard';
-import Input from '../Form/Input';
-
-export default function PureCropManagement({
- history,
- match,
- onBack,
- variety,
- onAddManagementPlan,
- managementPlanCardContents,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const [searchString, setSearchString] = useState('');
- const searchStringOnChange = (e) => setSearchString(e.target.value);
- const filteredManagementPlanCardContents = useMemo(() => {
- return searchString
- ? managementPlanCardContents.filter(
- ({ locationName, managementPlanName, status }) =>
- locationName?.toLowerCase()?.includes(searchString?.toLowerCase()) ||
- managementPlanName?.toLowerCase()?.includes(searchString?.toLowerCase()) ||
- status?.toLowerCase()?.includes(searchString?.toLowerCase()),
- )
- : managementPlanCardContents;
- }, [searchString, managementPlanCardContents]);
-
- return (
-
-
-
- {t('CROP_DETAIL.MANAGEMENT_PLANS')}
- {managementPlanCardContents?.length > 2 && (
-
- )}
- {isAdmin && {t('CROP_DETAIL.ADD_PLAN')} }
- {managementPlanCardContents && (
-
- {filteredManagementPlanCardContents.map((managementPlan, index) => (
-
- history.push(
- `/crop/${variety.crop_variety_id}/management_plan/${managementPlan.management_plan_id}/tasks`,
- )
- }
- {...managementPlan}
- key={index}
- />
- ))}
-
- )}
-
- );
-}
-
-PureCropManagement.propTypes = {
- managementPlanCardContents: PropTypes.arrayOf(
- PropTypes.shape({
- managementPlanName: PropTypes.string,
- locationName: PropTypes.string,
- notes: PropTypes.string,
- startDate: PropTypes.any,
- endDate: PropTypes.any,
- numberOfPendingTask: PropTypes.number,
- status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
- management_plan_id: PropTypes.number,
- }),
- ),
- history: PropTypes.object,
- match: PropTypes.object,
- onBack: PropTypes.func,
- variety: PropTypes.object,
- onAddManagementPlan: PropTypes.func,
- isAdmin: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Crop/styles.module.scss b/packages/webapp/src/components/Crop/styles.module.scss
index e7082537ea..7e9af04209 100644
--- a/packages/webapp/src/components/Crop/styles.module.scss
+++ b/packages/webapp/src/components/Crop/styles.module.scss
@@ -7,14 +7,42 @@
cursor: pointer;
}
+@media only screen and (max-width: 1000px) {
+ .headerTitle {
+ width: 75vw;
+ }
+}
+
+@media only screen and (max-width: 850px) {
+ .headerTitle {
+ width: 65vw;
+ }
+}
+@media only screen and (max-width: 650px) {
+ .headerTitle {
+ width: 55vw;
+ }
+}
+
+@media only screen and (max-width: 450px) {
+ .headerTitle {
+ width: 40vw;
+ }
+}
+
.headerTitle {
color: var(--teal900);
font-weight: 600;
font-size: 24px;
line-height: 32px;
display: inline-block;
- margin-bottom: 14px
+ margin-bottom: 14px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 800px;
}
+
.headerTitleContainer {
margin-top: 15px;
padding-left: 25px;
diff --git a/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.js b/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.js
deleted file mode 100644
index 55be9fb855..0000000000
--- a/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import { makeStyles } from '@material-ui/core/styles';
-
-import PropTypes from 'prop-types';
-
-import { Text, Underlined } from '../../Typography';
-import clsx from 'clsx';
-import Card from '../../Card';
-import { useTranslation } from 'react-i18next';
-import Square from '../../Square';
-import NativeDatePickerWrapper from '../../Form/NativeDatePicker/NativeDatePickerWrapper';
-import moment from 'moment';
-import { getDateInputFormat } from '../../../util/moment';
-import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
-
-const useStyles = makeStyles({
- container: {
- display: 'flex',
- padding: '12px',
- position: 'relative',
- flexDirection: 'column',
- rowGap: '16px',
- },
- semibold: {
- fontWeight: 600,
- },
- secondRowContainer: {
- display: 'flex',
- gap: '10px',
- },
- cropCountContainer: {
- display: 'flex',
- gap: '4px',
- alignItems: 'center',
- },
-});
-
-export default function CropStatusInfoBox({
- status,
- date = getDateInputFormat(new Date()),
- setDate,
- ...props
-}) {
- const classes = useStyles();
- const { t } = useTranslation();
- const onDateChange = (e) => setDate?.(e.target.value);
-
- return (
-
- {/*
- {t('common:EDIT_DATE')}
- */}
- {/*
- {t('CROP_CATALOGUE.CROP_STATUS')}{' '}
-
- {moment(date).locale(getLanguageFromLocalStorage()).format('MMMM DD, YYYY')}
- {' '}
- */}
- {status && (
-
-
- {status.active}
- {t('common:ACTIVE')}
-
-
- {status.planned}
- {t('common:PLANNED')}
-
-
- {status.past}
- {t('common:PAST')}
-
-
- )}
-
- );
-}
-
-CropStatusInfoBox.propTypes = {
- setDate: PropTypes.func,
- date: PropTypes.string,
-
- status: PropTypes.exact({
- active: PropTypes.number,
- planned: PropTypes.number,
- past: PropTypes.number,
- }),
-};
diff --git a/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.jsx b/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.jsx
new file mode 100644
index 0000000000..95aed81ab9
--- /dev/null
+++ b/packages/webapp/src/components/CropCatalogue/CropStatusInfoBox/index.jsx
@@ -0,0 +1,95 @@
+import { makeStyles } from '@material-ui/core/styles';
+
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import Card from '../../Card';
+import { useTranslation } from 'react-i18next';
+import Square from '../../Square';
+import { getDateInputFormat } from '../../../util/moment';
+
+const useStyles = makeStyles({
+ container: {
+ display: 'flex',
+ padding: '12px',
+ position: 'relative',
+ flexDirection: 'column',
+ rowGap: '16px',
+ },
+ semibold: {
+ fontWeight: 600,
+ },
+ secondRowContainer: {
+ display: 'flex',
+ gap: '10px',
+ },
+ cropCountContainer: {
+ display: 'flex',
+ gap: '4px',
+ alignItems: 'center',
+ },
+});
+
+export default function CropStatusInfoBox({
+ status,
+ date = getDateInputFormat(new Date()),
+ setDate,
+ ...props
+}) {
+ const classes = useStyles();
+ const { t } = useTranslation();
+ const onDateChange = (e) => setDate?.(e.target.value);
+
+ return (
+
+ {/*
+ {t('common:EDIT_DATE')}
+ */}
+ {/*
+ {t('CROP_CATALOGUE.CROP_STATUS')}{' '}
+
+ {moment(date).locale(getLanguageFromLocalStorage()).format('MMMM DD, YYYY')}
+ {' '}
+ */}
+ {status && (
+
+
+ {status.active}
+ {t('common:ACTIVE')}
+
+
+ {status.planned}
+ {t('common:PLANNED')}
+
+
+ {status.past}
+ {t('common:PAST')}
+
+
+ {status.noPlans}
+ {t('common:NEEDS_PLAN')}
+
+
+ )}
+
+ );
+}
+
+CropStatusInfoBox.propTypes = {
+ setDate: PropTypes.func,
+ date: PropTypes.string,
+
+ status: PropTypes.exact({
+ active: PropTypes.number,
+ planned: PropTypes.number,
+ past: PropTypes.number,
+ noPlans: PropTypes.number,
+ }),
+};
diff --git a/packages/webapp/src/components/CropListPage/index.js b/packages/webapp/src/components/CropListPage/index.js
deleted file mode 100644
index 8dd9e248c8..0000000000
--- a/packages/webapp/src/components/CropListPage/index.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import React from 'react';
-import Input from '../Form/Input';
-import { useTranslation } from 'react-i18next';
-import Layout from '../Layout';
-import RouterTab from '../RouterTab';
-import PageTitle from '../PageTitle/v2';
-import PureManagementPlanTile from '../CropTile/ManagementPlanTile';
-import useCropTileListGap from '../CropTile/useCropTileListGap';
-import PureCropTileContainer from '../CropTile/CropTileContainer';
-import PageBreak from '../PageBreak';
-import Square from '../Square';
-import { AddLink } from '../Typography';
-
-export default function PureCropList({
- onFilterChange,
- onAddCrop,
- activeCrops,
- pastCrops,
- plannedCrops,
- history,
- match,
- isAdmin,
- title,
-}) {
- const isSearchable = true;
- const { t } = useTranslation();
-
- const { ref: containerRef, gap, padding, cardWidth } = useCropTileListGap([
- activeCrops?.length,
- plannedCrops?.length,
- pastCrops?.length,
- ]);
-
- return (
-
- history.push('/map')} />
-
- {isSearchable && (
-
- )}
- {isAdmin && (
-
-
{t('LOCATION_CROPS.ADD_NEW')}
-
- )}
-
-
- {activeCrops.length > 0 && (
- <>
-
- {activeCrops.length}
-
-
- {activeCrops.map((fc) => (
- history.push(`/crop/${fc.crop_variety_id}/management`)}
- />
- ))}
-
- >
- )}
- {plannedCrops.length > 0 && (
- <>
-
- {plannedCrops.length}
-
-
-
- {plannedCrops.map((fc) => (
- history.push(`/crop/${fc.crop_variety_id}/management`)}
- />
- ))}
-
- >
- )}
- {pastCrops.length > 0 && (
- <>
-
- {pastCrops.length}
-
-
-
- {pastCrops.map((fc) => (
- history.push(`/crop/${fc.crop_variety_id}/management`)}
- />
- ))}
-
- >
- )}
-
-
- );
-}
diff --git a/packages/webapp/src/components/CropListPage/index.jsx b/packages/webapp/src/components/CropListPage/index.jsx
new file mode 100644
index 0000000000..3a4f527994
--- /dev/null
+++ b/packages/webapp/src/components/CropListPage/index.jsx
@@ -0,0 +1,155 @@
+import React from 'react';
+import Input from '../Form/Input';
+import { useTranslation } from 'react-i18next';
+import Layout from '../Layout';
+import RouterTab from '../RouterTab';
+import PageTitle from '../PageTitle/v2';
+import PureManagementPlanTile from '../CropTile/ManagementPlanTile';
+import useCropTileListGap from '../CropTile/useCropTileListGap';
+import PureCropTileContainer from '../CropTile/CropTileContainer';
+import PageBreak from '../PageBreak';
+import Square from '../Square';
+import { AddLink } from '../Typography';
+
+export default function PureCropList({
+ onFilterChange,
+ onAddCrop,
+ activeCrops,
+ pastCrops,
+ plannedCrops,
+ history,
+ match,
+ isAdmin,
+ title,
+ location,
+}) {
+ const isSearchable = true;
+ const { t } = useTranslation();
+
+ const {
+ ref: containerRef,
+ gap,
+ padding,
+ cardWidth,
+ } = useCropTileListGap([activeCrops?.length, plannedCrops?.length, pastCrops?.length]);
+ return (
+
+ history.push('/map')} />
+
+ {isSearchable && (
+
+ )}
+ {isAdmin && (
+
+
{t('LOCATION_CROPS.ADD_NEW')}
+
+ )}
+
+
+ {activeCrops.length > 0 && (
+ <>
+
+ {activeCrops.length}
+
+
+ {activeCrops.map((fc) => (
+
+ history.push(`/crop/${fc.crop_variety_id}/management`, {
+ returnPath: location?.pathname,
+ })
+ }
+ />
+ ))}
+
+ >
+ )}
+ {plannedCrops.length > 0 && (
+ <>
+
+ {plannedCrops.length}
+
+
+
+ {plannedCrops.map((fc) => (
+
+ history.push(`/crop/${fc.crop_variety_id}/management`, {
+ returnPath: location?.pathname,
+ })
+ }
+ />
+ ))}
+
+ >
+ )}
+ {pastCrops.length > 0 && (
+ <>
+
+ {pastCrops.length}
+
+
+
+ {pastCrops.map((fc) => (
+
+ history.push(`/crop/${fc.crop_variety_id}/management`, {
+ returnPath: location?.pathname,
+ })
+ }
+ />
+ ))}
+
+ >
+ )}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/CropTile/CropTileContainer/index.js b/packages/webapp/src/components/CropTile/CropTileContainer/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CropTile/CropTileContainer/index.js
rename to packages/webapp/src/components/CropTile/CropTileContainer/index.jsx
diff --git a/packages/webapp/src/components/CropTile/ManagementPlanTile/index.js b/packages/webapp/src/components/CropTile/ManagementPlanTile/index.jsx
similarity index 100%
rename from packages/webapp/src/components/CropTile/ManagementPlanTile/index.js
rename to packages/webapp/src/components/CropTile/ManagementPlanTile/index.jsx
diff --git a/packages/webapp/src/components/CropTile/index.js b/packages/webapp/src/components/CropTile/index.js
deleted file mode 100644
index f494641605..0000000000
--- a/packages/webapp/src/components/CropTile/index.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import React from 'react';
-import styles from './styles.module.scss';
-import clsx from 'clsx';
-import Square from '../Square';
-import PropTypes from 'prop-types';
-import { StatusLabel } from '../CardWithStatus/StatusLabel';
-import { managementPlanStatusTranslateKey } from '../CardWithStatus/ManagementPlanCard/ManagementPlanCard';
-import { useTranslation } from 'react-i18next';
-
-export default function PureCropTile({
- className,
- title,
- onClick,
- style,
- cropCount,
- needsPlan,
- src,
- alt,
- isPastVariety,
- isCropTemplate,
- children,
- isSelected,
- status,
-}) {
- const { t } = useTranslation();
- return (
-
-
{
- e.target.onerror = null;
- e.target.src = 'crop-images/default.jpg';
- }}
- />
-
- {cropCount && (
-
- {cropCount.active}
-
- {cropCount.planned}
-
-
- {cropCount.past}
-
-
- )}
- {status && (
-
-
-
- )}
-
- {needsPlan && (
-
-
-
- )}
-
-
-
- );
-}
-
-PureCropTile.prototype = {
- className: PropTypes.string,
- onClick: PropTypes.func,
- style: PropTypes.object,
- cropCount: PropTypes.exact({
- active: PropTypes.number,
- planned: PropTypes.number,
- past: PropTypes.number,
- }),
- needsPlan: PropTypes.bool,
- title: PropTypes.string,
- src: PropTypes.string,
- alt: PropTypes.string,
- isPastVariety: PropTypes.bool,
- isCropTemplate: PropTypes.bool,
- status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
-};
diff --git a/packages/webapp/src/components/CropTile/index.jsx b/packages/webapp/src/components/CropTile/index.jsx
new file mode 100644
index 0000000000..3904d0cbbe
--- /dev/null
+++ b/packages/webapp/src/components/CropTile/index.jsx
@@ -0,0 +1,106 @@
+import React from 'react';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+import Square from '../Square';
+import PropTypes from 'prop-types';
+import { StatusLabel } from '../CardWithStatus/StatusLabel';
+import { managementPlanStatusTranslateKey } from '../CardWithStatus/ManagementPlanCard/ManagementPlanCard';
+import { useTranslation } from 'react-i18next';
+
+export default function PureCropTile({
+ className,
+ title,
+ onClick,
+ style,
+ cropCount = {},
+ needsPlan,
+ src,
+ alt,
+ isPastVariety,
+ isCropTemplate,
+ children,
+ isSelected,
+ status,
+}) {
+ const { active = 0, planned = 0, past = 0, noPlans = 0 } = cropCount;
+ const { t } = useTranslation();
+ return (
+
+
{
+ e.target.onerror = null;
+ e.target.src = 'crop-images/default.jpg';
+ }}
+ />
+
+ {planned + past + active !== 0 && (
+
+ {active}
+
+ {planned}
+
+
+ {past}
+
+
+ )}
+ {status && (
+
+
+
+ )}
+
+ {noPlans !== 0 && (
+
+
+ {noPlans}
+
+
+ )}
+
+
+
+ );
+}
+
+PureCropTile.prototype = {
+ className: PropTypes.string,
+ onClick: PropTypes.func,
+ style: PropTypes.object,
+ cropCount: PropTypes.exact({
+ active: PropTypes.number,
+ planned: PropTypes.number,
+ past: PropTypes.number,
+ }),
+ needsPlan: PropTypes.bool,
+ title: PropTypes.string,
+ src: PropTypes.string,
+ alt: PropTypes.string,
+ isPastVariety: PropTypes.bool,
+ isCropTemplate: PropTypes.bool,
+ status: PropTypes.oneOf(['active', 'planned', 'completed', 'abandoned']),
+};
diff --git a/packages/webapp/src/components/CustomSignUp/index.js b/packages/webapp/src/components/CustomSignUp/index.js
deleted file mode 100644
index 5d0dcb03ea..0000000000
--- a/packages/webapp/src/components/CustomSignUp/index.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import styles from './styles.module.scss';
-import { ReactComponent as Logo } from '../../assets/images/signUp/logo.svg';
-import { ReactComponent as LineBreak } from '../../assets/images/signUp/lineBreak.svg';
-import Button from '../Form/Button';
-import Input from '../Form/Input';
-import React from 'react';
-import Footer from '../Footer';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Error } from '../Typography';
-import { NewReleaseCard } from '../Card/NewReleaseCard/NewReleaseCard';
-
-const inputClasses = {
- container: {
- width: 312,
- },
-};
-
-export default function PureCustomSignUp({
- inputs,
- onSubmit,
- disabled,
- GoogleLoginButton,
- classes,
- isChrome,
- errorMessage,
-}) {
- const { t } = useTranslation();
- const wrongBrowserTop = t('SIGNUP.WRONG_BROWSER');
- const wrongBrowserBottom = t('SIGNUP.WRONG_BROWSER_BOTTOM');
- return (
-
- );
-}
-
-PureCustomSignUp.prototype = {
- inputs: PropTypes.arrayOf(PropTypes.object),
- onSubmit: PropTypes.func,
- disabled: PropTypes.bool,
- GoogleLoginButton: PropTypes.node,
- classes: PropTypes.objectOf(PropTypes.object),
- errorMessage: PropTypes.string,
-};
-
-PureCustomSignUp.defaultProps = {
- inputs: [{}],
- onSubmit: () => {},
- disabled: undefined,
- GoogleLoginButton: undefined,
- classes: {},
- isChrome: true,
- errorMessage: undefined,
-};
diff --git a/packages/webapp/src/components/CustomSignUp/index.jsx b/packages/webapp/src/components/CustomSignUp/index.jsx
new file mode 100644
index 0000000000..f5c6f78c3c
--- /dev/null
+++ b/packages/webapp/src/components/CustomSignUp/index.jsx
@@ -0,0 +1,101 @@
+import styles from './styles.module.scss';
+import { ReactComponent as Logo } from '../../assets/images/signUp/logo.svg';
+import { ReactComponent as LineBreak } from '../../assets/images/signUp/lineBreak.svg';
+import Button from '../Form/Button';
+import Input from '../Form/Input';
+import React from 'react';
+import Footer from '../Footer';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Error } from '../Typography';
+import { NewReleaseCard } from '../Card/NewReleaseCard/NewReleaseCard';
+
+const inputClasses = {
+ container: {
+ width: 312,
+ },
+};
+
+export default function PureCustomSignUp({
+ inputs,
+ onSubmit,
+ disabled,
+ GoogleLoginButton,
+ classes,
+ isChrome,
+ errorMessage,
+}) {
+ const { t } = useTranslation();
+ const wrongBrowserTop = t('SIGNUP.WRONG_BROWSER');
+ const wrongBrowserBottom = t('SIGNUP.WRONG_BROWSER_BOTTOM');
+ return (
+
+ );
+}
+
+PureCustomSignUp.prototype = {
+ inputs: PropTypes.arrayOf(PropTypes.object),
+ onSubmit: PropTypes.func,
+ disabled: PropTypes.bool,
+ GoogleLoginButton: PropTypes.node,
+ classes: PropTypes.objectOf(PropTypes.object),
+ errorMessage: PropTypes.string,
+};
+
+PureCustomSignUp.defaultProps = {
+ inputs: [{}],
+ onSubmit: () => {},
+ disabled: undefined,
+ GoogleLoginButton: undefined,
+ classes: {},
+ isChrome: true,
+ errorMessage: undefined,
+};
diff --git a/packages/webapp/src/components/Documents/Add/index.js b/packages/webapp/src/components/Documents/Add/index.js
deleted file mode 100644
index 1d42c8b74b..0000000000
--- a/packages/webapp/src/components/Documents/Add/index.js
+++ /dev/null
@@ -1,242 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import Input from '../../Form/Input';
-import Form from '../../Form';
-import { useTranslation } from 'react-i18next';
-import ReactSelect from '../../Form/ReactSelect';
-import Checkbox from '../../Form/Checkbox';
-import InputAutoSize from '../../Form/InputAutoSize';
-import Button from '../../Form/Button';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import PageTitle from '../../PageTitle/v2';
-import { ReactComponent as TrashIcon } from '../../../assets/images/document/trash.svg';
-import { Controller, useForm } from 'react-hook-form';
-import CertifierSelectionMenuItem
- from '../../OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem';
-import { Loading } from '../../Loading/Loading';
-import { ContainerWithIcon } from '../../ContainerWithIcon/ContainerWithIcon';
-
-function PureDocumentDetailView({
- submit,
- onGoBack,
- onCancel,
- deleteImage,
- useHookFormPersist,
- imageComponent,
- persistedFormData,
- isEdit,
- documentUploader,
-}) {
- const { t } = useTranslation();
- const typeOptions = {
- CLEANING_PRODUCT: { label: t('DOCUMENTS.TYPE.CLEANING_PRODUCT'), value: 'CLEANING_PRODUCT' },
- CROP_COMPLIANCE: { label: t('DOCUMENTS.TYPE.CROP_COMPLIANCE'), value: 'CROP_COMPLIANCE' },
- FERTILIZING_PRODUCT: {
- label: t('DOCUMENTS.TYPE.FERTILIZING_PRODUCT'),
- value: 'FERTILIZING_PRODUCT',
- },
- PEST_CONTROL_PRODUCT: {
- label: t('DOCUMENTS.TYPE.PEST_CONTROL_PRODUCT'),
- value: 'PEST_CONTROL_PRODUCT',
- },
- SOIL_AMENDMENT: { label: t('DOCUMENTS.TYPE.SOIL_AMENDMENT'), value: 'SOIL_AMENDMENT' },
- SOIL_SAMPLE_RESULTS: { label: t('DOCUMENTS.TYPE.SOIL_SAMPLE_RESULTS'), value: 'SOIL_SAMPLE_RESULTS' },
- WATER_SAMPLE_RESULTS: { label: t('DOCUMENTS.TYPE.WATER_SAMPLE_RESULTS'), value: 'WATER_SAMPLE_RESULTS' },
- OTHER: { label: t('DOCUMENTS.TYPE.OTHER'), value: 'OTHER' },
- };
-
- const NAME = 'name';
- const TYPE = 'type';
- const VALID_UNTIL = 'valid_until';
- const NOTES = 'notes';
- const NO_EXPIRATION = 'no_expiration';
-
- const defaultData = persistedFormData
- ? {
- name: persistedFormData.name,
- type: typeOptions[persistedFormData.type],
- valid_until: persistedFormData.valid_until?.substring(0, 10),
- notes: persistedFormData.notes,
- files: persistedFormData.files,
- no_expiration: persistedFormData.no_expiration,
- }
- : {};
-
- const {
- register,
- handleSubmit,
- control,
- getValues,
- watch,
- formState: { errors, isValid, isDirty },
- } = useForm({
- mode: 'onBlur',
- shouldUnregister: false,
- defaultValues: defaultData,
- });
-
- const submitWithFiles = (data) => {
- const getDocumentThumbnailUrl = (files) => {
- for (const file of files) {
- if (file.thumbnail_url) return file.thumbnail_url;
- }
- return undefined;
- };
- let validUntil = !!data.valid_until ? data.valid_until : null;
- data.type = !!data.type ? data.type.value : data.type;
- validUntil = data.no_expiration ? null : validUntil;
- submit({
- ...data,
- thumbnail_url: getDocumentThumbnailUrl(uploadedFiles),
- files: uploadedFiles.map((file, i) => ({
- ...file,
- })),
- valid_until: validUntil,
- });
- };
-
- const noExpirationChecked = watch(NO_EXPIRATION);
-
- const {
- persistedData: { uploadedFiles },
- historyCancel,
- } = useHookFormPersist(getValues);
- const [isFirstFileUpdateEnded, setIsFilesUpdated] = useState(false);
- const onFileUpdateEnd = () => {
- setIsFilesUpdated(true);
- };
-
- const [shouldShowLoadingImage, setShouldShowLoadingImage] = useState(
- !isEdit && !uploadedFiles?.length,
- );
- const onUpload = () => {
- setShouldShowLoadingImage(true);
- };
- useEffect(() => {
- uploadedFiles?.length && setShouldShowLoadingImage(false);
- }, [uploadedFiles?.length]);
-
- const disabled = isEdit
- ? !isValid || uploadedFiles?.length === 0 || !(isDirty || isFirstFileUpdateEnded)
- : !isValid || uploadedFiles?.length === 0;
-
- return (
-
- );
-}
-
-export default PureDocumentDetailView;
diff --git a/packages/webapp/src/components/Documents/Add/index.jsx b/packages/webapp/src/components/Documents/Add/index.jsx
new file mode 100644
index 0000000000..20e39b0c28
--- /dev/null
+++ b/packages/webapp/src/components/Documents/Add/index.jsx
@@ -0,0 +1,249 @@
+import React, { useEffect, useState } from 'react';
+import Input from '../../Form/Input';
+import Form from '../../Form';
+import { useTranslation } from 'react-i18next';
+import ReactSelect from '../../Form/ReactSelect';
+import Checkbox from '../../Form/Checkbox';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Button from '../../Form/Button';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import PageTitle from '../../PageTitle/v2';
+import { ReactComponent as TrashIcon } from '../../../assets/images/document/trash.svg';
+import { Controller, useForm } from 'react-hook-form';
+import CertifierSelectionMenuItem from '../../OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem';
+import { Loading } from '../../Loading/Loading';
+import { ContainerWithIcon } from '../../ContainerWithIcon/ContainerWithIcon';
+
+function PureDocumentDetailView({
+ submit,
+ onGoBack,
+ onCancel,
+ deleteImage,
+ useHookFormPersist,
+ imageComponent,
+ persistedFormData,
+ isEdit,
+ documentUploader,
+}) {
+ const { t } = useTranslation();
+ const typeOptions = {
+ CLEANING_PRODUCT: { label: t('DOCUMENTS.TYPE.CLEANING_PRODUCT'), value: 'CLEANING_PRODUCT' },
+ CROP_COMPLIANCE: { label: t('DOCUMENTS.TYPE.CROP_COMPLIANCE'), value: 'CROP_COMPLIANCE' },
+ FERTILIZING_PRODUCT: {
+ label: t('DOCUMENTS.TYPE.FERTILIZING_PRODUCT'),
+ value: 'FERTILIZING_PRODUCT',
+ },
+ INVOICES: { label: t('DOCUMENTS.TYPE.INVOICES'), value: 'INVOICES' },
+ PEST_CONTROL_PRODUCT: {
+ label: t('DOCUMENTS.TYPE.PEST_CONTROL_PRODUCT'),
+ value: 'PEST_CONTROL_PRODUCT',
+ },
+ RECEIPTS: { label: t('DOCUMENTS.TYPE.RECEIPTS'), value: 'RECEIPTS' },
+ SOIL_AMENDMENT: { label: t('DOCUMENTS.TYPE.SOIL_AMENDMENT'), value: 'SOIL_AMENDMENT' },
+ SOIL_SAMPLE_RESULTS: {
+ label: t('DOCUMENTS.TYPE.SOIL_SAMPLE_RESULTS'),
+ value: 'SOIL_SAMPLE_RESULTS',
+ },
+ WATER_SAMPLE_RESULTS: {
+ label: t('DOCUMENTS.TYPE.WATER_SAMPLE_RESULTS'),
+ value: 'WATER_SAMPLE_RESULTS',
+ },
+ OTHER: { label: t('DOCUMENTS.TYPE.OTHER'), value: 'OTHER' },
+ };
+
+ const NAME = 'name';
+ const TYPE = 'type';
+ const VALID_UNTIL = 'valid_until';
+ const NOTES = 'notes';
+ const NO_EXPIRATION = 'no_expiration';
+
+ const defaultData = persistedFormData
+ ? {
+ name: persistedFormData.name,
+ type: typeOptions[persistedFormData.type],
+ valid_until: persistedFormData.valid_until?.substring(0, 10),
+ notes: persistedFormData.notes,
+ files: persistedFormData.files,
+ no_expiration: persistedFormData.no_expiration,
+ }
+ : {};
+
+ const {
+ register,
+ handleSubmit,
+ control,
+ getValues,
+ watch,
+ formState: { errors, isValid, isDirty },
+ } = useForm({
+ mode: 'onBlur',
+ shouldUnregister: false,
+ defaultValues: defaultData,
+ });
+
+ const submitWithFiles = (data) => {
+ const getDocumentThumbnailUrl = (files) => {
+ for (const file of files) {
+ if (file.thumbnail_url) return file.thumbnail_url;
+ }
+ return undefined;
+ };
+ let validUntil = !!data.valid_until ? data.valid_until : null;
+ data.type = !!data.type ? data.type.value : data.type;
+ validUntil = data.no_expiration ? null : validUntil;
+ submit({
+ ...data,
+ thumbnail_url: getDocumentThumbnailUrl(uploadedFiles),
+ files: uploadedFiles.map((file, i) => ({
+ ...file,
+ })),
+ valid_until: validUntil,
+ });
+ };
+
+ const noExpirationChecked = watch(NO_EXPIRATION);
+
+ const {
+ persistedData: { uploadedFiles },
+ historyCancel,
+ } = useHookFormPersist(getValues);
+ const [isFirstFileUpdateEnded, setIsFilesUpdated] = useState(false);
+ const onFileUpdateEnd = () => {
+ setIsFilesUpdated(true);
+ };
+
+ const [shouldShowLoadingImage, setShouldShowLoadingImage] = useState(
+ !isEdit && !uploadedFiles?.length,
+ );
+ const onUpload = () => {
+ setShouldShowLoadingImage(true);
+ };
+ useEffect(() => {
+ uploadedFiles?.length && setShouldShowLoadingImage(false);
+ }, [uploadedFiles?.length]);
+
+ const disabled = isEdit
+ ? !isValid || uploadedFiles?.length === 0 || !(isDirty || isFirstFileUpdateEnded)
+ : !isValid || uploadedFiles?.length === 0;
+
+ return (
+
+ );
+}
+
+export default PureDocumentDetailView;
diff --git a/packages/webapp/src/components/Documents/Main/index.js b/packages/webapp/src/components/Documents/Main/index.js
deleted file mode 100644
index d45ddcac33..0000000000
--- a/packages/webapp/src/components/Documents/Main/index.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import Layout from '../../Layout';
-import Button from '../../Form/Button';
-import Input from '../../Form/Input';
-import InputAutoSize from '../../Form/InputAutoSize';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../../PageTitle/v2';
-import Checkbox from '../../Form/Checkbox';
-import CertifierSelectionMenuItem from '../../OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem';
-
-function MainDocumentView({ onRetire, onUpdate, onGoBack, document, imageComponent }) {
- const { t } = useTranslation();
- const isArchived = document.valid_until !== null && new Date(document.valid_until) < new Date();
- const validUntil = document.valid_until?.split('T')[0];
- return (
-
-
- {t('DOCUMENTS.ARCHIVE')}
-
-
- {t('common:EDIT')}
-
- >
- }
- >
-
-
- {document.valid_until && (
-
- )}
- {document.no_expiration && (
-
- )}
-
-
- {document.files?.map(({ thumbnail_url, file_name, url }, index) =>
- thumbnail_url ? (
- imageComponent({
- style: { width: '100%', maxWidth: '312px', position: 'relative', zIndex: 0 },
- src: thumbnail_url,
- key: index,
- })
- ) : (
-
- ),
- )}
-
-
-
- );
-}
-
-export default MainDocumentView;
diff --git a/packages/webapp/src/components/Documents/Main/index.jsx b/packages/webapp/src/components/Documents/Main/index.jsx
new file mode 100644
index 0000000000..b038c98761
--- /dev/null
+++ b/packages/webapp/src/components/Documents/Main/index.jsx
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import Layout from '../../Layout';
+import Button from '../../Form/Button';
+import Input from '../../Form/Input';
+import InputAutoSize from '../../Form/InputAutoSize';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../PageTitle/v2';
+import Checkbox from '../../Form/Checkbox';
+import CertifierSelectionMenuItem from '../../OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem';
+
+function MainDocumentView({ onRetire, onUpdate, onGoBack, document, imageComponent }) {
+ const { t } = useTranslation();
+ const isArchived = document.valid_until !== null && new Date(document.valid_until) < new Date();
+ const validUntil = document.valid_until?.split('T')[0];
+ return (
+
+
+ {t(`DOCUMENTS.${document.archived ? 'UNARCHIVE' : 'ARCHIVE'}`)}
+
+
+ {t('common:EDIT')}
+
+ >
+ }
+ >
+
+
+ {document.valid_until && (
+
+ )}
+ {document.no_expiration && (
+
+ )}
+
+
+ {document.files?.map(({ thumbnail_url, file_name, url }, index) =>
+ thumbnail_url ? (
+ imageComponent({
+ style: { width: '100%', maxWidth: '312px', position: 'relative', zIndex: 0 },
+ src: thumbnail_url,
+ key: index,
+ })
+ ) : (
+
+ ),
+ )}
+
+
+
+ );
+}
+
+export default MainDocumentView;
diff --git a/packages/webapp/src/components/EditCropVariety/index.js b/packages/webapp/src/components/EditCropVariety/index.js
deleted file mode 100644
index 4cd0a57f55..0000000000
--- a/packages/webapp/src/components/EditCropVariety/index.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import Button from '../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Label } from '../Typography';
-import Input, { integerOnKeyDown } from '../Form/Input';
-import styles from './styles.module.scss';
-import Radio from '../Form/Radio';
-import Form from '../Form';
-import { useForm } from 'react-hook-form';
-import PageTitle from '../PageTitle/v2';
-import RadioGroup from '../Form/RadioGroup';
-import Infoi from '../Tooltip/Infoi';
-import Leaf from '../../assets/images/farmMapFilter/Leaf.svg';
-
-export default function PureEditCropVariety({
- onSubmit,
- onError,
- isSeekingCert,
- imageUploader,
- handleGoBack,
- cropVariety,
-}) {
- const { t } = useTranslation(['translation', 'common', 'crop']);
- const {
- register,
- handleSubmit,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: {
- crop_variety_photo_url:
- cropVariety.crop_variety_photo_url ||
- cropVariety.crop_photo_url`https://${process.env.REACT_APP_DO_BUCKET_NAME}.nyc3.digitaloceanspaces.com//default_crop/v2/default.webp`,
- ...(({
- crop_variety_name,
- supplier,
- lifecycle,
- organic,
- treated,
- genetically_engineered,
- searched,
- }) => ({
- crop_variety_name,
- supplier,
- lifecycle,
- organic,
- treated,
- genetically_engineered,
- searched,
- }))(cropVariety),
- },
- });
-
- const VARIETY = 'crop_variety_name';
- const SUPPLIER = 'supplier';
- const LIFE_CYCLE = 'lifecycle';
- const CROP_VARIETY_PHOTO_URL = 'crop_variety_photo_url';
-
- const CERTIFIED_ORGANIC = 'organic';
- const COMMERCIAL_AVAILABILITY = 'searched';
- const GENETIC_EGINEERED = 'genetically_engineered';
- const TREATED = 'treated';
- const HS_CODE_ID = 'hs_code_id';
-
- const disabled = !isValid;
-
- const varietyRegister = register(VARIETY, { required: true });
- const supplierRegister = register(SUPPLIER, { required: isSeekingCert ? true : false });
- const lifeCycleRegister = register(LIFE_CYCLE, { required: true });
- const imageUrlRegister = register(CROP_VARIETY_PHOTO_URL, { required: true });
-
- const crop_variety_photo_url = watch(CROP_VARIETY_PHOTO_URL);
- const organic = watch(CERTIFIED_ORGANIC);
- const cropTranslationKey = cropVariety.crop_translation_key;
- const cropNameLabel = cropTranslationKey
- ? t(`crop:${cropTranslationKey}`)
- : cropVariety.crop_common_name;
-
- return (
-
- );
-}
-
-PureEditCropVariety.prototype = {
- history: PropTypes.object,
- match: PropTypes.object,
- onSubmit: PropTypes.func,
- onError: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- isSeekingCert: PropTypes.bool,
- persistedFormData: PropTypes.object,
- crop: PropTypes.object,
- imageUploader: PropTypes.node,
-};
diff --git a/packages/webapp/src/components/EditCropVariety/index.jsx b/packages/webapp/src/components/EditCropVariety/index.jsx
new file mode 100644
index 0000000000..1d89b411df
--- /dev/null
+++ b/packages/webapp/src/components/EditCropVariety/index.jsx
@@ -0,0 +1,269 @@
+import Button from '../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Label } from '../Typography';
+import Input, { integerOnKeyDown } from '../Form/Input';
+import styles from './styles.module.scss';
+import Radio from '../Form/Radio';
+import Form from '../Form';
+import { useForm } from 'react-hook-form';
+import PageTitle from '../PageTitle/v2';
+import RadioGroup from '../Form/RadioGroup';
+import Infoi from '../Tooltip/Infoi';
+import Leaf from '../../assets/images/farmMapFilter/Leaf.svg';
+
+export default function PureEditCropVariety({
+ onSubmit,
+ onError,
+ isSeekingCert,
+ imageUploader,
+ handleGoBack,
+ cropVariety,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'crop']);
+ const {
+ register,
+ handleSubmit,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: true,
+ defaultValues: {
+ crop_variety_photo_url:
+ cropVariety.crop_variety_photo_url ||
+ cropVariety.crop_photo_url`https://${
+ import.meta.env.VITE_DO_BUCKET_NAME
+ }.nyc3.digitaloceanspaces.com//default_crop/v2/default.webp`,
+ ...(({
+ crop_variety_name,
+ supplier,
+ lifecycle,
+ organic,
+ treated,
+ genetically_engineered,
+ searched,
+ hs_code_id,
+ }) => ({
+ crop_variety_name,
+ supplier,
+ lifecycle,
+ organic,
+ treated,
+ genetically_engineered,
+ searched,
+ hs_code_id,
+ }))(cropVariety),
+ },
+ });
+
+ const VARIETY = 'crop_variety_name';
+ const SUPPLIER = 'supplier';
+ const LIFE_CYCLE = 'lifecycle';
+ const CROP_VARIETY_PHOTO_URL = 'crop_variety_photo_url';
+
+ const CERTIFIED_ORGANIC = 'organic';
+ const COMMERCIAL_AVAILABILITY = 'searched';
+ const GENETIC_EGINEERED = 'genetically_engineered';
+ const TREATED = 'treated';
+ const HS_CODE_ID = 'hs_code_id';
+
+ const disabled = !isValid;
+
+ const varietyRegister = register(VARIETY, { required: true });
+ const supplierRegister = register(SUPPLIER, { required: isSeekingCert ? true : false });
+ const lifeCycleRegister = register(LIFE_CYCLE, { required: true });
+ const imageUrlRegister = register(CROP_VARIETY_PHOTO_URL, { required: true });
+
+ const crop_variety_photo_url = watch(CROP_VARIETY_PHOTO_URL);
+ const organic = watch(CERTIFIED_ORGANIC);
+ const cropTranslationKey = cropVariety.crop_translation_key;
+ const cropNameLabel = cropTranslationKey
+ ? t(`crop:${cropTranslationKey}`)
+ : cropVariety.crop_common_name;
+
+ return (
+
+ );
+}
+
+PureEditCropVariety.prototype = {
+ history: PropTypes.object,
+ match: PropTypes.object,
+ onSubmit: PropTypes.func,
+ onError: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ isSeekingCert: PropTypes.bool,
+ persistedFormData: PropTypes.object,
+ crop: PropTypes.object,
+ imageUploader: PropTypes.node,
+};
diff --git a/packages/webapp/src/components/ExpiredTokenScreen/index.js b/packages/webapp/src/components/ExpiredTokenScreen/index.jsx
similarity index 100%
rename from packages/webapp/src/components/ExpiredTokenScreen/index.js
rename to packages/webapp/src/components/ExpiredTokenScreen/index.jsx
diff --git a/packages/webapp/src/components/FarmSwitchOutro/index.js b/packages/webapp/src/components/FarmSwitchOutro/index.js
deleted file mode 100644
index 707823d057..0000000000
--- a/packages/webapp/src/components/FarmSwitchOutro/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import styles from './styles.module.scss';
-import { ReactComponent as OutroImg } from '../../assets/images/farm-switch-outro/outro.svg';
-import Button from '../Form/Button';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-export default function FarmSwitchPureOutroSplash({ onFinish, farm_name }) {
- //TODO move selector to container
- const { t } = useTranslation();
- const descriptionTop = t('SWITCH_OUTRO.DESCRIPTION_TOP');
- const descriptionBottom = t('SWITCH_OUTRO.DESCRIPTION_BOTTOM');
-
- return (
-
-
{t('SWITCH_OUTRO.TITLE')}
-
-
-
-
-
{descriptionTop}
-
{descriptionBottom}
-
{farm_name}
-
-
- );
-}
diff --git a/packages/webapp/src/components/FarmSwitchOutro/index.jsx b/packages/webapp/src/components/FarmSwitchOutro/index.jsx
new file mode 100644
index 0000000000..891f5ed06d
--- /dev/null
+++ b/packages/webapp/src/components/FarmSwitchOutro/index.jsx
@@ -0,0 +1,30 @@
+import styles from './styles.module.scss';
+import { ReactComponent as OutroImg } from '../../assets/images/farm-switch-outro/outro.svg';
+import Button from '../Form/Button';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+export default function FarmSwitchPureOutroSplash({ onFinish, farm_name }) {
+ //TODO move selector to container
+ const { t } = useTranslation();
+ const descriptionTop = t('SWITCH_OUTRO.DESCRIPTION_TOP');
+ const descriptionBottom = t('SWITCH_OUTRO.DESCRIPTION_BOTTOM');
+
+ return (
+
+
+
{t('SWITCH_OUTRO.TITLE')}
+
+
+
+
+
{descriptionTop}
+
{descriptionBottom}
+
{farm_name}
+
+
+ {t('SWITCH_OUTRO.BUTTON')}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/FarmSwitchOutro/styles.module.scss b/packages/webapp/src/components/FarmSwitchOutro/styles.module.scss
index 4a5fdc8a85..d81ee5a4e1 100644
--- a/packages/webapp/src/components/FarmSwitchOutro/styles.module.scss
+++ b/packages/webapp/src/components/FarmSwitchOutro/styles.module.scss
@@ -17,11 +17,14 @@
/* Rectangle 49 */
display: flex;
flex-direction: column;
- width: 312px;
- height: 430px;
+ width: 296px;
+ min-height: 430px;
/* Grey-100 */
background: #fafafd;
border-radius: 7.05466px;
+ align-items: center;
+ justify-content: space-between;
+ padding: 20px
}
.descriptionTop {
@@ -41,6 +44,7 @@
.descriptionBottom {
justify-content: center;
+ text-align: center;
font-family: 'Open Sans', 'SansSerif', serif;
font-style: normal;
font-weight: normal;
@@ -59,19 +63,18 @@
line-height: 32px;
display: flex;
align-items: center;
+ word-break: break-word;
+ margin-bottom: 12px;
}
.imgContainer {
- margin-left: 5%;
margin-top: -40px;
+ transform: translateX(-20px);
+ width: 100%;
}
.title {
- margin-top: 20px;
- margin-left: 20%;
font-family: 'Open Sans', 'SansSerif', serif;
- padding-left: 20px;
- padding-right: 20px;
font-style: normal;
font-weight: lighter;
font-size: 20px;
@@ -88,7 +91,14 @@
}
.bottomContainer {
- margin: 30px auto 0 auto;
+ margin: 0 0 0 0;
width: 240px;
box-shadow: 0 2px 8px rgba(102, 115, 138, 0.5);
}
+
+.bodyContainer {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 100%;
+}
diff --git a/packages/webapp/src/components/Field/DrawingToolTipBox.js b/packages/webapp/src/components/Field/DrawingToolTipBox.js
deleted file mode 100644
index be69f51a6b..0000000000
--- a/packages/webapp/src/components/Field/DrawingToolTipBox.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (DrawingToolTipBox.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Component } from 'react';
-import { Modal } from 'react-bootstrap';
-import Carousel from 'nuka-carousel';
-import ReactPlayer from 'react-player';
-import FirstVideo from './drawing.mp4';
-import SecondVideo from './dragging.mp4';
-import styles from './styles.module.scss';
-import { BsChevronRight, BsChevronLeft } from 'react-icons/bs';
-
-class DrawingToolTipBox extends Component {
- constructor(props) {
- super(props);
- this.state = {
- show: this.props.initShow || false,
- playVideo: [false, false],
- };
- this.handleClose = this.handleClose.bind(this);
- this.toggleVideo = this.toggleVideo.bind(this);
- this.toggleShow = this.toggleShow.bind(this);
- }
-
- handleClose() {
- this.setState({ show: false });
- }
-
- toggleVideo(index) {
- let currentVideo = this.state.playVideo;
- currentVideo[index + 1] = true;
- this.setState({ playVideo: currentVideo });
- }
-
- componentDidMount() {
- this.toggleVideo(-1);
- }
-
- toggleShow() {
- this.setState({ show: true });
- }
-
- render() {
- const slides = [
- {
- text: 'Click on the map to draw dots to form a polygon',
- videoPath: FirstVideo,
- },
- {
- text: 'Rearrange the polygon by dragging the dots',
- videoPath: SecondVideo,
- },
- ];
- return (
-
-
- (
- this.toggleVideo(currentSlide)}>
-
-
-
-
- )}
- renderCenterLeftControls={({ previousSlide }) => (
-
-
-
- )}
- >
- {slides.map((slide, index) => {
- return (
-
- );
- })}
-
-
-
- );
- }
-}
-
-export default DrawingToolTipBox;
diff --git a/packages/webapp/src/components/Field/dragging.mp4 b/packages/webapp/src/components/Field/dragging.mp4
deleted file mode 100644
index 094cb3cd46..0000000000
Binary files a/packages/webapp/src/components/Field/dragging.mp4 and /dev/null differ
diff --git a/packages/webapp/src/components/Field/drawing.mp4 b/packages/webapp/src/components/Field/drawing.mp4
deleted file mode 100644
index 26f67dd417..0000000000
Binary files a/packages/webapp/src/components/Field/drawing.mp4 and /dev/null differ
diff --git a/packages/webapp/src/components/Field/styles.module.scss b/packages/webapp/src/components/Field/styles.module.scss
deleted file mode 100644
index c674ad5750..0000000000
--- a/packages/webapp/src/components/Field/styles.module.scss
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (styles.scss) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-.slideContainer {
- display: flex;
- flex-direction: column;
- width: 100%;
- max-width: 1024px;
- color: var(--typePrimary);
- height: 70vh;
- align-items: center;
- text-align: center;
-}
diff --git a/packages/webapp/src/components/Filter/CheckBoxPill/index.js b/packages/webapp/src/components/Filter/CheckBoxPill/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Filter/CheckBoxPill/index.js
rename to packages/webapp/src/components/Filter/CheckBoxPill/index.jsx
diff --git a/packages/webapp/src/components/Filter/FilterDate/index.jsx b/packages/webapp/src/components/Filter/FilterDate/index.jsx
new file mode 100644
index 0000000000..11be5e7cd9
--- /dev/null
+++ b/packages/webapp/src/components/Filter/FilterDate/index.jsx
@@ -0,0 +1,42 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import Input from '../../Form/Input';
+
+export function FilterDate({
+ defaultValue,
+ filterKey,
+ onChange,
+ subject,
+ filterRef,
+ shouldReset,
+ props,
+}) {
+ const [date, setDate] = useState(defaultValue ?? '');
+
+ useEffect(() => {
+ if (shouldReset) {
+ setDate('');
+ }
+ }, [shouldReset]);
+ useEffect(() => {
+ if (filterRef?.current) {
+ filterRef.current[filterKey] = date || undefined;
+ }
+ }, [date]);
+
+ const handleDateChange = (e) => {
+ setDate(e.target.value);
+ onChange?.(e);
+ };
+
+ return (
+
+ );
+}
+
+FilterDate.prototype = {
+ label: PropTypes.string,
+ selected: PropTypes.bool,
+ removable: PropTypes.bool,
+ shouldReset: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Filter/FilterDateRange/index.jsx b/packages/webapp/src/components/Filter/FilterDateRange/index.jsx
new file mode 100644
index 0000000000..78e3bdb923
--- /dev/null
+++ b/packages/webapp/src/components/Filter/FilterDateRange/index.jsx
@@ -0,0 +1,94 @@
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import Switch from '../../Form/Switch';
+import DateRangePicker from '../../Form/DateRangePicker';
+import { getDateInputFormat } from '../../../util/moment';
+
+export function FilterDateRange({
+ setDirty,
+ defaultFromDate,
+ defaultToDate,
+ onDirty,
+ subject,
+ filterRef,
+ shouldReset,
+ style,
+}) {
+ const [fromDate, setFromDate] = useState(defaultFromDate ?? '');
+ const [toDate, setToDate] = useState(defaultToDate ?? '');
+ useEffect(() => {
+ if (shouldReset) {
+ setFromDate('');
+ setToDate('');
+ }
+ }, [shouldReset]);
+ useEffect(() => {
+ if (filterRef?.current) {
+ filterRef.current.FROM_DATE = fromDate || undefined;
+ }
+ }, [fromDate]);
+ useEffect(() => {
+ if (filterRef.current) {
+ filterRef.current.TO_DATE = toDate || undefined;
+ }
+ }, [toDate]);
+ const [showDateFilter, setShowDateFilter] = useState(!!(defaultFromDate || defaultToDate));
+ const onSwitchClick = () => {
+ setDirty?.();
+ if (showDateFilter) {
+ onDirty?.();
+ setShowDateFilter(false);
+ setFromDate('');
+ setToDate('');
+ } else {
+ setShowDateFilter(true);
+ setFromDate(() => {
+ if (defaultFromDate) return defaultFromDate;
+ if (!defaultToDate) return getDateInputFormat();
+ });
+ setToDate(() => {
+ if (defaultToDate) return defaultToDate;
+ if (!defaultFromDate) {
+ const toDate = new Date();
+ toDate.setDate(toDate.getDate() + 7);
+ return getDateInputFormat(toDate);
+ }
+ });
+ }
+ };
+ const handleFromDateChange = (e) => {
+ setFromDate(e.target.value);
+ setDirty?.();
+ };
+
+ const handleToDateChange = (e) => {
+ setToDate(e.target.value);
+ setDirty?.();
+ };
+ return (
+
+
+ {showDateFilter && (
+ <>
+
+ >
+ )}
+
+ );
+}
+
+FilterDateRange.prototype = {
+ label: PropTypes.string,
+ selected: PropTypes.bool,
+ removable: PropTypes.bool,
+ shouldReset: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Filter/FilterMultiSelect/index.jsx b/packages/webapp/src/components/Filter/FilterMultiSelect/index.jsx
new file mode 100644
index 0000000000..d0161a6c8a
--- /dev/null
+++ b/packages/webapp/src/components/Filter/FilterMultiSelect/index.jsx
@@ -0,0 +1,68 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import PropTypes from 'prop-types';
+import ReactSelect from '../../Form/ReactSelect';
+import produce from 'immer';
+import { useTranslation } from 'react-i18next';
+
+export const FilterMultiSelect = ({
+ subject,
+ filterKey,
+ style,
+ filterRef,
+ shouldReset,
+ options = [],
+ onChange,
+}) => {
+ const { t } = useTranslation(['common']);
+
+ const defaultValue = useMemo(() => {
+ return options.filter((option) => option.default);
+ }, []);
+ const [value, setValue] = useState(defaultValue);
+
+ const defaultFilterState = useMemo(() => {
+ return options.reduce((defaultFilterState, option) => {
+ defaultFilterState[option.value] = {
+ active: false,
+ label: option.label,
+ };
+ return defaultFilterState;
+ }, {});
+ }, []);
+
+ useEffect(() => {
+ if (shouldReset) {
+ setValue([]);
+ }
+ }, [shouldReset]);
+
+ useEffect(() => {
+ filterRef.current[filterKey] = produce(defaultFilterState, (defaultFilterState) => {
+ for (const option of value) {
+ defaultFilterState[option.value].active = true;
+ }
+ });
+ }, [value]);
+
+ return (
+ {
+ setValue(value);
+ onChange?.(value);
+ }}
+ isMulti
+ />
+ );
+};
+
+FilterMultiSelect.prototype = {
+ subject: PropTypes.string,
+ options: PropTypes.array,
+ filterKey: PropTypes.string,
+ shouldReset: PropTypes.number,
+};
diff --git a/packages/webapp/src/components/Filter/FilterPillSelect/index.jsx b/packages/webapp/src/components/Filter/FilterPillSelect/index.jsx
new file mode 100644
index 0000000000..731b0e17f4
--- /dev/null
+++ b/packages/webapp/src/components/Filter/FilterPillSelect/index.jsx
@@ -0,0 +1,98 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import CheckBoxPill from '../CheckBoxPill';
+import clsx from 'clsx';
+import { BsChevronDown } from 'react-icons/bs';
+import produce from 'immer';
+
+const FilterPillSelect = ({
+ subject,
+ filterKey,
+ style,
+ filterRef,
+ shouldReset,
+ options = [],
+ onChange,
+}) => {
+ const [open, setOpen] = useState(false);
+ const defaultFilterState = useMemo(() => {
+ return options.reduce((defaultFilterState, option) => {
+ defaultFilterState[option.value] = {
+ active: option.default,
+ label: option.label,
+ };
+ return defaultFilterState;
+ }, {});
+ }, []);
+ const [filterState, setFilterState] = useState(defaultFilterState);
+ const updateFilterState = (value) => {
+ setFilterState((filterState) => {
+ return produce(filterState, (filterState) => {
+ filterState[value].active = !filterState[value].active;
+ });
+ });
+ onChange?.(value);
+ };
+ const counter = useMemo(
+ () =>
+ Object.values(filterState).reduce((acc, curr) => {
+ return curr.active ? acc + 1 : acc;
+ }, 0),
+ [filterState],
+ );
+ useEffect(() => {
+ filterRef.current[filterKey] = filterState;
+ }, [filterState]);
+
+ useEffect(() => {
+ if (shouldReset) {
+ const initState = options.reduce((defaultFilterState, option) => {
+ defaultFilterState[option.value] = {
+ active: false,
+ label: option.label,
+ };
+ return defaultFilterState;
+ }, {});
+ setFilterState(initState);
+ }
+ }, [shouldReset]);
+
+ return (
+
+
setOpen(!open)}>
+
{subject}
+ {counter > 0 && (
+ <>
+
+
+
{`+${counter}`}
+ >
+ )}
+
+
+
+ {options.map((option) => {
+ return (
+
+ );
+ })}
+
+
+ );
+};
+
+FilterPillSelect.prototype = {
+ subject: PropTypes.string,
+ options: PropTypes.array,
+ filterKey: PropTypes.string,
+ shouldReset: PropTypes.number,
+};
+
+export default FilterPillSelect;
diff --git a/packages/webapp/src/components/Filter/styles.module.scss b/packages/webapp/src/components/Filter/FilterPillSelect/styles.module.scss
similarity index 100%
rename from packages/webapp/src/components/Filter/styles.module.scss
rename to packages/webapp/src/components/Filter/FilterPillSelect/styles.module.scss
diff --git a/packages/webapp/src/components/Filter/Pill/index.js b/packages/webapp/src/components/Filter/Pill/index.js
deleted file mode 100644
index f4b21adee9..0000000000
--- a/packages/webapp/src/components/Filter/Pill/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import clsx from 'clsx';
-import { BsX } from 'react-icons/bs';
-
-const Pill = ({ className, label, selected, removable, onRemovePill }) => {
- return (
-
- {label}
- {removable && (
-
- )}
-
- );
-};
-
-Pill.prototype = {
- label: PropTypes.string,
- selected: PropTypes.bool,
- removable: PropTypes.bool,
-};
-
-export default Pill;
diff --git a/packages/webapp/src/components/Filter/Pill/index.jsx b/packages/webapp/src/components/Filter/Pill/index.jsx
new file mode 100644
index 0000000000..30b174960d
--- /dev/null
+++ b/packages/webapp/src/components/Filter/Pill/index.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+import { BsX } from 'react-icons/bs';
+
+const Pill = ({ className, label, selected, removable, onRemovePill }) => {
+ return (
+
+ {label}
+ {removable && (
+
+ )}
+
+ );
+};
+
+Pill.prototype = {
+ label: PropTypes.string,
+ selected: PropTypes.bool,
+ removable: PropTypes.bool,
+};
+
+export default Pill;
diff --git a/packages/webapp/src/components/Filter/filterTypes.js b/packages/webapp/src/components/Filter/filterTypes.js
new file mode 100644
index 0000000000..c1fa67b1e9
--- /dev/null
+++ b/packages/webapp/src/components/Filter/filterTypes.js
@@ -0,0 +1,4 @@
+export const PILL_SELECT = 'PILL_SELECT';
+export const SEARCHABLE_MULTI_SELECT = 'SEARCHABLE_MULTI_SELECT';
+export const DATE_RANGE = 'DATE_RANGE';
+export const DATE = 'DATE';
diff --git a/packages/webapp/src/components/Filter/index.js b/packages/webapp/src/components/Filter/index.js
deleted file mode 100644
index 322c6c4819..0000000000
--- a/packages/webapp/src/components/Filter/index.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import CheckBoxPill from './CheckBoxPill';
-import clsx from 'clsx';
-import { BsChevronDown } from 'react-icons/bs';
-import { cloneObject } from '../../util';
-
-const Filter = ({
- subject,
- items,
- filterKey,
- style,
- filterRef,
- filterState,
- updateFilter,
- counter,
-}) => {
- const [open, setOpen] = useState(false);
-
- const updateFilterState = (value) => {
- updateFilter(filterKey, value);
- };
-
- useEffect(() => {
- filterRef.current[filterKey] = filterState;
- }, [filterRef, filterState]);
-
- return (
-
-
setOpen(!open)}>
-
{subject}
- {counter > 0 && (
- <>
-
-
-
{`+${counter}`}
- >
- )}
-
-
-
- {items.map((item) => {
- return (
-
- );
- })}
-
-
- );
-};
-
-Filter.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
- filterKey: PropTypes.string,
-};
-
-export default Filter;
diff --git a/packages/webapp/src/components/FilterPage/index.js b/packages/webapp/src/components/FilterPage/index.js
deleted file mode 100644
index 9dbbc44d63..0000000000
--- a/packages/webapp/src/components/FilterPage/index.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import Layout from '../Layout';
-import PageTitle from '../PageTitle/v2';
-import { Underlined } from '../Typography';
-import { useTranslation } from 'react-i18next';
-import Filter from '../Filter';
-import Button from '../Form/Button';
-import { cloneObject } from '../../util';
-
-const PureFilterPage = ({
- title,
- filters,
- onApply,
- filterRef,
- onGoBack,
- children,
- resetters = [],
-}) => {
- const { t } = useTranslation();
-
- const initFilterPageState = {};
- const initCountTrackerState = {};
- for (const filter of filters) {
- const initFilterState = {};
- for (const option of filter.options) {
- initFilterState[option.value] = {
- active: option.default,
- label: option.label,
- };
- }
- initFilterPageState[filter.filterKey] = initFilterState;
- initCountTrackerState[filter.filterKey] = 0;
- }
- const [filterPageState, setFilterPageState] = useState(initFilterPageState);
- const [countTrackerState, setCountTrackerState] = useState(initCountTrackerState);
-
- useEffect(() => {
- for (const filterKey in filterPageState) {
- const filter = filterPageState[filterKey];
- const activeSum = Object.values(filter).reduce((acc, curr) => {
- return curr.active ? acc + 1 : acc;
- }, 0);
- setCountTrackerState((prev) => {
- const change = cloneObject(prev);
- change[filterKey] = activeSum;
- return change;
- });
- }
- }, [filterPageState]);
-
- const updateFilter = (filterKey, value) => {
- setFilterPageState((prev) => {
- const change = cloneObject(prev);
- change[filterKey][value].active = !prev[filterKey][value].active;
- return change;
- });
- };
-
- const resetFilter = () => {
- setFilterPageState((prev) => {
- const change = filterResetHelper(cloneObject(prev));
- return change;
- });
-
- for (const resetter of resetters) {
- const { setFunc, defaultVal } = resetter;
- setFunc(defaultVal);
- }
- };
-
- return (
-
- {t('common:APPLY')}
-
- }
- >
-
-
-
- resetFilter()}>
- {t('FILTER.CLEAR_ALL_FILTERS')}
-
-
-
- {filters.map((filter) => {
- if (filter.options.length !== 0)
- return (
-
- );
- })}
- {children}
-
- );
-};
-
-PureFilterPage.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
- onGoBack: PropTypes.func,
-};
-
-export default PureFilterPage;
-
-// // TRUST THE NATURAL RECURSION
-// const recursiveFilterReset = (filter) => {
-// Object.keys(filter).forEach((key) => {
-// const value = filter[key];
-// if (typeof value === 'boolean') {
-// filter[key] = false;
-// } else {
-// filter[key] = recursiveFilterReset(value);
-// }
-// });
-// return filter;
-// };
-
-const filterResetHelper = (filter) => {
- for (const filterKey in filter) {
- const filterContents = filter[filterKey];
- for (const filterValue in filterContents) {
- const filterItem = filterContents[filterValue];
- filterItem.active = false;
- }
- }
- return filter;
-};
diff --git a/packages/webapp/src/components/FilterPage/index.jsx b/packages/webapp/src/components/FilterPage/index.jsx
new file mode 100644
index 0000000000..749c9917b5
--- /dev/null
+++ b/packages/webapp/src/components/FilterPage/index.jsx
@@ -0,0 +1,131 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import Layout from '../Layout';
+import PageTitle from '../PageTitle/v2';
+import { Underlined } from '../Typography';
+import { useTranslation } from 'react-i18next';
+import FilterPillSelect from '../Filter/FilterPillSelect';
+import Button from '../Form/Button';
+import { DATE, DATE_RANGE, PILL_SELECT, SEARCHABLE_MULTI_SELECT } from '../Filter/filterTypes';
+import { FilterDateRange } from '../Filter/FilterDateRange';
+import { FilterMultiSelect } from '../Filter/FilterMultiSelect';
+import { FilterDate } from '../Filter/FilterDate';
+
+const PureFilterPage = ({
+ title,
+ filters,
+ onApply,
+ filterRef,
+ onGoBack,
+ children,
+ resetters = [],
+}) => {
+ const { t } = useTranslation();
+
+ const [shouldReset, setShouldReset] = useState(0);
+ const triggerReset = () => setShouldReset((shouldReset) => shouldReset + 1);
+
+ const resetFilter = () => {
+ triggerReset();
+ for (const resetter of resetters) {
+ const { setFunc, defaultVal } = resetter;
+ setFunc(defaultVal);
+ }
+ setIsDirty(true);
+ };
+
+ const [isDirty, setIsDirty] = useState(false);
+ const setDirty = () => !isDirty && setIsDirty(true);
+
+ return (
+
+ {t('common:APPLY')}
+
+ }
+ >
+
+
+
+ resetFilter()}>
+ {t('FILTER.CLEAR_ALL_FILTERS')}
+
+
+
+ {filters.map((filter) => {
+ if ((filter.type === PILL_SELECT || !filter.type) && filter.options.length > 0) {
+ return (
+
+ );
+ } else if (filter.type === DATE_RANGE) {
+ return (
+
+ );
+ } else if (filter.type === SEARCHABLE_MULTI_SELECT) {
+ return (
+
+ );
+ } else if (filter.type === DATE) {
+ return (
+
+ );
+ }
+ })}
+ {children}
+
+ );
+};
+
+PureFilterPage.prototype = {
+ subject: PropTypes.string,
+ items: PropTypes.array,
+ onGoBack: PropTypes.func,
+ hasDateRangeFilter: PropTypes.bool,
+};
+
+export default PureFilterPage;
+
+// // TRUST THE NATURAL RECURSION
+// const recursiveFilterReset = (filter) => {
+// Object.keys(filter).forEach((key) => {
+// const value = filter[key];
+// if (typeof value === 'boolean') {
+// filter[key] = false;
+// } else {
+// filter[key] = recursiveFilterReset(value);
+// }
+// });
+// return filter;
+// };
diff --git a/packages/webapp/src/components/Finances/DateRangeSelector/index.js b/packages/webapp/src/components/Finances/DateRangeSelector/index.js
deleted file mode 100644
index 1d158cbc60..0000000000
--- a/packages/webapp/src/components/Finances/DateRangeSelector/index.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import styles from './styles.module.scss';
-import DateContainer, { FromToDateContainer } from '../../../components/Inputs/DateContainer';
-import { setDateRange } from '../../../containers/Finances/actions';
-import moment from 'moment';
-import InfoBoxComponent from '../../InfoBoxComponent';
-import { dateRangeSelector } from '../../../containers/Finances/selectors';
-import { Main, Semibold } from '../../Typography';
-import { withTranslation } from 'react-i18next';
-
-class DateRangeSelector extends Component {
- constructor(props) {
- super(props);
- let startDate, endDate;
- const { dateRange } = this.props;
- if (dateRange && dateRange.startDate && dateRange.endDate) {
- startDate = moment(dateRange.startDate);
- endDate = moment(dateRange.endDate);
- } else {
- startDate = moment().startOf('year');
- endDate = moment().endOf('year');
- }
-
- this.state = {
- startDate,
- endDate,
- };
- this.changeStartDate.bind(this);
- this.changeEndDate.bind(this);
- }
-
- changeStartDate = (date) => {
- this.setState({ startDate: date });
- const endDate = this.state.endDate;
- this.props.dispatch(setDateRange({ startDate: date, endDate }));
- this.props.changeDateMethod('start', date);
- };
-
- changeEndDate = (date) => {
- this.setState({ endDate: date });
- const startDate = this.state.startDate;
- this.props.dispatch(setDateRange({ startDate, endDate: date }));
- this.props.changeDateMethod('end', date);
- };
-
- render() {
- const { hideTooltip } = this.props;
- const changeDateToParent = this.props.changeDateMethod;
-
- return (
-
-
-
- {this.props.t('DATE_RANGE.TITLE')}
-
- {!hideTooltip && (
-
- )}
-
-
-
-
- );
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-const mapStateToProps = (state) => {
- return {
- dateRange: dateRangeSelector(state),
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(DateRangeSelector));
diff --git a/packages/webapp/src/components/Finances/DateRangeSelector/index.jsx b/packages/webapp/src/components/Finances/DateRangeSelector/index.jsx
new file mode 100644
index 0000000000..6e7387f6e1
--- /dev/null
+++ b/packages/webapp/src/components/Finances/DateRangeSelector/index.jsx
@@ -0,0 +1,106 @@
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import styles from './styles.module.scss';
+import { FromToDateContainer } from '../../../components/Inputs/DateContainer';
+import { setDateRange } from '../../../containers/Finances/actions';
+import moment from 'moment';
+import InfoBoxComponent from '../../InfoBoxComponent';
+import { dateRangeSelector } from '../../../containers/Finances/selectors';
+import { Semibold } from '../../Typography';
+import { withTranslation } from 'react-i18next';
+
+class DateRangeSelector extends Component {
+ constructor(props) {
+ super(props);
+ let startDate, endDate, validRange;
+ const { dateRange } = this.props;
+ if (dateRange && dateRange.startDate && dateRange.endDate) {
+ startDate = moment(dateRange.startDate);
+ endDate = moment(dateRange.endDate);
+ } else {
+ startDate = moment().startOf('year');
+ endDate = moment().endOf('year');
+ }
+ startDate <= endDate ? (validRange = true) : (validRange = false);
+
+ this.state = {
+ startDate,
+ endDate,
+ validRange,
+ };
+ this.changeStartDate.bind(this);
+ this.changeEndDate.bind(this);
+ }
+
+ changeStartDate = (date) => {
+ if (date > this.state.endDate) {
+ this.setState({ validRange: false });
+ return;
+ }
+ this.setState({ validRange: true });
+ this.setState({ startDate: date });
+ const endDate = this.state.endDate;
+ this.props.dispatch(setDateRange({ startDate: date, endDate }));
+ this.props.changeDateMethod('start', date);
+ };
+
+ changeEndDate = (date) => {
+ if (date < this.state.startDate) {
+ this.setState({ validRange: false });
+ return;
+ }
+ this.setState({ validRange: true });
+ this.setState({ endDate: date });
+ const startDate = this.state.startDate;
+ this.props.dispatch(setDateRange({ startDate, endDate: date }));
+ this.props.changeDateMethod('end', date);
+ };
+
+ render() {
+ const { hideTooltip } = this.props;
+ const changeDateToParent = this.props.changeDateMethod;
+
+ return (
+
+
+
+ {this.props.t('DATE_RANGE.TITLE')}
+
+ {!hideTooltip && (
+
+ )}
+
+
+
+ {!this.state.validRange && (
+
+ {this.props.t('DATE_RANGE.INVALID_RANGE_MESSAGE')}
+
+ )}
+
+ );
+ }
+}
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+const mapStateToProps = (state) => {
+ return {
+ dateRange: dateRangeSelector(state),
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(DateRangeSelector));
diff --git a/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.js b/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.js
deleted file mode 100644
index 69c3df4a4c..0000000000
--- a/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from '../styles.module.scss';
-import clsx from 'clsx';
-import { BsChevronRight } from 'react-icons/bs';
-import { Text } from '../../../Typography';
-import { ReactComponent as CalendarIcon } from '../../../../assets/images/managementPlans/calendar.svg';
-
-const FinanceItem = ({ title, subtitle, amount, isPlan, onClickForward }) => {
- return (
-
-
-
{title}
- {subtitle && (
-
- {isPlan && (
-
-
-
- )}
-
{subtitle}
-
- )}
-
-
{`$${amount.toFixed(2)}`}
- {onClickForward && (
-
- )}
-
- );
-};
-
-FinanceItem.prototype = {
- title: PropTypes.string,
- subtitle: PropTypes.string,
- amount: PropTypes.number,
- isPlan: PropTypes.bool,
- onClickForward: PropTypes.func,
-};
-
-export default FinanceItem;
diff --git a/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.jsx b/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.jsx
new file mode 100644
index 0000000000..5aec171004
--- /dev/null
+++ b/packages/webapp/src/components/Finances/FinanceGroup/GroupItem/index.jsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from '../styles.module.scss';
+import clsx from 'clsx';
+import { BsChevronRight } from 'react-icons/bs';
+import { Text } from '../../../Typography';
+import { ReactComponent as CalendarIcon } from '../../../../assets/images/managementPlans/calendar.svg';
+import grabCurrencySymbol from '../../../../util/grabCurrencySymbol';
+
+const FinanceItem = ({ title, subtitle, amount, isPlan, onClickForward }) => {
+ return (
+
+
+
{title}
+ {subtitle && (
+
+ {isPlan && (
+
+
+
+ )}
+
{subtitle}
+
+ )}
+
+
{`${grabCurrencySymbol()}${amount.toFixed(2)}`}
+ {onClickForward && (
+
+ )}
+
+ );
+};
+
+FinanceItem.prototype = {
+ title: PropTypes.string,
+ subtitle: PropTypes.string,
+ amount: PropTypes.number,
+ isPlan: PropTypes.bool,
+ onClickForward: PropTypes.func,
+};
+
+export default FinanceItem;
diff --git a/packages/webapp/src/components/Finances/FinanceGroup/Header/index.js b/packages/webapp/src/components/Finances/FinanceGroup/Header/index.js
deleted file mode 100644
index 663b60e8ff..0000000000
--- a/packages/webapp/src/components/Finances/FinanceGroup/Header/index.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from '../styles.module.scss';
-import clsx from 'clsx';
-import { BsChevronRight, BsChevronDown } from 'react-icons/bs';
-import { Semibold, Text } from '../../../Typography';
-
-const FinanceGroupHeader = ({
- title,
- subtitle,
- currencyAmount,
- isDropDown,
- open,
- setOpen,
- onClickForward,
-}) => {
- return (
-
-
-
{title}
- {subtitle &&
{subtitle}
}
-
-
{`$${currencyAmount.toFixed(2)}`}
- {isDropDown ? (
-
setOpen(!open)}
- />
- ) : (
-
- )}
-
- );
-};
-
-FinanceGroupHeader.prototype = {
- title: PropTypes.string,
- subtitle: PropTypes.string,
- currencyAmount: PropTypes.number,
- isDropDown: PropTypes.bool,
- open: PropTypes.bool,
- setOpen: PropTypes.func,
- onClickForward: PropTypes.func,
-};
-
-export default FinanceGroupHeader;
diff --git a/packages/webapp/src/components/Finances/FinanceGroup/Header/index.jsx b/packages/webapp/src/components/Finances/FinanceGroup/Header/index.jsx
new file mode 100644
index 0000000000..541b04861c
--- /dev/null
+++ b/packages/webapp/src/components/Finances/FinanceGroup/Header/index.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from '../styles.module.scss';
+import clsx from 'clsx';
+import { BsChevronDown, BsChevronRight } from 'react-icons/bs';
+import { Semibold, Text } from '../../../Typography';
+import grabCurrencySymbol from '../../../../util/grabCurrencySymbol';
+
+const FinanceGroupHeader = ({
+ title,
+ subtitle,
+ currencyAmount,
+ isDropDown,
+ open,
+ setOpen,
+ onClickForward,
+}) => {
+ return (
+
+
+
{title}
+ {subtitle &&
{subtitle}
}
+
+
{`${grabCurrencySymbol()}${currencyAmount.toFixed(
+ 2,
+ )}`}
+ {isDropDown ? (
+
setOpen(!open)}
+ />
+ ) : (
+
+ )}
+
+ );
+};
+
+FinanceGroupHeader.prototype = {
+ title: PropTypes.string,
+ subtitle: PropTypes.string,
+ currencyAmount: PropTypes.number,
+ isDropDown: PropTypes.bool,
+ open: PropTypes.bool,
+ setOpen: PropTypes.func,
+ onClickForward: PropTypes.func,
+};
+
+export default FinanceGroupHeader;
diff --git a/packages/webapp/src/components/Finances/FinanceGroup/index.js b/packages/webapp/src/components/Finances/FinanceGroup/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Finances/FinanceGroup/index.js
rename to packages/webapp/src/components/Finances/FinanceGroup/index.jsx
diff --git a/packages/webapp/src/components/Finances/FinanceListHeader/index.js b/packages/webapp/src/components/Finances/FinanceListHeader/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Finances/FinanceListHeader/index.js
rename to packages/webapp/src/components/Finances/FinanceListHeader/index.jsx
diff --git a/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.js b/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.js
deleted file mode 100644
index 7f86f1030c..0000000000
--- a/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import React, { useEffect } from 'react';
-// import styles from './styles.module.scss';
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import PageTitle from '../../PageTitle/v2';
-import { useTranslation } from 'react-i18next';
-import { useForm } from 'react-hook-form';
-import { Semibold, Text } from '../../Typography';
-import Input, { getInputErrors } from '../../Form/Input';
-import Unit from '../../Form/Unit';
-import { seedYield } from '../../../util/unit';
-import convert from 'convert-units';
-import { roundToTwoDecimal } from '../../../util';
-
-function PureUpdateEstimatedCropRevenue({ system, managementPlan, onGoBack, onSubmit }) {
- const { t } = useTranslation();
-
- const {
- crop,
- crop_variety,
- estimated_price_per_mass,
- estimated_price_per_mass_unit,
- estimated_revenue,
- estimated_yield,
- estimated_yield_unit,
- name,
- } = managementPlan;
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- setError,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: {
- crop_management_plan: {
- estimated_price_per_mass: estimated_price_per_mass ?? undefined,
- estimated_price_per_mass_unit,
- estimated_yield,
- estimated_yield_unit,
- estimated_revenue,
- },
- },
- });
-
- const ESTIMATED_PRICE_PER_UNIT = 'crop_management_plan.estimated_price_per_mass';
- const ESTIMATED_PRICE_PER_UNIT_UNIT = 'crop_management_plan.estimated_price_per_mass_unit';
- const ESTIMATED_ANNUAL_YIELD = 'crop_management_plan.estimated_yield';
- const ESTIMATED_ANNUAL_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
- const ESTIMATED_ANNUAL_REVENUE = 'crop_management_plan.estimated_revenue';
-
- const disabled = !isValid;
-
- const calculateRevenue = (e) => {
- const pricePerMass = getValues(ESTIMATED_PRICE_PER_UNIT);
- const pricePerMassUnit = getValues(ESTIMATED_PRICE_PER_UNIT_UNIT);
- const annualYield = getValues(ESTIMATED_ANNUAL_YIELD);
- const annualYieldUnit = getValues(ESTIMATED_ANNUAL_YIELD_UNIT);
- if (!pricePerMass || !annualYield) return;
- const convertedPricePerMass = roundToTwoDecimal(
- convert(pricePerMass).from(seedYield.databaseUnit).to(pricePerMassUnit.value),
- );
- const convertedAnnualYield = roundToTwoDecimal(
- convert(annualYield).from(seedYield.databaseUnit).to(annualYieldUnit.value),
- );
- if (pricePerMassUnit.value === annualYieldUnit.value) {
- const revenue = roundToTwoDecimal(convertedPricePerMass * convertedAnnualYield);
- setValue(ESTIMATED_ANNUAL_REVENUE, revenue);
- } else {
- const adjustedAnnualYield = roundToTwoDecimal(
- convert(convertedAnnualYield).from(annualYieldUnit.value).to(pricePerMassUnit.value),
- );
- const revenue = roundToTwoDecimal(convertedPricePerMass * adjustedAnnualYield);
- setValue(ESTIMATED_ANNUAL_REVENUE, revenue);
- }
- };
-
- const cropText = crop_variety.crop_variety_name
- ? `${crop_variety.crop_variety_name}, ${t(`crop:${crop.crop_translation_key}`)}`
- : t(`crop:${crop.crop_translation_key}`);
-
- return (
-
- );
-}
-
-export default PureUpdateEstimatedCropRevenue;
diff --git a/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.jsx b/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.jsx
new file mode 100644
index 0000000000..aab8b1eff6
--- /dev/null
+++ b/packages/webapp/src/components/Finances/UpdateEstimatedCropRevenue/index.jsx
@@ -0,0 +1,153 @@
+import React from 'react';
+// import styles from './styles.module.scss';
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import PageTitle from '../../PageTitle/v2';
+import { useTranslation } from 'react-i18next';
+import { useForm } from 'react-hook-form';
+import { Semibold, Text } from '../../Typography';
+import Input, { getInputErrors } from '../../Form/Input';
+import Unit from '../../Form/Unit';
+import { seedYield } from '../../../util/convert-units/unit';
+import { convert } from '../../../util/convert-units/convert';
+import { roundToTwoDecimal } from '../../../util';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+
+function PureUpdateEstimatedCropRevenue({ system, managementPlan, onGoBack, onSubmit }) {
+ const { t } = useTranslation();
+
+ const {
+ crop,
+ crop_variety,
+ estimated_price_per_mass,
+ estimated_price_per_mass_unit,
+ estimated_revenue,
+ estimated_yield,
+ estimated_yield_unit,
+ name,
+ } = managementPlan;
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ setError,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: {
+ crop_management_plan: {
+ estimated_price_per_mass: estimated_price_per_mass ?? undefined,
+ estimated_price_per_mass_unit,
+ estimated_yield,
+ estimated_yield_unit,
+ estimated_revenue,
+ },
+ },
+ });
+
+ const ESTIMATED_PRICE_PER_UNIT = 'crop_management_plan.estimated_price_per_mass';
+ const ESTIMATED_PRICE_PER_UNIT_UNIT = 'crop_management_plan.estimated_price_per_mass_unit';
+ const ESTIMATED_ANNUAL_YIELD = 'crop_management_plan.estimated_yield';
+ const ESTIMATED_ANNUAL_YIELD_UNIT = 'crop_management_plan.estimated_yield_unit';
+ const ESTIMATED_ANNUAL_REVENUE = 'crop_management_plan.estimated_revenue';
+
+ const disabled = !isValid;
+
+ const calculateRevenue = (e) => {
+ const pricePerMass = getValues(ESTIMATED_PRICE_PER_UNIT);
+ const pricePerMassUnit = getValues(ESTIMATED_PRICE_PER_UNIT_UNIT);
+ const annualYield = getValues(ESTIMATED_ANNUAL_YIELD);
+ const annualYieldUnit = getValues(ESTIMATED_ANNUAL_YIELD_UNIT);
+ if (!pricePerMass || !annualYield) return;
+ const convertedPricePerMass = roundToTwoDecimal(
+ convert(pricePerMass).from(seedYield.databaseUnit).to(pricePerMassUnit.value),
+ );
+ const convertedAnnualYield = roundToTwoDecimal(
+ convert(annualYield).from(seedYield.databaseUnit).to(annualYieldUnit.value),
+ );
+ if (pricePerMassUnit.value === annualYieldUnit.value) {
+ const revenue = roundToTwoDecimal(convertedPricePerMass * convertedAnnualYield);
+ setValue(ESTIMATED_ANNUAL_REVENUE, revenue);
+ } else {
+ const adjustedAnnualYield = roundToTwoDecimal(
+ convert(convertedAnnualYield).from(annualYieldUnit.value).to(pricePerMassUnit.value),
+ );
+ const revenue = roundToTwoDecimal(convertedPricePerMass * adjustedAnnualYield);
+ setValue(ESTIMATED_ANNUAL_REVENUE, revenue);
+ }
+ };
+
+ const cropText = crop_variety.crop_variety_name
+ ? `${crop_variety.crop_variety_name}, ${t(`crop:${crop.crop_translation_key}`)}`
+ : t(`crop:${crop.crop_translation_key}`);
+
+ return (
+
+ );
+}
+
+export default PureUpdateEstimatedCropRevenue;
diff --git a/packages/webapp/src/components/Finances/WholeFarmRevenue/index.js b/packages/webapp/src/components/Finances/WholeFarmRevenue/index.js
deleted file mode 100644
index 1b42ebe2e7..0000000000
--- a/packages/webapp/src/components/Finances/WholeFarmRevenue/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import clsx from 'clsx';
-import { gridContainer, gridItem } from '../FinanceGroup/styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import { Semibold } from '../../Typography';
-
-const WholeFarmRevenue = ({ amount, className, ...props }) => {
- const { t } = useTranslation();
-
- return (
-
-
- {t('FINANCES.WHOLE_FARM_REVENUE')}
-
-
- {`$${amount.toFixed(2)}`}
-
-
- );
-};
-
-WholeFarmRevenue.prototype = {
- amount: PropTypes.number,
- className: PropTypes.string,
-};
-
-export default WholeFarmRevenue;
diff --git a/packages/webapp/src/components/Finances/WholeFarmRevenue/index.jsx b/packages/webapp/src/components/Finances/WholeFarmRevenue/index.jsx
new file mode 100644
index 0000000000..8d378300c1
--- /dev/null
+++ b/packages/webapp/src/components/Finances/WholeFarmRevenue/index.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+import { gridContainer, gridItem } from '../FinanceGroup/styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import { Semibold } from '../../Typography';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+
+const WholeFarmRevenue = ({ amount, className, ...props }) => {
+ const { t } = useTranslation();
+
+ return (
+
+
+ {t('FINANCES.WHOLE_FARM_REVENUE')}
+
+
+ {`${grabCurrencySymbol()}${amount.toFixed(2)}`}
+
+
+ );
+};
+
+WholeFarmRevenue.prototype = {
+ amount: PropTypes.number,
+ className: PropTypes.string,
+};
+
+export default WholeFarmRevenue;
diff --git a/packages/webapp/src/components/Footer/index.js b/packages/webapp/src/components/Footer/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Footer/index.js
rename to packages/webapp/src/components/Footer/index.jsx
diff --git a/packages/webapp/src/components/Form/Button/button.module.scss b/packages/webapp/src/components/Form/Button/button.module.scss
index 13a315796d..b537cae9df 100644
--- a/packages/webapp/src/components/Form/Button/button.module.scss
+++ b/packages/webapp/src/components/Form/Button/button.module.scss
@@ -1,4 +1,3 @@
-@import '../../../assets/colors';
@import '../../../assets/mixin';
.primary {
background-color: var(--btnPrimary);
diff --git a/packages/webapp/src/components/Form/Button/index.js b/packages/webapp/src/components/Form/Button/index.js
deleted file mode 100644
index 9a5d23d9e7..0000000000
--- a/packages/webapp/src/components/Form/Button/index.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import styles from './button.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-
-const Button = ({
- color = 'primary',
- children = 'Button',
- sm,
- disabled = false,
- fullLength = false,
- className,
- onClick,
- type,
- inputRef,
- ...props
-}) => {
- return (
-
- {children}
-
- );
-};
-
-Button.propTypes = {
- color: PropTypes.oneOf(['primary', 'secondary', 'success', 'none']),
- disabled: PropTypes.bool,
- fullLength: PropTypes.bool,
- children: PropTypes.node,
- onClick: PropTypes.func,
- type: PropTypes.oneOf(['button', 'submit', 'reset']),
- sm: PropTypes.bool,
- className: PropTypes.string,
- inputRef: PropTypes.oneOfType([
- PropTypes.func,
- PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
- ]),
-};
-
-export default Button;
diff --git a/packages/webapp/src/components/Form/Button/index.tsx b/packages/webapp/src/components/Form/Button/index.tsx
new file mode 100644
index 0000000000..9a5a3c6fc8
--- /dev/null
+++ b/packages/webapp/src/components/Form/Button/index.tsx
@@ -0,0 +1,50 @@
+import React, { ReactNode } from 'react';
+import styles from './button.module.scss';
+import clsx from 'clsx';
+
+type ButtonProps = {
+ color?: | 'primary' | 'secondary' | 'success' | 'none',
+ children?: ReactNode,
+ sm?: boolean,
+ disabled?: boolean,
+ fullLength?: boolean,
+ className?: string,
+ onClick?(): void,
+ type?: 'button' | 'submit' | 'reset',
+ inputRef?: any,
+ id?: string
+}
+
+const Button = ({
+ color = 'primary',
+ children = 'Button',
+ sm,
+ disabled = false,
+ fullLength = false,
+ className,
+ onClick,
+ type,
+ inputRef,
+ ...props
+ }: ButtonProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export default Button;
diff --git a/packages/webapp/src/components/Form/Checkbox/checkbox.module.scss b/packages/webapp/src/components/Form/Checkbox/checkbox.module.scss
index 735f98f7b2..d0b603e3c1 100644
--- a/packages/webapp/src/components/Form/Checkbox/checkbox.module.scss
+++ b/packages/webapp/src/components/Form/Checkbox/checkbox.module.scss
@@ -1,4 +1,3 @@
-@import '../../../assets/colors';
@import '../../../assets/mixin';
.container {
display: inline-block;
diff --git a/packages/webapp/src/components/Form/Checkbox/index.js b/packages/webapp/src/components/Form/Checkbox/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/Checkbox/index.js
rename to packages/webapp/src/components/Form/Checkbox/index.jsx
diff --git a/packages/webapp/src/components/Form/DateRangePicker/index.js b/packages/webapp/src/components/Form/DateRangePicker/index.js
deleted file mode 100644
index 5d7dfddb2e..0000000000
--- a/packages/webapp/src/components/Form/DateRangePicker/index.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import { Error } from '../../Typography';
-import Input from '../Input';
-import { useWatch } from 'react-hook-form';
-
-const FROM_DATE = 'from_date';
-const TO_DATE = 'to_date';
-
-const DateRangePicker = ({
- register,
- getValues,
- control,
- className,
- fromProps = {},
- toProps = {},
- ...props
-}) => {
- const { t } = useTranslation();
-
- const fromDateRegister = register(FROM_DATE, {
- required: true,
- validate: {
- beforeToDate: (v) => v < getValues(TO_DATE),
- },
- });
- const toDateRegister = register(TO_DATE, {
- required: true,
- validate: {
- afterFromDate: (v) => v > getValues(FROM_DATE),
- },
- });
-
- return (
-
- );
-};
-
-const DateError = ({ control, errorMessage }) => {
- const from_date = useWatch({ control, name: FROM_DATE });
- const to_date = useWatch({ control, name: TO_DATE });
- const areDatesProperlySet =
- (from_date && to_date && from_date < to_date) || !from_date || !to_date;
-
- return <>{!areDatesProperlySet && {errorMessage} }>;
-};
-
-DateRangePicker.prototype = {
- register: PropTypes.func.isRequired,
- getValues: PropTypes.func.isRequired,
- control: PropTypes.object.isRequired,
- className: PropTypes.string,
-};
-
-export default DateRangePicker;
diff --git a/packages/webapp/src/components/Form/DateRangePicker/index.jsx b/packages/webapp/src/components/Form/DateRangePicker/index.jsx
new file mode 100644
index 0000000000..f68c5af0ab
--- /dev/null
+++ b/packages/webapp/src/components/Form/DateRangePicker/index.jsx
@@ -0,0 +1,92 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import { Error } from '../../Typography';
+import Input from '../Input';
+import { useWatch } from 'react-hook-form';
+import InfoBoxComponent from '../../InfoBoxComponent';
+
+const FROM_DATE = 'from_date';
+const TO_DATE = 'to_date';
+
+const DateRangePicker = ({
+ register,
+ getValues,
+ control,
+ className,
+ fromProps = {},
+ toProps = {},
+ ...props
+}) => {
+ const { t } = useTranslation();
+
+ const fromDateRegister = register?.(FROM_DATE, {
+ required: true,
+ validate: {
+ beforeToDate: (v) => v < getValues(TO_DATE),
+ },
+ });
+ const toDateRegister = register?.(TO_DATE, {
+ required: true,
+ validate: {
+ afterFromDate: (v) => v > getValues(FROM_DATE),
+ },
+ });
+
+ const pickersWithToolTips = ['Estimated Revenue Date Range'];
+
+ return (
+
+ {pickersWithToolTips.includes(className) && (
+
+ )}
+
+ {control && (
+
+ )}
+
+ );
+};
+
+const DateError = ({ control, errorMessage }) => {
+ const from_date = useWatch({ control, name: FROM_DATE });
+ const to_date = useWatch({ control, name: TO_DATE });
+ const areDatesProperlySet =
+ (from_date && to_date && from_date < to_date) || !from_date || !to_date;
+
+ return <>{!areDatesProperlySet && {errorMessage} }>;
+};
+
+DateRangePicker.prototype = {
+ register: PropTypes.func.isRequired,
+ getValues: PropTypes.func.isRequired,
+ control: PropTypes.object.isRequired,
+ className: PropTypes.string,
+};
+
+export default DateRangePicker;
diff --git a/packages/webapp/src/components/Form/DropDownButton/index.js b/packages/webapp/src/components/Form/DropDownButton/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/DropDownButton/index.js
rename to packages/webapp/src/components/Form/DropDownButton/index.jsx
diff --git a/packages/webapp/src/components/Form/Errors/PasswordError/index.js b/packages/webapp/src/components/Form/Errors/PasswordError/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/Errors/PasswordError/index.js
rename to packages/webapp/src/components/Form/Errors/PasswordError/index.jsx
diff --git a/packages/webapp/src/components/Form/Errors/index.js b/packages/webapp/src/components/Form/Errors/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/Errors/index.js
rename to packages/webapp/src/components/Form/Errors/index.jsx
diff --git a/packages/webapp/src/components/Form/FilePickerWrapper/index.js b/packages/webapp/src/components/Form/FilePickerWrapper/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/FilePickerWrapper/index.js
rename to packages/webapp/src/components/Form/FilePickerWrapper/index.jsx
diff --git a/packages/webapp/src/components/Form/FormTitleLayout.js b/packages/webapp/src/components/Form/FormTitleLayout.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/FormTitleLayout.js
rename to packages/webapp/src/components/Form/FormTitleLayout.jsx
diff --git a/packages/webapp/src/components/Form/Input/index.js b/packages/webapp/src/components/Form/Input/index.js
deleted file mode 100644
index 7a833259ec..0000000000
--- a/packages/webapp/src/components/Form/Input/index.js
+++ /dev/null
@@ -1,206 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import styles from './input.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import { Error, Info, Label } from '../../Typography';
-import { Cross } from '../../Icons';
-import { MdVisibility, MdVisibilityOff } from 'react-icons/md';
-import { BiSearchAlt2 } from 'react-icons/bi';
-import { mergeRefs } from '../utils';
-import { useTranslation } from 'react-i18next';
-import { ReactComponent as Leaf } from '../../../assets/images/signUp/leaf.svg';
-import Infoi from '../../Tooltip/Infoi';
-import { get } from 'react-hook-form';
-import i18n from '../../../locales/i18n';
-
-const Input = ({
- disabled = false,
- classes = {},
- style,
- label,
- optional,
- info,
- errors,
- icon,
- hookFormRegister,
- isSearchBar,
- type = 'text',
- max,
- min,
- toolTipContent,
- unit,
- showCross = true,
- onChange,
- onBlur,
- hasLeaf,
- placeholder,
- currency,
- ...props
-}) => {
- const { t } = useTranslation(['translation', 'common']);
- const name = hookFormRegister?.name ?? props?.name;
-
- const [inputType, setType] = useState(type);
- const isPassword = type === 'password';
- const showPassword = inputType === 'text';
- const setVisibility = () =>
- setType((prevState) => (prevState === 'password' ? 'text' : 'password'));
-
- const [showError, setShowError] = useState();
- useEffect(() => {
- setShowError(!!errors && !disabled);
- }, [errors]);
- const input = useRef();
- const onClear = () => {
- input.current.value = '';
- onChange?.({ target: input.current });
- hookFormRegister?.onChange({ target: input.current });
- setShowError(false);
- };
-
- const onKeyDown = ['number', 'decimal'].includes(type) ? numberOnKeyDown : undefined;
-
- return (
-
- {(label || toolTipContent || icon) && (
-
-
- {label}
- {optional && (
-
- {t('common:OPTIONAL')}
-
- )}
- {hasLeaf && }
-
- {toolTipContent && (
-
-
-
- )}
- {icon &&
{icon} }
-
- )}
- {showError && !unit && showCross && (
-
- )}
- {isSearchBar &&
}
- {isPassword &&
- !showError &&
- (showPassword ? (
-
- ) : (
-
- ))}
- {unit &&
{unit}
}
- {currency &&
{currency}
}
-
{
- onChange?.(e);
- hookFormRegister?.onChange?.(e);
- }}
- onBlur={(e) => {
- if (type === 'number') {
- if (max !== undefined && e.target.value > max) {
- input.current.value = max;
- hookFormRegister?.onChange?.({ target: input.current });
- } else if (min !== undefined && e.target.value < min) {
- input.current.value = min;
- hookFormRegister?.onChange?.({ target: input.current });
- }
- }
- onBlur?.(e);
- hookFormRegister?.onChange?.({ target: input.current });
- hookFormRegister?.onBlur?.(e);
- i18n.t('common:REQUIRED') === errors && setShowError(true);
- }}
- onWheel={type === 'number' ? preventNumberScrolling : undefined}
- {...props}
- />
- {info && !showError &&
{info} }
- {showError ?
{errors} : null}
-
- );
-};
-
-Input.propTypes = {
- disabled: PropTypes.bool,
- label: PropTypes.string,
- optional: PropTypes.bool,
- info: PropTypes.string,
- errors: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
- classes: PropTypes.exact({
- input: PropTypes.object,
- label: PropTypes.object,
- container: PropTypes.object,
- info: PropTypes.object,
- errors: PropTypes.object,
- }),
- icon: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- style: PropTypes.object,
- isSearchBar: PropTypes.bool,
- type: PropTypes.string,
- toolTipContent: PropTypes.string,
- unit: PropTypes.string,
- currency: PropTypes.string,
- name: PropTypes.string,
- hookFormRegister: PropTypes.exact({
- ref: PropTypes.func,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- name: PropTypes.string,
- }),
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- hasLeaf: PropTypes.bool,
- max: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
- min: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
- placeholder: PropTypes.string,
-};
-
-export default Input;
-
-export const numberOnKeyDown = (e) => ['e', 'E', '+', '-'].includes(e.key) && e.preventDefault();
-export const integerOnKeyDown = (e) =>
- ['e', 'E', '+', '-', '.'].includes(e.key) && e.preventDefault();
-export const preventNumberScrolling = (e) => e.target.blur();
-
-export const getInputErrors = (errors, name) => {
- const error = get(errors, name);
- if (error?.type === 'required') {
- return i18n.t('common:REQUIRED');
- } else {
- return error?.message;
- }
-};
diff --git a/packages/webapp/src/components/Form/Input/index.jsx b/packages/webapp/src/components/Form/Input/index.jsx
new file mode 100644
index 0000000000..88368ce373
--- /dev/null
+++ b/packages/webapp/src/components/Form/Input/index.jsx
@@ -0,0 +1,232 @@
+import React, { useEffect, useRef, useState } from 'react';
+import styles from './input.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import { Error, Info, Label } from '../../Typography';
+import { Cross } from '../../Icons';
+import { MdVisibility, MdVisibilityOff } from 'react-icons/md';
+import { BiSearchAlt2 } from 'react-icons/bi';
+import { mergeRefs } from '../utils';
+import { useTranslation } from 'react-i18next';
+import { ReactComponent as Leaf } from '../../../assets/images/signUp/leaf.svg';
+import Infoi from '../../Tooltip/Infoi';
+import { get } from 'react-hook-form';
+import i18n from '../../../locales/i18n';
+import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
+
+const Input = ({
+ disabled = false,
+ classes = {},
+ style,
+ label,
+ optional,
+ info,
+ errors,
+ icon,
+ hookFormRegister,
+ isSearchBar,
+ type = 'text',
+ max,
+ min,
+ toolTipContent,
+ unit,
+ showCross = true,
+ onChange,
+ onBlur,
+ hasLeaf,
+ placeholder,
+ currency,
+ ...props
+}) => {
+ const { t } = useTranslation(['translation', 'common']);
+ const name = hookFormRegister?.name ?? props?.name;
+
+ const [inputType, setType] = useState(type);
+ const isPassword = type === 'password';
+ const showPassword = inputType === 'text';
+ const setVisibility = () =>
+ setType((prevState) => (prevState === 'password' ? 'text' : 'password'));
+
+ const [showError, setShowError] = useState();
+ useEffect(() => {
+ setShowError(!!errors && !disabled);
+ }, [errors]);
+ const input = useRef();
+ const onClear = () => {
+ input.current.value = '';
+ onChange?.({ target: input.current });
+ hookFormRegister?.onChange({ target: input.current });
+ setShowError(false);
+ };
+
+ const onKeyDown = ['number', 'decimal'].includes(type) ? numberOnKeyDown : undefined;
+
+ return (
+
+ {(label || toolTipContent || icon) && (
+
+
+ {label}
+ {optional && (
+
+ {t('common:OPTIONAL')}
+
+ )}
+ {hasLeaf && }
+
+ {toolTipContent && (
+
+
+
+ )}
+ {icon &&
{icon} }
+
+ )}
+ {showError && !unit && showCross && (
+
+ )}
+ {isSearchBar &&
}
+ {isPassword &&
+ !showError &&
+ (showPassword ? (
+
+ ) : (
+
+ ))}
+ {unit &&
{unit}
}
+ {currency &&
{currency}
}
+
{
+ onChange?.(e);
+ hookFormRegister?.onChange?.(e);
+ }}
+ onBlur={(e) => {
+ if (type === 'number') {
+ if (max !== undefined && e.target.value > max) {
+ input.current.value = max;
+ hookFormRegister?.onChange?.({ target: input.current });
+ } else if (min !== undefined && e.target.value < min) {
+ input.current.value = min;
+ hookFormRegister?.onChange?.({ target: input.current });
+ }
+ }
+ onBlur?.(e);
+ hookFormRegister?.onChange?.({ target: input.current });
+ hookFormRegister?.onBlur?.(e);
+ i18n.t('common:REQUIRED') === errors && setShowError(true);
+ }}
+ onWheel={type === 'number' ? preventNumberScrolling : undefined}
+ {...props}
+ />
+ {info && !showError &&
{info} }
+ {showError ?
{errors} : null}
+
+ );
+};
+
+Input.propTypes = {
+ disabled: PropTypes.bool,
+ label: PropTypes.string,
+ optional: PropTypes.bool,
+ info: PropTypes.string,
+ errors: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+ classes: PropTypes.exact({
+ input: PropTypes.object,
+ label: PropTypes.object,
+ container: PropTypes.object,
+ info: PropTypes.object,
+ errors: PropTypes.object,
+ }),
+ icon: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ style: PropTypes.object,
+ isSearchBar: PropTypes.bool,
+ type: PropTypes.string,
+ toolTipContent: PropTypes.string,
+ unit: PropTypes.string,
+ currency: PropTypes.string,
+ name: PropTypes.string,
+ hookFormRegister: PropTypes.exact({
+ ref: PropTypes.func,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ name: PropTypes.string,
+ }),
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ hasLeaf: PropTypes.bool,
+ max: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ min: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+ placeholder: PropTypes.string,
+};
+
+export default Input;
+
+/**
+ * Indicates if a keyboard event should be accepted for an integer form input.
+ * @param {KeyboardEvent} event
+ * @returns {boolean} true if the event is acceptable; false otherwise
+ */
+const isEventOkForIntegerInput = (event) => {
+ if (event.key.length > 1) return true; // Accept "Backspace", etc.
+ return /[0-9]/.test(event.key); // Accept a digit, but no other single character.
+};
+
+/**
+ * Always accepts backspace, arrow keys, and numbers.
+ * Only accepts one period and only after 1 or more numbers.
+ */
+export const numberOnKeyDown = (event) => {
+ if (event.key.length == 1) {
+ if (event.target.value.length == 0 || /\./.test(event.target.value)) {
+ !/[0-9]/.test(event.key) && event.preventDefault();
+ } else {
+ !/[0-9]|\./.test(event.key) && event.preventDefault();
+ }
+ }
+};
+
+export const integerOnKeyDown = (event) => {
+ if (isEventOkForIntegerInput(event)) return;
+ event.preventDefault();
+};
+export const preventNumberScrolling = (e) => e.target.blur();
+
+export const getInputErrors = (errors, name) => {
+ const error = get(errors, name);
+ if (error?.type === 'required') {
+ return i18n.t('common:REQUIRED');
+ } else {
+ return error?.message;
+ }
+};
diff --git a/packages/webapp/src/components/Form/Input/input.module.scss b/packages/webapp/src/components/Form/Input/input.module.scss
index 8e6f51f09a..a8951e0185 100644
--- a/packages/webapp/src/components/Form/Input/input.module.scss
+++ b/packages/webapp/src/components/Form/Input/input.module.scss
@@ -1,4 +1,3 @@
-@import '../../../assets/colors';
.input {
border: 1px solid var(--grey400);
box-sizing: border-box;
diff --git a/packages/webapp/src/components/Form/InputAutoSize/index.js b/packages/webapp/src/components/Form/InputAutoSize/index.js
deleted file mode 100644
index aca36ff1f7..0000000000
--- a/packages/webapp/src/components/Form/InputAutoSize/index.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import PropTypes from 'prop-types';
-import { Error, Label } from '../../Typography';
-import React, { useEffect, useRef, useState } from 'react';
-import clsx from 'clsx';
-import styles from './styles.module.scss';
-import { mergeRefs } from '../utils';
-import { TextareaAutosize } from '@material-ui/core';
-import { useTranslation } from 'react-i18next';
-
-export default function InputAutoSize({
- classes = {},
- rowsMax = 4,
- rowsMin = 1,
- style,
- label,
- hookFormRegister,
- onBlur,
- optional,
- onChange,
- errors,
- ...props
-}) {
- const input = useRef();
- const name = hookFormRegister?.name ?? props?.name;
- const { t } = useTranslation(['translation', 'common']);
-
- return (
-
- {label && (
-
- {label}
- {optional && (
-
- {t('common:OPTIONAL')}
-
- )}
-
- )}
-
- {
- onChange?.(e);
- hookFormRegister?.onChange(e);
- }}
- onBlur={(e) => {
- onBlur?.(e);
- hookFormRegister?.onBlur(e);
- }}
- {...props}
- />
- {errors ? {errors} : null}
-
- );
-}
-
-InputAutoSize.propTypes = {
- label: PropTypes.string,
- classes: PropTypes.exact({
- input: PropTypes.object,
- label: PropTypes.object,
- container: PropTypes.object,
- info: PropTypes.object,
- }),
- hookFormRegister: PropTypes.exact({
- ref: PropTypes.func,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- name: PropTypes.string,
- }),
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- style: PropTypes.object,
- rowsMin: PropTypes.number,
- rowsMax: PropTypes.number,
- optional: PropTypes.bool,
- errors: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
-};
diff --git a/packages/webapp/src/components/Form/InputAutoSize/index.jsx b/packages/webapp/src/components/Form/InputAutoSize/index.jsx
new file mode 100644
index 0000000000..94a54d0f1a
--- /dev/null
+++ b/packages/webapp/src/components/Form/InputAutoSize/index.jsx
@@ -0,0 +1,85 @@
+import PropTypes from 'prop-types';
+import { Error, Label } from '../../Typography';
+import React, { useRef } from 'react';
+import clsx from 'clsx';
+import styles from './styles.module.scss';
+import { mergeRefs } from '../utils';
+import { TextareaAutosize } from '@material-ui/core';
+import { useTranslation } from 'react-i18next';
+
+export default function InputAutoSize({
+ classes = {},
+ rowsMax = 4,
+ rowsMin = 1,
+ style,
+ label,
+ hookFormRegister,
+ onBlur,
+ optional,
+ onChange,
+ errors,
+ ...props
+}) {
+ const input = useRef();
+ const name = hookFormRegister?.name ?? props?.name;
+ const { t } = useTranslation(['translation', 'common']);
+
+ return (
+
+ {label && (
+
+ {label}
+ {optional && (
+
+ {t('common:OPTIONAL')}
+
+ )}
+
+ )}
+
+ {
+ onChange?.(e);
+ hookFormRegister?.onChange(e);
+ }}
+ onBlur={(e) => {
+ onBlur?.(e);
+ hookFormRegister?.onBlur(e);
+ }}
+ {...props}
+ />
+ {errors ? {errors} : null}
+
+ );
+}
+
+InputAutoSize.propTypes = {
+ label: PropTypes.string,
+ classes: PropTypes.exact({
+ input: PropTypes.object,
+ label: PropTypes.object,
+ container: PropTypes.object,
+ info: PropTypes.object,
+ }),
+ hookFormRegister: PropTypes.exact({
+ ref: PropTypes.func,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ name: PropTypes.string,
+ }),
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ style: PropTypes.object,
+ rowsMin: PropTypes.number,
+ rowsMax: PropTypes.number,
+ optional: PropTypes.bool,
+ errors: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
+};
diff --git a/packages/webapp/src/components/Form/InputDuration/index.js b/packages/webapp/src/components/Form/InputDuration/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/InputDuration/index.js
rename to packages/webapp/src/components/Form/InputDuration/index.jsx
diff --git a/packages/webapp/src/components/Form/NativeDatePicker/NativeDatePickerWrapper/index.js b/packages/webapp/src/components/Form/NativeDatePicker/NativeDatePickerWrapper/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/NativeDatePicker/NativeDatePickerWrapper/index.js
rename to packages/webapp/src/components/Form/NativeDatePicker/NativeDatePickerWrapper/index.jsx
diff --git a/packages/webapp/src/components/Form/Radio/index.js b/packages/webapp/src/components/Form/Radio/index.js
deleted file mode 100644
index c6c02829c2..0000000000
--- a/packages/webapp/src/components/Form/Radio/index.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React from 'react';
-import styles from './radio.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import Infoi from '../../Tooltip/Infoi';
-
-const Radio = ({
- label = 'label',
- disabled = false,
- classes = {},
- children,
- style,
- hookFormRegister,
- onChange,
- onBlur,
- inputRef,
- toolTipContent,
- ...props
-}) => {
- const name = hookFormRegister?.name ?? props?.name;
- return (
-
- {
- onChange?.(e);
- hookFormRegister?.onChange(e);
- }}
- onBlur={(e) => {
- onBlur?.(e);
- hookFormRegister?.onBlur(e);
- }}
- type={'radio'}
- {...props}
- disabled={disabled}
- />
-
- {label}
-
- {toolTipContent && }
-
-
- {children}
-
- );
-};
-
-Radio.propTypes = {
- label: PropTypes.string,
- disabled: PropTypes.bool,
- classes: PropTypes.exact({
- checkbox: PropTypes.object,
- label: PropTypes.object,
- container: PropTypes.object,
- }),
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- hookFormRegister: PropTypes.exact({
- ref: PropTypes.func,
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
- name: PropTypes.string,
- }),
- onChange: PropTypes.func,
- onBlur: PropTypes.func,
-};
-
-export default Radio;
diff --git a/packages/webapp/src/components/Form/Radio/index.jsx b/packages/webapp/src/components/Form/Radio/index.jsx
new file mode 100644
index 0000000000..8e277616c6
--- /dev/null
+++ b/packages/webapp/src/components/Form/Radio/index.jsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import styles from './radio.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import Infoi from '../../Tooltip/Infoi';
+
+const Radio = ({
+ label = 'label',
+ disabled = false,
+ classes = {},
+ children,
+ style,
+ hookFormRegister,
+ onChange,
+ onBlur,
+ inputRef,
+ toolTipContent,
+ ...props
+}) => {
+ const name = hookFormRegister?.name ?? props?.name;
+ return (
+
+ {
+ onChange?.(e);
+ hookFormRegister?.onChange(e);
+ }}
+ onBlur={(e) => {
+ onBlur?.(e);
+ hookFormRegister?.onBlur(e);
+ }}
+ type={'radio'}
+ {...props}
+ disabled={disabled}
+ />
+
+ {label}
+
+ {toolTipContent && }
+
+
+ {children}
+
+ );
+};
+
+Radio.propTypes = {
+ label: PropTypes.node,
+ disabled: PropTypes.bool,
+ classes: PropTypes.exact({
+ checkbox: PropTypes.object,
+ label: PropTypes.object,
+ container: PropTypes.object,
+ }),
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ hookFormRegister: PropTypes.exact({
+ ref: PropTypes.func,
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+ name: PropTypes.string,
+ }),
+ onChange: PropTypes.func,
+ onBlur: PropTypes.func,
+};
+
+export default Radio;
diff --git a/packages/webapp/src/components/Form/Radio/radio.module.scss b/packages/webapp/src/components/Form/Radio/radio.module.scss
index cb264f53a0..f7c7efaf69 100644
--- a/packages/webapp/src/components/Form/Radio/radio.module.scss
+++ b/packages/webapp/src/components/Form/Radio/radio.module.scss
@@ -1,4 +1,3 @@
-@import '../../../assets/colors';
@import '../../../assets/mixin';
.container {
display: flex;
diff --git a/packages/webapp/src/components/Form/RadioGroup/index.js b/packages/webapp/src/components/Form/RadioGroup/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/RadioGroup/index.js
rename to packages/webapp/src/components/Form/RadioGroup/index.jsx
diff --git a/packages/webapp/src/components/Form/ReactSelect/index.js b/packages/webapp/src/components/Form/ReactSelect/index.js
deleted file mode 100644
index 4e3d7bfa6f..0000000000
--- a/packages/webapp/src/components/Form/ReactSelect/index.js
+++ /dev/null
@@ -1,267 +0,0 @@
-import React from 'react';
-import Select from 'react-select';
-import CreatableSelect from 'react-select/creatable';
-import PropTypes from 'prop-types';
-import { Label, Underlined } from '../../Typography';
-import { useTranslation } from 'react-i18next';
-import { colors } from '../../../assets/theme';
-import Infoi from '../../Tooltip/Infoi';
-
-export const styles = {
- option: (provided, state) => ({
- ...provided,
- backgroundColor: 'white',
- '&:hover': {
- backgroundColor: 'var(--green100)',
- },
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--fontColor)',
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: '"Open Sans", "SansSerif", serif',
- paddingLeft: '10px',
- }),
- groupHeading: (provided, state) => ({
- ...provided,
- backgroundColor: 'white',
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--fontColor)',
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: '"Open Sans", "SansSerif", serif',
- paddingLeft: '10px',
- '&:hover': {
- backgroundColor: 'var(--green100)',
- },
- textTransform: 'capitalize',
- height: '40px',
- display: 'flex',
- alignItems: 'center',
- }),
-
- indicatorSeparator: () => ({}),
-
- control: (provided, state) => ({
- display: 'flex',
- border: `1px solid var(--grey400)`,
- boxShadow: 'none',
- boxSizing: 'border-box',
- borderRadius: '4px',
- minHeight: '48px',
- paddingLeft: '0',
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--fontColor)',
- borderColor: state.isFocused ? 'var(--inputActive)' : 'var(--grey400)',
- '&:hover': {
- borderColor: 'var(--inputActive)',
- },
- }),
-
- menu: (provided, state) => ({
- ...provided,
- marginTop: '4px',
- padding: '4px 0',
- boxShadow: '0px 1px 2px rgba(102, 115, 138, 0.25)',
- borderColor: 'transparent',
- }),
-
- placeholder: () => ({
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--iconDefault)',
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: '"Open Sans", "SansSerif", serif',
- }),
-
- singleValue: () => ({
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--fontColor)',
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: '"Open Sans", "SansSerif", serif',
- }),
-
- multiValueLabel: (provided, state) => ({
- ...provided,
- fontSize: '12px',
- lineHeight: '16px',
- }),
- multiValue: (provided, state) => ({
- ...provided,
- height: '24px',
- margin: '4px',
- }),
- valueContainer: (provided, state) => ({
- ...provided,
- padding: '8px',
- maxHeight: '144px',
- overflowY: 'scroll',
- '::-webkit-scrollbar': { display: 'none' },
- scrollbarWidth: 'none',
- msOverflowStyle: 'none',
- }),
- indicatorsContainer: (provided, state) => ({
- ...provided,
- alignItems: 'flex-start',
- }),
- dropdownIndicator: (provided, state) => ({
- ...provided,
- paddingTop: '14px',
- }),
- clearIndicator: () => ({}),
-};
-
-const ReactSelect = React.forwardRef(
- (
- {
- label,
- optional,
- placeholder,
- options,
- toolTipContent,
- icon,
- style,
- autoOpen,
- components,
- isSearchable,
- defaultValue,
- creatable = false,
- isDisabled = false,
- ...props
- },
- ref,
- ) => {
- const { t } = useTranslation();
- return (
-
- {(label || toolTipContent || icon) && (
-
-
- {label}
- {optional && (
-
- {t('common:OPTIONAL')}
-
- )}
-
- {toolTipContent && (
-
-
-
- )}
- {icon && (
-
- {icon}
-
- )}
-
- )}{' '}
- {creatable && (
-
({
- ...provided,
- color: isDisabled ? 'var(--grey600)' : null,
- }),
- container: (provided, state) => ({
- ...provided,
- backgroundColor: isDisabled ? 'var(--inputDisabled)' : null,
- }),
- }}
- placeholder={placeholder}
- options={options}
- components={{
- ClearIndicator: ({ innerProps }) => (
-
- {t('REACT_SELECT.CLEAR')}
-
- ),
- ...components,
- }}
- isSearchable={options?.length > 8 || isSearchable}
- inputRef={ref}
- defaultValue={defaultValue}
- isDisabled={isDisabled}
- isClearable={true}
- {...props}
- />
- )}
- {!creatable && (
- ({
- ...provided,
- color: isDisabled ? 'var(--grey600)' : null,
- }),
- container: (provided, state) => ({
- ...provided,
- backgroundColor: isDisabled ? 'var(--inputDisabled)' : null,
- }),
- }}
- placeholder={placeholder}
- options={options}
- components={{
- ClearIndicator: ({ innerProps }) => (
-
- {t('REACT_SELECT.CLEAR_ALL')}
-
- ),
- ...components,
- }}
- isSearchable={options?.length > 8 || isSearchable}
- inputRef={ref}
- defaultValue={defaultValue}
- isDisabled={isDisabled}
- {...props}
- />
- )}
-
- );
- },
-);
-
-ReactSelect.propTypes = {
- label: PropTypes.string,
- toolTipContent: PropTypes.string,
- icon: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- placeholder: PropTypes.string,
- autoOpen: PropTypes.bool,
- style: PropTypes.objectOf(PropTypes.string),
- /**
- To use with react-hook-form see page https://react-hook-form.com/api/#Controller and sandbox https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js:3850-3861
- */
- options: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.string, value: PropTypes.any })),
- components: PropTypes.object,
-};
-export default ReactSelect;
diff --git a/packages/webapp/src/components/Form/ReactSelect/index.jsx b/packages/webapp/src/components/Form/ReactSelect/index.jsx
new file mode 100644
index 0000000000..789542734f
--- /dev/null
+++ b/packages/webapp/src/components/Form/ReactSelect/index.jsx
@@ -0,0 +1,295 @@
+import React from 'react';
+import Select from 'react-select';
+import CreatableSelect from 'react-select/creatable';
+import PropTypes from 'prop-types';
+import { Label, Underlined } from '../../Typography';
+import { useTranslation } from 'react-i18next';
+import { colors } from '../../../assets/theme';
+import Infoi from '../../Tooltip/Infoi';
+import { BsX } from 'react-icons/bs';
+
+export const styles = {
+ option: (provided, state) => ({
+ ...provided,
+ backgroundColor: 'white',
+ '&:hover': {
+ backgroundColor: 'var(--green100)',
+ },
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: state.isDisabled ? 'var(--grey400)' : 'var(--fontColor)',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: '"Open Sans", "SansSerif", serif',
+ paddingLeft: '10px',
+ minHeight: '40px',
+ }),
+ groupHeading: (provided, state) => ({
+ ...provided,
+ backgroundColor: 'white',
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--fontColor)',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: '"Open Sans", "SansSerif", serif',
+ paddingLeft: '10px',
+ '&:hover': {
+ backgroundColor: 'var(--green100)',
+ },
+ textTransform: 'capitalize',
+ height: '40px',
+ display: 'flex',
+ alignItems: 'center',
+ }),
+
+ indicatorSeparator: () => ({}),
+
+ control: (provided, state) => ({
+ display: 'flex',
+ border: `1px solid var(--grey400)`,
+ boxShadow: 'none',
+ boxSizing: 'border-box',
+ borderRadius: '4px',
+ minHeight: '48px',
+ paddingLeft: '0',
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--fontColor)',
+ borderColor: state.isFocused ? 'var(--inputActive)' : 'var(--grey400)',
+ '&:hover': {
+ borderColor: 'var(--inputActive)',
+ },
+ }),
+
+ menu: (provided, state) => ({
+ ...provided,
+ marginTop: '4px',
+ padding: '4px 0',
+ boxShadow: '0px 1px 2px rgba(102, 115, 138, 0.25)',
+ borderColor: 'transparent',
+ }),
+
+ placeholder: (provided) => ({
+ ...provided,
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--iconDefault)',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: '"Open Sans", "SansSerif", serif',
+ }),
+
+ singleValue: () => ({
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--fontColor)',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: '"Open Sans", "SansSerif", serif',
+ }),
+ multiValueRemove: (provided, state) => ({
+ ...provided,
+ color: 'white',
+ cursor: 'pointer',
+ fontSize: '18px',
+ '&:hover': {
+ backgroundColor: 'transparent',
+ color: 'white',
+ },
+ }),
+
+ multiValueLabel: (provided, state) => ({
+ ...provided,
+ fontSize: '14px',
+ lineHeight: '24px',
+ color: 'white',
+ padding: 0,
+ }),
+ multiValue: (provided, state) => ({
+ ...provided,
+ borderRadius: '32px',
+ padding: '0 12px',
+ border: '1px solid var(--teal700)',
+ fontWeight: 600,
+ backgroundColor: colors.teal600,
+ minHeight: '26px',
+ }),
+
+ valueContainer: (provided, state) => ({
+ ...provided,
+ padding: '8px',
+ maxHeight: '144px',
+ overflowY: 'scroll',
+ '::-webkit-scrollbar': { display: 'none' },
+ scrollbarWidth: 'none',
+ msOverflowStyle: 'none',
+ }),
+ indicatorsContainer: (provided, state) => ({
+ ...provided,
+ alignItems: 'flex-start',
+ }),
+ dropdownIndicator: (provided, state) => ({
+ ...provided,
+ paddingTop: '14px',
+ }),
+ clearIndicator: () => ({}),
+};
+
+const ReactSelect = React.forwardRef(function ReactSelect(
+ {
+ label,
+ optional,
+ placeholder,
+ createPromptText,
+ options,
+ toolTipContent,
+ icon,
+ style,
+ autoOpen,
+ components,
+ isSearchable,
+ defaultValue,
+ creatable = false,
+ isDisabled = false,
+ ...props
+ },
+ ref,
+) {
+ const { t } = useTranslation();
+ if (!placeholder) placeholder = t('common:SELECT') + '...';
+ if (!createPromptText) createPromptText = t('common:CREATE');
+
+ return (
+
+ {(label || toolTipContent || icon) && (
+
+
+ {label}
+ {optional && (
+
+ {t('common:OPTIONAL')}
+
+ )}
+
+ {toolTipContent && (
+
+
+
+ )}
+ {icon && (
+
+ {icon}
+
+ )}
+
+ )}{' '}
+ {creatable && (
+
`${createPromptText} "${userInput}"`}
+ styles={{
+ ...styles,
+ singleValue: (provided, state) => ({
+ ...provided,
+ color: isDisabled ? 'var(--grey600)' : null,
+ }),
+ container: (provided, state) => ({
+ ...provided,
+ backgroundColor: isDisabled ? 'var(--inputDisabled)' : null,
+ }),
+ }}
+ placeholder={placeholder}
+ options={options}
+ components={{
+ ClearIndicator: ({ innerProps }) => (
+
+ {t('REACT_SELECT.CLEAR')}
+
+ ),
+ ...components,
+ }}
+ isSearchable={options?.length > 8 || isSearchable}
+ ref={ref}
+ defaultValue={defaultValue}
+ isDisabled={isDisabled}
+ isClearable={true}
+ {...props}
+ />
+ )}
+ {!creatable && (
+ ({
+ ...provided,
+ color: isDisabled ? 'var(--grey600)' : null,
+ }),
+ container: (provided, state) => ({
+ ...provided,
+ backgroundColor: isDisabled ? 'var(--inputDisabled)' : null,
+ }),
+ }}
+ placeholder={placeholder}
+ options={options}
+ components={{
+ ClearIndicator: ({ innerProps }) => (
+
+ {t('REACT_SELECT.CLEAR_ALL')}
+
+ ),
+ MultiValueRemove: ({ innerProps }) => (
+
+
+
+ ),
+ ...components,
+ }}
+ isSearchable={options?.length > 8 || isSearchable}
+ ref={ref}
+ defaultValue={defaultValue}
+ isDisabled={isDisabled}
+ {...props}
+ />
+ )}
+
+ );
+});
+
+ReactSelect.propTypes = {
+ label: PropTypes.string,
+ toolTipContent: PropTypes.string,
+ icon: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+ placeholder: PropTypes.string,
+ autoOpen: PropTypes.bool,
+ style: PropTypes.objectOf(PropTypes.string),
+ /**
+ To use with react-hook-form see page https://react-hook-form.com/api/#Controller and sandbox https://codesandbox.io/s/react-hook-form-controller-079xx?file=/src/index.js:3850-3861
+ */
+ options: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.string, value: PropTypes.any })),
+ components: PropTypes.object,
+};
+export default ReactSelect;
diff --git a/packages/webapp/src/components/Form/Slider/TimeSlider.js b/packages/webapp/src/components/Form/Slider/TimeSlider.js
deleted file mode 100644
index 8950f9b04a..0000000000
--- a/packages/webapp/src/components/Form/Slider/TimeSlider.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { Slider } from '@material-ui/core';
-import { getDuration } from './../../../util/index';
-import { withStyles } from '@material-ui/core/styles';
-import sliderStyles from './slider.module.scss';
-import { Semibold, Main, Label } from '../../Typography';
-import styles from '../../Typography/typography.module.scss';
-import clsx from 'clsx';
-
-const CustomSlider = withStyles({
- root: {
- color: '--teal900',
- height: 2,
- padding: '15px 0',
- },
-})(Slider);
-
-const TimeSlider = ({
- classes = {},
- initialTime = 15,
- step = 15,
- minimum = 15,
- max = 720,
- style,
- label,
- setValue,
- ...props
-}) => {
- const [time, setTime] = useState(initialTime);
- const [duration, setDuration] = useState({ hours: 0, minutes: 0 });
- useEffect(() => {
- const { getDurationString, ...data } = getDuration(time);
- setDuration(data);
- setValue(time);
- }, [time]);
- const getTimeTag = (time, unit) => (
- <>
- {time}
- {unit} {' '}
- >
- );
-
- return (
- <>
- {label ? label : ''}
-
-
- {!duration.hours && !duration.minutes && (
- 0m
- )}
- <>
- {!!duration.hours && getTimeTag(duration.hours, duration.hours > 1 ? 'hrs' : 'hr')}
- {!!duration.minutes && getTimeTag(duration.minutes, 'mins')}
- >
-
-
- setTime(value)}
- max={max}
- {...props}
- />
-
-
- >
- );
-};
-
-TimeSlider.propTypes = {};
-
-export default TimeSlider;
diff --git a/packages/webapp/src/components/Form/Slider/TimeSlider.jsx b/packages/webapp/src/components/Form/Slider/TimeSlider.jsx
new file mode 100644
index 0000000000..f47ecd07de
--- /dev/null
+++ b/packages/webapp/src/components/Form/Slider/TimeSlider.jsx
@@ -0,0 +1,73 @@
+import React, { useEffect, useState } from 'react';
+import { Slider } from '@material-ui/core';
+import { getDuration } from './../../../util/index';
+import { withStyles } from '@material-ui/core/styles';
+import sliderStyles from './slider.module.scss';
+import { Label, Semibold } from '../../Typography';
+import styles from '../../Typography/typography.module.scss';
+import clsx from 'clsx';
+
+const CustomSlider = withStyles({
+ root: {
+ color: '--teal900',
+ height: 2,
+ padding: '15px 0',
+ },
+})(Slider);
+
+const TimeSlider = ({
+ classes = {},
+ initialTime = 15,
+ step = 15,
+ minimum = 15,
+ max = 720,
+ style,
+ label,
+ setValue,
+ ...props
+}) => {
+ const [time, setTime] = useState(initialTime);
+ const [duration, setDuration] = useState({ hours: 0, minutes: 0 });
+ useEffect(() => {
+ const { getDurationString, ...data } = getDuration(time);
+ setDuration(data);
+ setValue(time);
+ }, [time]);
+ const getTimeTag = (time, unit) => (
+ <>
+ {time}
+ {unit} {' '}
+ >
+ );
+
+ return (
+ <>
+ {label ? label : ''}
+
+
+ {!duration.hours && !duration.minutes && (
+ 0m
+ )}
+ <>
+ {!!duration.hours && getTimeTag(duration.hours, duration.hours > 1 ? 'hrs' : 'hr')}
+ {!!duration.minutes && getTimeTag(duration.minutes, 'mins')}
+ >
+
+
+ setTime(value)}
+ max={max}
+ {...props}
+ />
+
+
+ >
+ );
+};
+
+TimeSlider.propTypes = {};
+
+export default TimeSlider;
diff --git a/packages/webapp/src/components/Form/Switch/index.jsx b/packages/webapp/src/components/Form/Switch/index.jsx
new file mode 100644
index 0000000000..e15335be43
--- /dev/null
+++ b/packages/webapp/src/components/Form/Switch/index.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import { Main } from '../../Typography';
+
+const Switch = ({ checked, onChange, label, ...props }) => {
+ return (
+
+
+
+
+
+ {label && {label} }
+
+ );
+};
+
+Switch.propTypes = {
+ onChange: PropTypes.func,
+ label: PropTypes.string,
+ checked: PropTypes.bool,
+};
+
+export default Switch;
diff --git a/packages/webapp/src/components/Form/Switch/styles.module.scss b/packages/webapp/src/components/Form/Switch/styles.module.scss
new file mode 100644
index 0000000000..6d4c842b63
--- /dev/null
+++ b/packages/webapp/src/components/Form/Switch/styles.module.scss
@@ -0,0 +1,60 @@
+.switch {
+ position: relative;
+ display: inline-block;
+ width: 24px;
+ height: 16px;
+}
+
+/* Hide default HTML checkbox */
+.switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+}
+
+/* The slider */
+.slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--grey400);
+ -webkit-transition: .1s;
+ transition: .1s;
+}
+
+.slider:before {
+ position: absolute;
+ content: "";
+ height: 10px;
+ width: 10px;
+ left: 3px;
+ bottom: 3px;
+ background-color: white;
+ -webkit-transition: .1s;
+ transition: .1s;
+}
+
+input:checked + .slider {
+ background-color: var(--teal700);
+}
+
+input:checked + .slider:before {
+ transform: translateX(8px);
+}
+
+/* Rounded sliders */
+.slider.round {
+ border-radius: 34px;
+}
+
+.slider.round:before {
+ border-radius: 50%;
+}
+.container{
+ display: flex;
+ column-gap: 8px;
+ align-items: center;
+}
diff --git a/packages/webapp/src/components/Form/TextArea/index.js b/packages/webapp/src/components/Form/TextArea/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/TextArea/index.js
rename to packages/webapp/src/components/Form/TextArea/index.jsx
diff --git a/packages/webapp/src/components/Form/Unit/index.js b/packages/webapp/src/components/Form/Unit/index.js
deleted file mode 100644
index d9c0ee6e4a..0000000000
--- a/packages/webapp/src/components/Form/Unit/index.js
+++ /dev/null
@@ -1,436 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useState } from 'react';
-import styles from './unit.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import { Error, Info, Label } from '../../Typography';
-import { Cross } from '../../Icons';
-import { useTranslation } from 'react-i18next';
-import i18n from '../../../locales/i18n';
-import { integerOnKeyDown, numberOnKeyDown, preventNumberScrolling } from '../Input';
-import Select from 'react-select';
-import { styles as reactSelectDefaultStyles } from '../ReactSelect';
-import convert from 'convert-units';
-import { area_total_area, getDefaultUnit, roundToTwoDecimal } from '../../../util/unit';
-import Infoi from '../../Tooltip/Infoi';
-import { Controller, get, useFormState } from 'react-hook-form';
-import { ReactComponent as Leaf } from '../../../assets/images/signUp/leaf.svg';
-
-export const getUnitOptionMap = () => ({
- m2: { label: 'm²', value: 'm2' },
- ha: { label: 'ha', value: 'ha' },
- ft2: { label: 'ft²', value: 'ft2' },
- ac: { label: 'ac', value: 'ac' },
- cm: { label: 'cm', value: 'cm' },
- m: { label: 'm', value: 'm' },
- km: { label: 'km', value: 'km' },
- in: { label: 'in', value: 'in' },
- ft: { label: 'ft', value: 'ft' },
- 'fl-oz': { label: 'fl oz', value: 'fl-oz' },
- gal: { label: 'gal', value: 'gal' },
- l: { label: 'l', value: 'l' },
- ml: { label: 'ml', value: 'ml' },
- mi: { label: 'mi', value: 'mi' },
- 'l/min': { label: 'l/m', value: 'l/min' },
- 'l/h': { label: 'l/h', value: 'l/h' },
- 'gal/min': { label: 'g/m', value: 'gal/min' },
- 'gal/h': { label: 'g/h', value: 'gal/h' },
- g: { label: 'g', value: 'g' },
- kg: { label: 'kg', value: 'kg' },
- mt: { label: 'mt', value: 'mt' },
- oz: { label: 'oz', value: 'oz' },
- lb: { label: 'lb', value: 'lb' },
- t: { label: 't', value: 't' },
- d: { label: i18n.t('UNIT.TIME.DAY'), value: 'd' },
- year: { label: i18n.t('UNIT.TIME.YEAR'), value: 'year' },
- week: { label: i18n.t('UNIT.TIME.WEEK'), value: 'week' },
- month: { label: i18n.t('UNIT.TIME.MONTH'), value: 'month' },
-});
-
-const getOptions = (unitType = area_total_area, system) => {
- return unitType[system].units.map((unit) => getUnitOptionMap()[unit]);
-};
-const getOnKeyDown = (measure) => {
- switch (measure) {
- case 'time':
- return integerOnKeyDown;
- default:
- return numberOnKeyDown;
- }
-};
-
-const DEFAULT_REACT_SELECT_WIDTH = 61;
-
-const getReactSelectWidth = (measure) => {
- if (measure === 'time') return 93;
- return DEFAULT_REACT_SELECT_WIDTH;
-};
-
-const useReactSelectStyles = (disabled, { reactSelectWidth = DEFAULT_REACT_SELECT_WIDTH } = {}) => {
- return useMemo(
- () => ({
- ...reactSelectDefaultStyles,
- container: (provided, state) => ({
- ...provided,
- }),
- control: (provided, state) => ({
- display: 'flex',
- border: `none`,
- boxShadow: 'none',
- boxSizing: 'border-box',
- borderRadius: '4px',
- height: '48px',
- paddingLeft: '0',
- fontSize: '16px',
- lineHeight: '24px',
- color: 'var(--fontColor)',
- background: 'transparent',
- }),
- valueContainer: (provided, state) => ({
- ...provided,
- padding: '0',
- width: `${reactSelectWidth - 19}px`,
- justifyContent: 'center',
- }),
- singleValue: (provided, state) => ({
- fontSize: '16px',
- lineHeight: '24px',
- color: state.isDisabled ? 'var(--grey600)' : 'var(--grey600)',
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: '"Open Sans", "SansSerif", serif',
- width: `${reactSelectWidth - 19}px`,
- overflowX: 'hidden',
- textAlign: 'center',
- position: 'absolute',
- }),
- placeholder: () => ({
- display: 'none',
- }),
- dropdownIndicator: (provided, state) => ({
- ...provided,
- display: state.isDisabled ? 'none' : 'flex',
- padding: ' 14px 0 12px 0',
- transform: 'translateX(-4px)',
- }),
- }),
- [disabled, reactSelectWidth],
- );
-};
-const Unit = ({
- disabled = false,
- classes = { container: {} },
- style = {},
- label,
- info,
- register,
- name,
- displayUnitName,
- hookFormSetValue,
- hookFormGetValue,
- hookFromWatch,
- defaultValue,
- system,
- control,
- unitType = area_total_area,
- from: defaultValueUnit,
- to,
- required,
- optional = !required,
- mode = 'onBlur',
- max = 1000000000,
- toolTipContent,
- onBlur,
- hasLeaf,
- ...props
-}) => {
- const { t } = useTranslation(['translation', 'common']);
- const onClear = () => {
- setVisibleInputValue('');
- hookFormSetHiddenValue('', { shouldClearError: !optional, shouldValidate: optional });
- };
-
- const [showError, setShowError] = useState();
- const [isDirty, setDirty] = useState();
- const { errors } = useFormState({ control });
- const error = get(errors, name);
-
- useEffect(() => {
- setShowError(!!error && !disabled && isDirty);
- }, [error]);
-
- const {
- displayUnit,
- displayValue,
- options,
- databaseUnit,
- isSelectDisabled,
- measure,
- reactSelectWidth,
- } = useMemo(() => {
- const databaseUnit = defaultValueUnit ?? unitType.databaseUnit;
- const options = getOptions(unitType, system);
- const hookFormValue = hookFormGetValue(name);
- const value = hookFormValue || (hookFormValue === 0 ? 0 : defaultValue);
- const isSelectDisabled = options.length <= 1;
- const measure = convert().describe(databaseUnit)?.measure;
- const reactSelectWidth = getReactSelectWidth(measure);
- return to && convert().describe(to)?.system === system
- ? {
- displayUnit: to,
- displayValue: defaultValue && roundToTwoDecimal(convert(value).from(databaseUnit).to(to)),
- options,
- databaseUnit,
- isSelectDisabled,
- measure,
- reactSelectWidth,
- }
- : {
- ...getDefaultUnit(unitType, value, system, databaseUnit),
- options,
- databaseUnit,
- isSelectDisabled,
- measure,
- reactSelectWidth,
- };
- }, []);
- const reactSelectStyles = useReactSelectStyles(disabled, { reactSelectWidth });
-
- const hookFormUnitOption = hookFromWatch(displayUnitName);
- const hookFormUnit = hookFormUnitOption?.value;
- useEffect(() => {
- if (typeof hookFormUnitOption === 'string' && getUnitOptionMap()[hookFormUnitOption]) {
- hookFormSetValue(displayUnitName, getUnitOptionMap()[hookFormUnitOption]);
- }
- }, []);
- useEffect(() => {
- if (hookFormUnit && convert().describe(hookFormUnit)?.system !== system && measure !== 'time') {
- hookFormSetValue(displayUnitName, getUnitOptionMap()[displayUnit]);
- }
- }, [hookFormUnit]);
-
- useEffect(() => {
- if (!hookFormGetValue(displayUnitName)) {
- hookFormSetValue(displayUnitName, getUnitOptionMap()[displayUnit]);
- }
- }, []);
-
- const [visibleInputValue, setVisibleInputValue] = useState(displayValue);
- const hookFormValue = hookFromWatch(name, defaultValue);
-
- useEffect(() => {
- hookFormSetHiddenValue(hookFormValue, { shouldValidate: true, shouldDirty: false });
- }, []);
-
- useEffect(() => {
- if (hookFormUnit && hookFormValue !== undefined) {
- setVisibleInputValue(
- roundToTwoDecimal(convert(hookFormValue).from(databaseUnit).to(hookFormUnit)),
- );
- //Trigger validation
- (hookFormValue === 0 || hookFormValue > 0) && hookFormSetHiddenValue(hookFormValue);
- }
- }, [hookFormUnit]);
-
- const inputOnChange = (e) => {
- setVisibleInputValue(e.target.value);
- mode === 'onChange' && inputOnBlur(e);
- };
-
- const hookFormSetHiddenValue = useCallback(
- (value, { shouldDirty = false, shouldValidate = true, shouldClearError } = {}) => {
- //FIXME: walk around for racing condition on add management plan pages LF-1883
- hookFormSetValue(name, value, {
- shouldValidate: false,
- shouldDirty: false,
- });
- //TODO: refactor location form pages to use hookForm default value and
- !disabled &&
- setTimeout(() => {
- hookFormSetValue(name, value, {
- shouldValidate: !shouldClearError && shouldValidate,
- shouldDirty,
- });
- shouldClearError && setShowError(false);
- }, 0);
- },
- [name],
- );
-
- const inputOnBlur = (e) => {
- if (required && e.target.value === '') {
- hookFormSetHiddenValue('');
- } else if (e.target.value === '') {
- hookFormSetValue(name, '', { shouldValidate: true });
- setVisibleInputValue('');
- } else {
- hookFormSetHiddenValue(convert(e.target.value).from(hookFormUnit).to(databaseUnit), {
- shouldDirty: true,
- });
- }
- if (!isDirty) setDirty(true);
- };
- useEffect(() => {
- if (databaseUnit && hookFormUnit) {
- setVisibleInputValue(
- hookFormValue > 0 || hookFormValue === 0
- ? roundToTwoDecimal(convert(hookFormValue).from(databaseUnit).to(hookFormUnit))
- : '',
- );
- }
- }, [hookFormValue]);
-
- const getMax = useCallback(() => {
- return hookFormUnit ? convert(max).from(hookFormUnit).to(databaseUnit) : max;
- }, [hookFormUnit, max, databaseUnit]);
-
- return (
-
- {label && (
-
-
- {label}{' '}
- {optional && (
-
- {t('common:OPTIONAL')}
-
- )}
- {hasLeaf && }
-
- {toolTipContent && (
-
-
-
- )}
-
- )}
- {showError && (
-
- )}
-
-
- {info && !showError &&
{info} }
- {showError ? (
-
{error?.message}
- ) : null}
-
- );
-};
-
-Unit.propTypes = {
- disabled: PropTypes.bool,
- label: PropTypes.string,
- optional: PropTypes.bool,
- info: PropTypes.string,
- classes: PropTypes.exact({
- input: PropTypes.object,
- label: PropTypes.object,
- container: PropTypes.object,
- info: PropTypes.object,
- errors: PropTypes.object,
- }),
- style: PropTypes.object,
- hookFormSetValue: PropTypes.func,
- hookFormGetValue: PropTypes.func,
- hookFromWatch: PropTypes.func,
- name: PropTypes.string,
- system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
- mode: PropTypes.oneOf(['onBlur', 'onChange']),
- unitType: PropTypes.shape({
- metric: PropTypes.object,
- imperial: PropTypes.object,
- databaseUnit: PropTypes.string,
- }).isRequired,
- from: PropTypes.string,
- to: PropTypes.string,
- required: PropTypes.bool,
- toolTipContent: PropTypes.string,
- hasLeaf: PropTypes.bool,
-};
-
-export default Unit;
diff --git a/packages/webapp/src/components/Form/Unit/index.jsx b/packages/webapp/src/components/Form/Unit/index.jsx
new file mode 100644
index 0000000000..512de3c823
--- /dev/null
+++ b/packages/webapp/src/components/Form/Unit/index.jsx
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import styles from './unit.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import { Error, Info, Label } from '../../Typography';
+import { Cross } from '../../Icons';
+import { useTranslation } from 'react-i18next';
+import i18n from '../../../locales/i18n';
+import { integerOnKeyDown, numberOnKeyDown, preventNumberScrolling } from '../Input';
+import Select from 'react-select';
+import { styles as reactSelectDefaultStyles } from '../ReactSelect';
+import {
+ area_total_area,
+ getDefaultUnit,
+ roundToTwoDecimal,
+} from '../../../util/convert-units/unit';
+import Infoi from '../../Tooltip/Infoi';
+import { Controller, get, useFormState } from 'react-hook-form';
+import { ReactComponent as Leaf } from '../../../assets/images/signUp/leaf.svg';
+import { convert } from '../../../util/convert-units/convert';
+
+export const getUnitOptionMap = () => ({
+ m2: { label: 'm²', value: 'm2' },
+ ha: { label: 'ha', value: 'ha' },
+ ft2: { label: 'ft²', value: 'ft2' },
+ ac: { label: 'ac', value: 'ac' },
+ cm: { label: 'cm', value: 'cm' },
+ m: { label: 'm', value: 'm' },
+ km: { label: 'km', value: 'km' },
+ in: { label: 'in', value: 'in' },
+ ft: { label: 'ft', value: 'ft' },
+ 'fl-oz': { label: 'fl oz', value: 'fl-oz' },
+ gal: { label: 'gal', value: 'gal' },
+ l: { label: 'l', value: 'l' },
+ ml: { label: 'ml', value: 'ml' },
+ mi: { label: 'mi', value: 'mi' },
+ 'l/min': { label: 'l/m', value: 'l/min' },
+ 'l/h': { label: 'l/h', value: 'l/h' },
+ 'gal/min': { label: 'g/m', value: 'gal/min' },
+ 'gal/h': { label: 'g/h', value: 'gal/h' },
+ g: { label: 'g', value: 'g' },
+ kg: { label: 'kg', value: 'kg' },
+ mt: { label: 'mt', value: 'mt' },
+ oz: { label: 'oz', value: 'oz' },
+ lb: { label: 'lb', value: 'lb' },
+ t: { label: 't', value: 't' },
+ d: { label: i18n.t('UNIT.TIME.DAY'), value: 'd' },
+ year: { label: i18n.t('UNIT.TIME.YEAR'), value: 'year' },
+ week: { label: i18n.t('UNIT.TIME.WEEK'), value: 'week' },
+ month: { label: i18n.t('UNIT.TIME.MONTH'), value: 'month' },
+});
+
+const getOptions = (unitType = area_total_area, system) => {
+ return unitType[system].units.map((unit) => getUnitOptionMap()[unit]);
+};
+const getOnKeyDown = (measure) => {
+ switch (measure) {
+ case 'time':
+ return integerOnKeyDown;
+ default:
+ return numberOnKeyDown;
+ }
+};
+
+const DEFAULT_REACT_SELECT_WIDTH = 61;
+
+const getReactSelectWidth = (measure) => {
+ if (measure === 'time') return 93;
+ return DEFAULT_REACT_SELECT_WIDTH;
+};
+
+const useReactSelectStyles = (disabled, { reactSelectWidth = DEFAULT_REACT_SELECT_WIDTH } = {}) => {
+ return useMemo(
+ () => ({
+ ...reactSelectDefaultStyles,
+ container: (provided, state) => ({
+ ...provided,
+ }),
+ control: (provided, state) => ({
+ display: 'flex',
+ border: `none`,
+ boxShadow: 'none',
+ boxSizing: 'border-box',
+ borderRadius: '4px',
+ height: '48px',
+ paddingLeft: '0',
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--fontColor)',
+ background: 'transparent',
+ }),
+ valueContainer: (provided, state) => ({
+ ...provided,
+ padding: '0',
+ width: `${reactSelectWidth - 19}px`,
+ display: 'flex',
+ justifyContent: 'center',
+ }),
+ singleValue: (provided, state) => ({
+ fontSize: '16px',
+ lineHeight: '24px',
+ color: 'var(--grey600)',
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: '"Open Sans", "SansSerif", serif',
+ overflowX: 'hidden',
+ }),
+ placeholder: () => ({
+ display: 'none',
+ }),
+ dropdownIndicator: (provided, state) => ({
+ ...provided,
+ display: state.isDisabled ? 'none' : 'flex',
+ padding: ' 14px 0 12px 0',
+ transform: 'translateX(-4px)',
+ }),
+ }),
+ [disabled, reactSelectWidth],
+ );
+};
+const Unit = ({
+ disabled = false,
+ classes = { container: {} },
+ style = {},
+ label,
+ info,
+ register,
+ name,
+ displayUnitName,
+ hookFormSetValue,
+ hookFormGetValue,
+ hookFromWatch,
+ defaultValue,
+ system,
+ control,
+ unitType = area_total_area,
+ from: defaultValueUnit,
+ to,
+ required,
+ optional = !required,
+ mode = 'onBlur',
+ max = 1000000000,
+ toolTipContent,
+ onBlur,
+ hasLeaf,
+ ...props
+}) => {
+ const { t } = useTranslation(['translation', 'common']);
+ const onClear = () => {
+ setVisibleInputValue('');
+ hookFormSetHiddenValue('', { shouldClearError: !optional, shouldValidate: optional });
+ };
+
+ const [showError, setShowError] = useState();
+ const [isDirty, setDirty] = useState();
+ const { errors } = useFormState({ control });
+ const error = get(errors, name);
+
+ useEffect(() => {
+ setShowError(!!error && !disabled && isDirty);
+ }, [error]);
+
+ const {
+ displayUnit,
+ displayValue,
+ options,
+ databaseUnit,
+ isSelectDisabled,
+ measure,
+ reactSelectWidth,
+ } = useMemo(() => {
+ const databaseUnit = defaultValueUnit ?? unitType.databaseUnit;
+ const options = getOptions(unitType, system);
+ const hookFormValue = hookFormGetValue(name);
+ const value = hookFormValue || (hookFormValue === 0 ? 0 : defaultValue);
+ const isSelectDisabled = options.length <= 1;
+ const measure = convert().describe(databaseUnit)?.measure;
+ const reactSelectWidth = getReactSelectWidth(measure);
+ return to && convert().describe(to)?.system === system
+ ? {
+ displayUnit: to,
+ displayValue: defaultValue && roundToTwoDecimal(convert(value).from(databaseUnit).to(to)),
+ options,
+ databaseUnit,
+ isSelectDisabled,
+ measure,
+ reactSelectWidth,
+ }
+ : {
+ ...getDefaultUnit(unitType, value, system, databaseUnit),
+ options,
+ databaseUnit,
+ isSelectDisabled,
+ measure,
+ reactSelectWidth,
+ };
+ }, []);
+ const reactSelectStyles = useReactSelectStyles(disabled, { reactSelectWidth });
+
+ const hookFormUnitOption = hookFromWatch(displayUnitName);
+ const hookFormUnit = hookFormUnitOption?.value;
+ useEffect(() => {
+ if (typeof hookFormUnitOption === 'string' && getUnitOptionMap()[hookFormUnitOption]) {
+ hookFormSetValue(displayUnitName, getUnitOptionMap()[hookFormUnitOption]);
+ }
+ }, []);
+ useEffect(() => {
+ if (hookFormUnit && convert().describe(hookFormUnit)?.system !== system && measure !== 'time') {
+ hookFormSetValue(displayUnitName, getUnitOptionMap()[displayUnit]);
+ }
+ }, [hookFormUnit]);
+
+ useEffect(() => {
+ if (!hookFormGetValue(displayUnitName)) {
+ hookFormSetValue(displayUnitName, getUnitOptionMap()[displayUnit]);
+ }
+ }, []);
+
+ const [visibleInputValue, setVisibleInputValue] = useState(displayValue);
+ const hookFormValue = hookFromWatch(name, defaultValue);
+
+ useEffect(() => {
+ hookFormSetHiddenValue(hookFormValue, { shouldValidate: true, shouldDirty: false });
+ }, []);
+
+ const inputOnChange = (e) => {
+ setVisibleInputValue(e.target.value);
+ mode === 'onChange' && inputOnBlur(e);
+ };
+
+ const hookFormSetHiddenValue = useCallback(
+ (value, { shouldDirty = false, shouldValidate = true, shouldClearError } = {}) => {
+ //FIXME: walk around for racing condition on add management plan pages LF-1883
+ hookFormSetValue(name, value, {
+ shouldValidate: false,
+ shouldDirty: false,
+ });
+ //TODO: refactor location form pages to use hookForm default value and
+ !disabled &&
+ setTimeout(() => {
+ hookFormSetValue(name, value, {
+ shouldValidate: !shouldClearError && shouldValidate,
+ shouldDirty,
+ });
+ shouldClearError && setShowError(false);
+ }, 0);
+ },
+ [name],
+ );
+
+ const inputOnBlur = (e) => {
+ if (required && e.target.value === '') {
+ hookFormSetHiddenValue('');
+ } else if (e.target.value === '') {
+ hookFormSetValue(name, '', { shouldValidate: true });
+ setVisibleInputValue('');
+ } else {
+ hookFormSetHiddenValue(convert(e.target.value).from(hookFormUnit).to(databaseUnit), {
+ shouldDirty: true,
+ });
+ }
+ if (!isDirty) setDirty(true);
+ };
+ useEffect(() => {
+ if (databaseUnit && hookFormUnit) {
+ setVisibleInputValue(
+ hookFormValue > 0 || hookFormValue === 0
+ ? roundToTwoDecimal(convert(hookFormValue).from(databaseUnit).to(hookFormUnit))
+ : '',
+ );
+ }
+ }, [hookFormValue]);
+
+ const getMax = useCallback(() => {
+ return hookFormUnit ? convert(max).from(hookFormUnit).to(databaseUnit) : max;
+ }, [hookFormUnit, max, databaseUnit]);
+
+ return (
+
+ {label && (
+
+
+ {label}{' '}
+ {optional && (
+
+ {t('common:OPTIONAL')}
+
+ )}
+ {hasLeaf && }
+
+ {toolTipContent && (
+
+
+
+ )}
+
+ )}
+ {showError && (
+
+ )}
+
+
+ {info && !showError &&
{info} }
+ {showError ? (
+
{error?.message}
+ ) : null}
+
+ );
+};
+
+Unit.propTypes = {
+ disabled: PropTypes.bool,
+ label: PropTypes.string,
+ optional: PropTypes.bool,
+ info: PropTypes.string,
+ classes: PropTypes.exact({
+ input: PropTypes.object,
+ label: PropTypes.object,
+ container: PropTypes.object,
+ info: PropTypes.object,
+ errors: PropTypes.object,
+ }),
+ style: PropTypes.object,
+ hookFormSetValue: PropTypes.func,
+ hookFormGetValue: PropTypes.func,
+ hookFromWatch: PropTypes.func,
+ name: PropTypes.string,
+ system: PropTypes.oneOf(['imperial', 'metric']).isRequired,
+ mode: PropTypes.oneOf(['onBlur', 'onChange']),
+ unitType: PropTypes.shape({
+ metric: PropTypes.object,
+ imperial: PropTypes.object,
+ databaseUnit: PropTypes.string,
+ }).isRequired,
+ from: PropTypes.string,
+ to: PropTypes.string,
+ required: PropTypes.bool,
+ toolTipContent: PropTypes.string,
+ hasLeaf: PropTypes.bool,
+};
+
+export default Unit;
diff --git a/packages/webapp/src/components/Form/Unit/unit.module.scss b/packages/webapp/src/components/Form/Unit/unit.module.scss
index 79c1a4b37b..efef3d595e 100644
--- a/packages/webapp/src/components/Form/Unit/unit.module.scss
+++ b/packages/webapp/src/components/Form/Unit/unit.module.scss
@@ -1,4 +1,4 @@
-@import '../../../assets/colors';
+
.input {
flex-grow: 1;
@@ -54,6 +54,7 @@
flex-direction: column;
overflow: visible;
position: relative;
+ justify-content: space-between;
}
.sm {
diff --git a/packages/webapp/src/components/Form/index.js b/packages/webapp/src/components/Form/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/index.js
rename to packages/webapp/src/components/Form/index.jsx
diff --git a/packages/webapp/src/components/Form/useDefaultOption.js b/packages/webapp/src/components/Form/useDefaultOption.js
deleted file mode 100644
index beaadec551..0000000000
--- a/packages/webapp/src/components/Form/useDefaultOption.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import { useMemo } from 'react';
-
-export default function useDefaultOption(options, value) {
- return useMemo(() => {
- for (const option of options) {
- if (value === option.value) return option;
- }
- }, [value, options]);
-}
diff --git a/packages/webapp/src/components/Form/utils/index.js b/packages/webapp/src/components/Form/utils/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Form/utils/index.js
rename to packages/webapp/src/components/Form/utils/index.jsx
diff --git a/packages/webapp/src/components/Forms/Log/index.js b/packages/webapp/src/components/Forms/Log/index.js
deleted file mode 100644
index faa6a06ea5..0000000000
--- a/packages/webapp/src/components/Forms/Log/index.js
+++ /dev/null
@@ -1,369 +0,0 @@
-import React from 'react';
-import { actions, Control, Errors, Fieldset } from 'react-redux-form';
-import DropDown from '../../Inputs/DropDown';
-import styles from '../../../containers/Log/styles.module.scss';
-import { connect } from 'react-redux';
-import moment from 'moment';
-import { getLocations, getManagementPlans } from '../../../containers/saga';
-import { currentAndPlannedManagementPlansSelector } from '../../../containers/managementPlanSlice';
-import { withTranslation } from 'react-i18next';
-import { Label } from '../../Typography';
-import PureWarningBox from '../../WarningBox';
-import Input from '../../Form/Input';
-import { components } from 'react-select';
-
-class DefaultLogForm extends React.Component {
- constructor(props) {
- super(props);
- const { selectedFields, selectedCrops, dispatch, parent, model } = this.props;
- dispatch(getManagementPlans());
- dispatch(getLocations());
-
- let selectedCropsMap = {};
- // this is only called if DefaultLogForm is in an edit form
- if (selectedCrops) {
- selectedCrops.forEach((sc) => {
- if (!selectedCropsMap[sc.location_id]) {
- selectedCropsMap[sc.location_id] = [];
- }
- selectedCropsMap[sc.location_id].push(sc);
- });
- }
-
- this.state = {
- cropOptionsMap: {},
- selectedCropsMap,
- selectedFields: selectedFields || [],
- cropValue: null,
- crops: [],
- fieldOptions: [],
- fieldOptionsWithoutAll: [],
- displayLiveCropMessage: false,
- };
- this.setCropsOnFieldSelect = this.setCropsOnFieldSelect.bind(this);
-
- if (selectedFields) {
- this.setCropsOnFieldSelect(selectedFields);
- Object.keys(this.state.selectedCropsMap).forEach((k) => {
- dispatch(actions.change(`${parent}${model}.crop.${k}`, this.state.selectedCropsMap[k]));
- });
- }
- }
-
- hasSameCrop = (managementPlan) => {
- const { crops } = this.state;
-
- for (let c of crops) {
- if (
- c.management_plan_id !== managementPlan.management_plan_id &&
- c.crop_id === managementPlan.crop_id &&
- c.location_id === managementPlan.location_id
- ) {
- return true;
- }
- }
- return false;
- };
-
- setCropsOnFieldSelect(selectedOptions) {
- const { locations, parent, model } = this.props;
- const { crops } = this.props;
- let cropOptionsMap = this.state.cropOptionsMap;
- let selectedFields;
- const options = selectedOptions || [];
-
- // remove associated crop selections for field if field is removed from dropdown
- const activeFields = options.map((o) => o.value);
- const removedFields = locations
- .filter((f) => activeFields.indexOf(f.location_id) === -1)
- .map((f) => f.location_id);
- removedFields &&
- removedFields.map((rm) => {
- return this.props.dispatch(actions.change(`${parent}${model}.crop.${rm}`, null));
- });
-
- // map field_crops to locations that are selected in dropdown
- if (options.find((o) => o.value === 'all')) {
- selectedFields = this.state.fieldOptionsWithoutAll;
- locations.map((f) => {
- return (cropOptionsMap[f.location_id] = crops
- .filter((c) => c.location_id === f.location_id)
- .map((c) => {
- let hasDup = this.hasSameCrop(c);
- if (hasDup) {
- return {
- value: c.management_plan_id,
- label: `${this.props.t(`crop:${c.crop_translation_key}`)} (${moment(
- c.seed_date,
- ).format('YYYY-MM-DD')})`,
- };
- } else
- return {
- value: c.management_plan_id,
- label: this.props.t(`crop:${c.crop_translation_key}`),
- };
- }));
- });
- } else {
- options.map((o) => {
- return (cropOptionsMap[o.value] = crops
- .filter((c) => c.location_id === o.value)
- .map((c) => {
- let hasDup = this.hasSameCrop(c);
- if (hasDup) {
- return {
- value: c.management_plan_id,
- label: `${this.props.t(`crop:${c.crop_translation_key}`)} (${moment(
- c.seed_date,
- ).format('YYYY-MM-DD')})`,
- };
- } else
- return {
- value: c.management_plan_id,
- label: this.props.t(`crop:${c.crop_translation_key}`),
- };
- }));
- });
- }
- this.setState({
- selectedFields: selectedFields || options,
- cropOptionsMap,
- fieldSelected: true,
- cropValue: undefined,
- });
- }
-
- componentDidMount() {
- const { model, parent } = this.props;
- this.filterLiveCrops();
- // if 'all' is selected in fields dropdown, set field in redux state with all field options instead of option 'all'
- this.props.dispatch(actions.change(`${parent}${model}.field`, this.state.selectedFields));
- }
-
- filterLiveCrops = () => {
- const crops = this.props.crops;
- const locations = this.props.locations;
- const model = this.props.model;
-
- let displayLiveCropMessage = false;
-
- if (model === '.seedLog' || model === '.irrigationLog') {
- if (crops.length < 1) {
- displayLiveCropMessage = true;
- }
- }
-
- this.setState({
- crops,
- displayLiveCropMessage,
- });
- this.filterFieldOptions(crops, locations, model);
- };
-
- filterFieldOptions = (crops, locations, model) => {
- let included = [];
- let filteredFields = [];
- if (model === '.seedLog' && model === '.irrigationLog') {
- if (locations && crops) {
- for (let c of crops) {
- if (!included.includes(c.location_id)) {
- included.push(c.location_id);
- filteredFields.push({ value: c.location_id, label: c.name });
- }
- }
- }
- } else {
- if (locations) {
- for (let f of locations) {
- filteredFields.push({ value: f.location_id, label: f.name });
- }
- }
- }
-
- let fieldOptionsWithoutAll = JSON.parse(JSON.stringify(filteredFields));
- filteredFields.unshift({ value: 'all', label: this.props.t('LOG_COMMON.ALL_LOCATIONS') });
-
- this.setState({
- fieldOptions: filteredFields,
- fieldOptionsWithoutAll: fieldOptionsWithoutAll,
- });
- };
-
- render() {
- const {
- model,
- notesField,
- typeField,
- typeOptions,
- customFieldset,
- isCropNotRequired,
- isCropNotNeeded,
- } = this.props;
-
- // 'plow', 'ridgeTill', 'zoneTill', 'mulchTill', 'ripping', 'discing'
- const { fieldOptions, displayLiveCropMessage } = this.state;
- const typeLabels = {
- plow: this.props.t('LOG_FIELD_WORK.PLOW'),
- ridgeTill: this.props.t('LOG_FIELD_WORK.RIDGE_TILL'),
- zoneTill: this.props.t('LOG_FIELD_WORK.ZONE_TILL'),
- mulchTill: this.props.t('LOG_FIELD_WORK.MULCH_TILL'),
- ripping: this.props.t('LOG_FIELD_WORK.RIPPING'),
- discing: this.props.t('LOG_FIELD_WORK.DISCING'),
- sprinkler: this.props.t('LOG_IRRIGATION.SPRINKLER'),
- drip: this.props.t('LOG_IRRIGATION.DRIP'),
- subsurface: this.props.t('LOG_IRRIGATION.SUBSURFACE'),
- flood: this.props.t('LOG_IRRIGATION.FLOOD'),
- Harvest: this.props.t('LOG_HARVEST.HARVEST'),
- Pest: this.props.t('LOG_HARVEST.PEST'),
- Disease: this.props.t('LOG_HARVEST.DISEASE'),
- Weed: this.props.t('LOG_HARVEST.WEED'),
- Other: this.props.t('LOG_HARVEST.OTHER'),
- };
- // format options for react-select dropdown components
- //const fieldOptions = fields && fields.map((f) => ({ value: f.location_id, label: f.name }));
-
- let parsedTypeOptions =
- typeOptions && typeOptions.map((t) => ({ value: t, label: typeLabels[t] }));
-
- return (
-
- {displayLiveCropMessage && (
- // {this.props.t('LOG_COMMON.WARNING')}
-
- {this.props.t('LOG_COMMON.WARNING')}
-
- )}
-
- {this.props.t('LOG_COMMON.LOCATIONS')}
- val && val.length }}
- />
-
-
- {!isCropNotNeeded &&
- this.state.selectedFields &&
- this.state.selectedFields.map((f, index) => {
- const options = this.state.cropOptionsMap[f.value]?.length
- ? [
- {
- label: this.props.t('LOG_COMMON.ALL_CROPS'),
- options: this.state.cropOptionsMap[f.value],
- },
- ]
- : [];
- return (
-
-
- {this.props.t('LOG_COMMON.CROP')}
-
- {f.label}
-
-
- {
- return val && val.length;
- },
- }
- }
- />
-
-
- );
- })}
- {typeField && (
-
- {this.props.t('LOG_COMMON.TYPE')}
- val && val.value }}
- />
-
-
- )}
- {customFieldset && customFieldset()}
- {notesField && (
-
- )}
-
- );
- }
-}
-
-const Group = (props) => {
- const hasSelectedOption = props.children.some((opt) => opt.props.isSelected);
- const onClick = () => {
- props.selectProps.onChange(props.data.options);
- };
- return (
-
- );
-};
-
-const GroupHeading = ({ hasSelectedOption, ...props }) => {
- const style = { ...hasSelectedOption };
- return ;
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-const mapStateToProps = (state) => {
- return {
- crops: currentAndPlannedManagementPlansSelector(state),
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(DefaultLogForm));
diff --git a/packages/webapp/src/components/Forms/Sale/index.js b/packages/webapp/src/components/Forms/Sale/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Forms/Sale/index.js
rename to packages/webapp/src/components/Forms/Sale/index.jsx
diff --git a/packages/webapp/src/components/FullYearCalendar/index.js b/packages/webapp/src/components/FullYearCalendar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/FullYearCalendar/index.js
rename to packages/webapp/src/components/FullYearCalendar/index.jsx
diff --git a/packages/webapp/src/components/GlobalScss/index.jsx b/packages/webapp/src/components/GlobalScss/index.jsx
new file mode 100644
index 0000000000..6ce72fb573
--- /dev/null
+++ b/packages/webapp/src/components/GlobalScss/index.jsx
@@ -0,0 +1,5 @@
+import '../../assets/colors.scss';
+
+export function GlobalScss() {
+ return <>>;
+}
diff --git a/packages/webapp/src/components/Help/index.js b/packages/webapp/src/components/Help/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Help/index.js
rename to packages/webapp/src/components/Help/index.jsx
diff --git a/packages/webapp/src/components/HideForm/HideForm.js b/packages/webapp/src/components/HideForm/HideForm.jsx
similarity index 100%
rename from packages/webapp/src/components/HideForm/HideForm.js
rename to packages/webapp/src/components/HideForm/HideForm.jsx
diff --git a/packages/webapp/src/components/Home/index.js b/packages/webapp/src/components/Home/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Home/index.js
rename to packages/webapp/src/components/Home/index.jsx
diff --git a/packages/webapp/src/components/Icons/DocumentIcon/index.js b/packages/webapp/src/components/Icons/DocumentIcon/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Icons/DocumentIcon/index.js
rename to packages/webapp/src/components/Icons/DocumentIcon/index.jsx
diff --git a/packages/webapp/src/components/Icons/cross/index.js b/packages/webapp/src/components/Icons/cross/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Icons/cross/index.js
rename to packages/webapp/src/components/Icons/cross/index.jsx
diff --git a/packages/webapp/src/components/Icons/index.js b/packages/webapp/src/components/Icons/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Icons/index.js
rename to packages/webapp/src/components/Icons/index.jsx
diff --git a/packages/webapp/src/components/InfoBoxComponent/index.js b/packages/webapp/src/components/InfoBoxComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/InfoBoxComponent/index.js
rename to packages/webapp/src/components/InfoBoxComponent/index.jsx
diff --git a/packages/webapp/src/components/Inputs/Checkbox/index.js b/packages/webapp/src/components/Inputs/Checkbox/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/Checkbox/index.js
rename to packages/webapp/src/components/Inputs/Checkbox/index.jsx
diff --git a/packages/webapp/src/components/Inputs/CropVarietySale/index.js b/packages/webapp/src/components/Inputs/CropVarietySale/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/CropVarietySale/index.js
rename to packages/webapp/src/components/Inputs/CropVarietySale/index.jsx
diff --git a/packages/webapp/src/components/Inputs/DateContainer/index.js b/packages/webapp/src/components/Inputs/DateContainer/index.js
deleted file mode 100644
index 0f69183785..0000000000
--- a/packages/webapp/src/components/Inputs/DateContainer/index.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import React from 'react';
-import Input from '../../Form/Input';
-import moment from 'moment';
-import { Text } from '../../Typography';
-import { useTranslation } from 'react-i18next';
-import styles from './styles.module.scss';
-function DateContainer({
- date,
- onDateChange,
- placeholder,
- custom,
- classes = {},
- defaultDate,
- label,
-}) {
- const onChange = (e) => {
- onDateChange(moment(e.target.value));
- };
- return (
-
- {placeholder && (
- <>
-
- {placeholder}
-
-
- >
- )}
-
-
- );
-}
-
-export default DateContainer;
-
-export function FromToDateContainer({ onStartDateChange, onEndDateChange, startDate, endDate }) {
- const { t } = useTranslation();
- return (
-
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Inputs/DateContainer/index.jsx b/packages/webapp/src/components/Inputs/DateContainer/index.jsx
new file mode 100644
index 0000000000..747cf42714
--- /dev/null
+++ b/packages/webapp/src/components/Inputs/DateContainer/index.jsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import Input from '../../Form/Input';
+import moment from 'moment';
+import { Text } from '../../Typography';
+import { useTranslation } from 'react-i18next';
+import styles from './styles.module.scss';
+
+function DateContainer({
+ date,
+ onDateChange,
+ placeholder,
+ custom,
+ classes = {},
+ defaultDate,
+ label,
+}) {
+ const onChange = (e) => {
+ onDateChange(moment(e.target.value));
+ };
+ return (
+
+ {placeholder && (
+ <>
+
+ {placeholder}
+
+
+ >
+ )}
+
+
+ );
+}
+
+export default DateContainer;
+
+export function FromToDateContainer({ onStartDateChange, onEndDateChange, startDate, endDate }) {
+ const { t } = useTranslation();
+ return (
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Inputs/DescriptiveButton/index.js b/packages/webapp/src/components/Inputs/DescriptiveButton/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/DescriptiveButton/index.js
rename to packages/webapp/src/components/Inputs/DescriptiveButton/index.jsx
diff --git a/packages/webapp/src/components/Inputs/DropDown/index.js b/packages/webapp/src/components/Inputs/DropDown/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/DropDown/index.js
rename to packages/webapp/src/components/Inputs/DropDown/index.jsx
diff --git a/packages/webapp/src/components/Inputs/GoogleMapSearchBox/GoogleMapSearchBox.js b/packages/webapp/src/components/Inputs/GoogleMapSearchBox/GoogleMapSearchBox.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/GoogleMapSearchBox/GoogleMapSearchBox.js
rename to packages/webapp/src/components/Inputs/GoogleMapSearchBox/GoogleMapSearchBox.jsx
diff --git a/packages/webapp/src/components/Inputs/Text/index.js b/packages/webapp/src/components/Inputs/Text/index.js
deleted file mode 100644
index 9755debcc4..0000000000
--- a/packages/webapp/src/components/Inputs/Text/index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import styles from '../styles.module.scss';
-import { Control } from 'react-redux-form';
-import Input from '../../Form/Input';
-
-class Text extends React.Component {
- render() {
- const { model, title, validators } = this.props;
- return (
-
- );
- }
-}
-
-export default Text;
diff --git a/packages/webapp/src/components/Inputs/Text/index.jsx b/packages/webapp/src/components/Inputs/Text/index.jsx
new file mode 100644
index 0000000000..9bdb93200c
--- /dev/null
+++ b/packages/webapp/src/components/Inputs/Text/index.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { Control } from 'react-redux-form';
+import Input from '../../Form/Input';
+
+class Text extends React.Component {
+ render() {
+ const { model, title, validators } = this.props;
+ return (
+
+ );
+ }
+}
+
+export default Text;
diff --git a/packages/webapp/src/components/Inputs/Unit/index.js b/packages/webapp/src/components/Inputs/Unit/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/Unit/index.js
rename to packages/webapp/src/components/Inputs/Unit/index.jsx
diff --git a/packages/webapp/src/components/Inputs/YearPicker/index.js b/packages/webapp/src/components/Inputs/YearPicker/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Inputs/YearPicker/index.js
rename to packages/webapp/src/components/Inputs/YearPicker/index.jsx
diff --git a/packages/webapp/src/components/Insights/BalanceBarComponent/index.js b/packages/webapp/src/components/Insights/BalanceBarComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/BalanceBarComponent/index.js
rename to packages/webapp/src/components/Insights/BalanceBarComponent/index.jsx
diff --git a/packages/webapp/src/components/Insights/BiodiversitySpecies/index.js b/packages/webapp/src/components/Insights/BiodiversitySpecies/index.js
deleted file mode 100644
index a963be24ad..0000000000
--- a/packages/webapp/src/components/Insights/BiodiversitySpecies/index.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React, { Component } from 'react';
-import sharedStyles from '../shared.module.scss';
-import { withTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import { LinearProgress } from '@material-ui/core';
-
-class BiodiversitySpecies extends Component {
- constructor(props) {
- super(props);
- this.state = {};
-
- this.i18nSpeciesDict = {
- Birds: props.t('INSIGHTS.BIODIVERSITY.BIRDS'),
- Insects: props.t('INSIGHTS.BIODIVERSITY.INSECTS'),
- Plants: props.t('INSIGHTS.BIODIVERSITY.PLANTS'),
- Amphibians: props.t('INSIGHTS.BIODIVERSITY.AMPHIBIANS'),
- CropVarieties: props.t('INSIGHTS.BIODIVERSITY.CROP_VARIETIES'),
- };
- }
-
- render() {
- const { species, count, percent, t } = this.props;
- return (
-
-
- {this.i18nSpeciesDict[species]}
-
- {t('INSIGHTS.BIODIVERSITY.SPECIES_COUNT', { count })}
-
-
-
-
- );
- }
-}
-
-export default withTranslation()(BiodiversitySpecies);
diff --git a/packages/webapp/src/components/Insights/BiodiversitySpecies/index.jsx b/packages/webapp/src/components/Insights/BiodiversitySpecies/index.jsx
new file mode 100644
index 0000000000..25a229e97f
--- /dev/null
+++ b/packages/webapp/src/components/Insights/BiodiversitySpecies/index.jsx
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { Component } from 'react';
+import sharedStyles from '../shared.module.scss';
+import { withTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import { LinearProgress } from '@material-ui/core';
+
+class BiodiversitySpecies extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+
+ this.i18nSpeciesDict = {
+ Birds: props.t('INSIGHTS.BIODIVERSITY.BIRDS'),
+ Insects: props.t('INSIGHTS.BIODIVERSITY.INSECTS'),
+ Plants: props.t('INSIGHTS.BIODIVERSITY.PLANTS'),
+ Amphibians: props.t('INSIGHTS.BIODIVERSITY.AMPHIBIANS'),
+ CropVarieties: props.t('INSIGHTS.BIODIVERSITY.CROP_VARIETIES'),
+ Mammals: props.t('INSIGHTS.BIODIVERSITY.MAMMALS'),
+ };
+ }
+
+ render() {
+ const { species, count, percent, t } = this.props;
+ return (
+
+
+ {this.i18nSpeciesDict[species]}
+
+ {t('INSIGHTS.BIODIVERSITY.SPECIES_COUNT', { count })}
+
+
+
+
+ );
+ }
+}
+
+export default withTranslation()(BiodiversitySpecies);
diff --git a/packages/webapp/src/components/Insights/FrequencySelectorComponent/index.js b/packages/webapp/src/components/Insights/FrequencySelectorComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/FrequencySelectorComponent/index.js
rename to packages/webapp/src/components/Insights/FrequencySelectorComponent/index.jsx
diff --git a/packages/webapp/src/components/Insights/InsightsInfoComponent/index.js b/packages/webapp/src/components/Insights/InsightsInfoComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/InsightsInfoComponent/index.js
rename to packages/webapp/src/components/Insights/InsightsInfoComponent/index.jsx
diff --git a/packages/webapp/src/components/Insights/LabourHappinessTask/index.js b/packages/webapp/src/components/Insights/LabourHappinessTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/LabourHappinessTask/index.js
rename to packages/webapp/src/components/Insights/LabourHappinessTask/index.jsx
diff --git a/packages/webapp/src/components/Insights/NitrogenBalanceInfo/index.js b/packages/webapp/src/components/Insights/NitrogenBalanceInfo/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/NitrogenBalanceInfo/index.js
rename to packages/webapp/src/components/Insights/NitrogenBalanceInfo/index.jsx
diff --git a/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropCharts.jsx b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropCharts.jsx
new file mode 100644
index 0000000000..adf2a1b806
--- /dev/null
+++ b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropCharts.jsx
@@ -0,0 +1,112 @@
+import React, { useMemo, useState } from 'react';
+
+import { useTranslation } from 'react-i18next';
+
+import { PriceCropContainer } from './PriceCropContainer/PriceCropContainer';
+import { useComponentWidth } from '../../../containers/hooks/useComponentWidthHeight';
+import ReactSelect from '../../Form/ReactSelect';
+import { convert } from '../../../util/convert-units/convert';
+import { roundToTwoDecimal } from '../../../util/convert-units/unit';
+import { Label, Semibold } from '../../Typography';
+import styles from './styles.module.scss';
+import { colors } from '../../../assets/theme';
+
+export function PriceCropCharts({ cropsWithPriceInfo, currencySymbol, isImperial }) {
+ const unit = isImperial ? 'lb' : 'kg';
+ const { t } = useTranslation();
+ const { ref, width } = useComponentWidth();
+
+ const { uniqueYears, yearOptions } = useMemo(() => {
+ const yearSet = new Set();
+ for (const cropInfo of cropsWithPriceInfo) {
+ const crop_translation_key = Object.keys(cropInfo)[0];
+ for (const { crop_date } of cropInfo[crop_translation_key]) {
+ yearSet.add(+crop_date.split('-')[0]);
+ }
+ }
+ const uniqueYears = Array.from(yearSet).sort().reverse();
+ const yearOptions = uniqueYears.map((year) => ({ label: year, value: year }));
+ return { yearOptions, uniqueYears };
+ }, [cropsWithPriceInfo]);
+
+ const [year, setYear] = useState(uniqueYears[0] || new Date().getFullYear());
+
+ const filteredPricePoints = useMemo(() => {
+ return cropsWithPriceInfo.reduce((filteredPricePoints, cropInfo) => {
+ const crop_translation_key = Object.keys(cropInfo)[0];
+ const pricePoints = cropInfo[crop_translation_key]
+ .filter(({ crop_date }) => {
+ return Number(crop_date.split('-')[0]) === year;
+ })
+ .map((pricePoint) => ({
+ ...pricePoint,
+ own_price: roundToTwoDecimal(convert(pricePoint.crop_price).from('kg').to(unit)),
+ network_price: roundToTwoDecimal(convert(pricePoint.network_price).from('kg').to(unit)),
+ }));
+ if (pricePoints.length > 0) {
+ filteredPricePoints[crop_translation_key] = {};
+ filteredPricePoints[crop_translation_key].own_price = pricePoints.filter(
+ ({ crop_price }) => crop_price,
+ );
+ filteredPricePoints[crop_translation_key].network_price = pricePoints;
+ }
+ return filteredPricePoints;
+ }, {});
+ }, [year]);
+ const yTitle = t('INSIGHTS.PRICES.Y_TITLE', {
+ currency: currencySymbol,
+ mass: unit,
+ interpolation: { escapeValue: false },
+ });
+ return (
+
+ {uniqueYears.length > 1 && (
+
setYear(e.value)}
+ options={yearOptions}
+ value={{ label: year, value: year }}
+ />
+ )}
+
+
{yTitle}
+
+
+
+
+
+ {t('INSIGHTS.PRICES.OWN_PRICE')}
+
+
+
+
+
+ {t('INSIGHTS.PRICES.NETWORK_PRICE')}
+
+
+
+
+ {Object.entries(filteredPricePoints).map(([crop_translation_key, pricePoints], index) => {
+ return (
+
+ );
+ })}
+
+ );
+}
diff --git a/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/PriceCropContainer.jsx b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/PriceCropContainer.jsx
new file mode 100644
index 0000000000..69099aa662
--- /dev/null
+++ b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/PriceCropContainer.jsx
@@ -0,0 +1,246 @@
+import React, { useEffect, useMemo, useRef } from 'react';
+import { Text } from '../../../Typography';
+import { useTranslation } from 'react-i18next';
+import {
+ axisBottom,
+ axisLeft,
+ bisectCenter,
+ line,
+ max,
+ min,
+ pointer,
+ scaleLinear,
+ scaleTime,
+ select,
+ timeFormat,
+} from 'd3';
+import styles from './styles.module.scss';
+import { colors } from '../../../../assets/theme';
+import { useDebounce } from '../../../../containers/hooks/useDebounce';
+
+const priceAttributeMap = {
+ network_price: {
+ stroke: colors.orange700,
+ strokeWidth: 8,
+ strokeDasharray: '12,12',
+ },
+ own_price: {
+ stroke: colors.blue700,
+ strokeWidth: 3,
+ strokeDasharray: undefined,
+ },
+};
+
+export function PriceCropContainer({
+ currencySymbol,
+ name,
+ pricePoints,
+ year = 2022,
+ config: {
+ marginTop = 20, // top margin, in pixels
+ marginRight = 12, // right margin, in pixels
+ marginBottom = 30, // bottom margin, in pixels
+ marginLeft = 40, // left margin, in pixels
+ width = 640,
+ height = 320,
+ xRange = [marginLeft, width - marginRight],
+ yRange = [height - marginBottom, marginTop],
+ xType = scaleTime,
+ yType = scaleLinear,
+ strokeWidth = 1.5,
+ } = {},
+}) {
+ const { t } = useTranslation();
+
+ const svgRef = useRef();
+ const d3Refs = useRef({});
+
+ useEffect(() => {
+ d3Refs.current.svg = select(svgRef.current);
+ d3Refs.current.xScale = xType();
+ d3Refs.current.yScale = yType().range(yRange);
+ d3Refs.current.xAxis = axisBottom(d3Refs.current.xScale)
+ .tickFormat(timeFormat('%Y-%m'))
+ .tickSizeOuter(0);
+ d3Refs.current.yAxis = axisLeft(d3Refs.current.yScale).ticks(height / 40);
+ }, [svgRef.current]);
+
+ useEffect(() => {
+ d3Refs.current.xScale.range(xRange);
+ d3Refs.current.xAxis.ticks(getNumberOfTicks(width));
+ }, [width, svgRef.current]);
+
+ useEffect(() => {
+ const { yMax, yMin } = pricePoints?.network_price?.reduce(
+ ({ yMax, yMin }, { own_price, network_price }) => {
+ return {
+ yMax: max([yMax, own_price, network_price]),
+ yMin: min([yMin, own_price, network_price]),
+ };
+ },
+ { yMax: 0, yMin: 999999 },
+ ) || { yMax: 3, yMin: 3 };
+ d3Refs.current.yScale.domain([0, yMax + yMin]);
+ d3Refs.current.xScale.domain([new Date(year, 0, 1), new Date(year, 11, 31)]);
+ }, [year, pricePoints, svgRef.current]);
+
+ useEffect(() => {
+ const { yScale, svg, xScale, xAxis, yAxis } = d3Refs.current;
+
+ const xAxisG = svg.select(`.${styles.xAxis}`).call(xAxis);
+ const yAxisG = svg
+ .select(`.${styles.yAxis}`)
+ .call(yAxis)
+ .call((g) => g.select('.domain').remove())
+ .call((g) =>
+ g
+ .selectAll('.tick line')
+ .attr('x2', width - marginLeft - marginRight)
+ .attr('stroke-opacity', 0.1),
+ );
+ svg.select(`.${styles.lines}`).selectAll('*').remove();
+ svg
+ .select(`.${styles.lines}`)
+ .selectAll(`.${styles.line}`)
+ .data(['own_price', 'network_price'])
+ .join('path')
+ .attr('stroke', (priceType) => priceAttributeMap[priceType].stroke)
+ .attr('stroke-width', (priceType) => priceAttributeMap[priceType].strokeWidth)
+ .attr('stroke-dasharray', (priceType) => priceAttributeMap[priceType].strokeDasharray)
+ .attr('class', styles.line)
+ .attr('d', (priceType) =>
+ line()
+ .x(({ crop_date }) => xScale(getCropDate(crop_date)))
+ .y((pricePoint) => yScale(pricePoint[priceType]))(pricePoints[priceType]),
+ );
+
+ const circles = ['network_price', 'own_price'].reduce((circles, priceType) => {
+ for (const pricePoint of pricePoints[priceType]) {
+ circles.push({
+ stroke: priceAttributeMap[priceType].stroke,
+ cx: xScale(getCropDate(pricePoint.crop_date)),
+ cy: yScale(pricePoint[priceType]),
+ r: 6,
+ });
+ }
+ return circles;
+ }, []);
+ svg
+ .select(`.${styles.lines}`)
+ .selectAll(`.${styles.circle}`)
+ .data(circles)
+ .join('circle')
+ .attr('fill', ({ stroke }) => stroke)
+ .attr('r', ({ r }) => r)
+ .attr('cx', ({ cx }) => cx)
+ .attr('cy', ({ cy }) => cy)
+ .attr('class', styles.circle);
+ }, [pricePoints?.length, width, year]);
+
+ const cropPriceByMonth = useMemo(() => {
+ return pricePoints.own_price.reduce((cropPriceByMonth, cropPrice) => {
+ cropPriceByMonth[cropPrice.crop_date] = cropPrice;
+ return cropPriceByMonth;
+ }, {});
+ }, [pricePoints.own_price]);
+ const debounce = useDebounce();
+
+ function pointermoved(event) {
+ debounce(() => {
+ const { yScale, svg, xScale, xAxis, yAxis } = d3Refs.current;
+ const tooltip = svg.select(`.${styles.tooltip}`);
+ const cropDates = pricePoints.network_price.map(({ crop_date }) => getCropDate(crop_date));
+ const i = bisectCenter(cropDates, xScale.invert(pointer(event)[0]));
+ const netWorkPrice = { ...pricePoints.network_price[i], priceType: 'network_price' };
+ const cropPrice = cropPriceByMonth[netWorkPrice.crop_date] && {
+ ...cropPriceByMonth[netWorkPrice.crop_date],
+ priceType: 'own_price',
+ };
+ const cursorYInvert = yScale.invert(pointer(event)[1]);
+
+ const price =
+ cropPrice &&
+ Math.abs(cropPrice.own_price - cursorYInvert) <
+ Math.abs(netWorkPrice.network_price - cursorYInvert)
+ ? cropPrice
+ : netWorkPrice;
+ tooltip.style('display', null);
+ tooltip.attr(
+ 'transform',
+ `translate(${xScale(cropDates[i])},${yScale(price[price.priceType])})`,
+ );
+
+ const path = tooltip
+ .selectAll('path')
+ .data([1])
+ .join('path')
+ .attr('fill', colors.grey400)
+ .attr('stroke', 'transparent');
+
+ const text = tooltip
+ .selectAll('text')
+ .data([1])
+ .join('text')
+ .attr('fill', colors.grey900)
+ .call((text) =>
+ text
+ .selectAll('tspan')
+ .data([
+ `${t('common:DATE')}: ${price.crop_date}`,
+ `${t(`INSIGHTS.PRICES.${price.priceType.toUpperCase()}`)}: ${price[price.priceType]}`,
+ ])
+ .join('tspan')
+ .attr('x', 0)
+ .attr('y', (_, i) => `${i * 1.1}em`)
+ .text((d) => d),
+ );
+
+ const { x, y, width: w, height: h } = text.node().getBBox();
+ text.attr('transform', `translate(${-w / 2},${15 - y})`);
+ path.attr('d', `M${-w / 2 - 10},5H-5l5,-5l5,5H${w / 2 + 10}v${h + 20}h-${w + 20}z`);
+ svg.property('value', netWorkPrice).dispatch('input', { bubbles: true });
+ }, 100);
+ }
+
+ function pointerleft() {
+ const { yScale, svg, xScale, xAxis, yAxis } = d3Refs.current;
+ const tooltip = svg.select(`.${styles.tooltip}`);
+ tooltip.style('display', 'none');
+ svg.node().value = null;
+ svg.dispatch('input', { bubbles: true });
+ }
+
+ return (
+
+ {name}
+ event.preventDefault()}
+ >
+
+
+
+
+
+
+
+ );
+}
+
+function getNumberOfTicks(width) {
+ if (width > 680) return 12;
+ if (width > 480) return 6;
+ if (width > 320) return 4;
+ return 3;
+}
+
+function getCropDate(crop_date) {
+ return new Date(`${crop_date}-01`);
+}
diff --git a/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/styles.module.scss b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/styles.module.scss
new file mode 100644
index 0000000000..b5d8414f82
--- /dev/null
+++ b/packages/webapp/src/components/Insights/PriceCropCharts/PriceCropContainer/styles.module.scss
@@ -0,0 +1,66 @@
+.svg {
+ max-width: 100%;
+ font-family: 'Open Sans', 'SansSerif', serif;
+ -webkit-tap-highlight-color: transparent;
+ overflow: visible;
+ color: var(--grey900)
+}
+
+.xAxis {
+ text {
+ pointer-events: none;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+}
+
+.yAxis {
+ text {
+ pointer-events: none;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+}
+
+.lines {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.line {
+ cursor: default;
+ opacity: 0.8;
+ fill: transparent;
+}
+
+.circle {
+ cursor: pointer;
+ opacity: 0.9;
+}
+
+.tooltip {
+ pointer-events: none;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.title {
+ pointer-events: none;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/packages/webapp/src/components/Insights/PriceCropCharts/styles.module.scss b/packages/webapp/src/components/Insights/PriceCropCharts/styles.module.scss
new file mode 100644
index 0000000000..a8a35dbff0
--- /dev/null
+++ b/packages/webapp/src/components/Insights/PriceCropCharts/styles.module.scss
@@ -0,0 +1,22 @@
+.svg {
+ height: 20px;
+ width: 48px;
+}
+
+.chartTitleContainer {
+ position: relative;
+ pointer-events: none;
+}
+
+.labelContainer {
+ position: absolute;
+ right: 0;
+ top: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.label {
+ display: flex;
+ flex-direction: row;
+}
diff --git a/packages/webapp/src/components/Insights/PriceCropContainer/index.js b/packages/webapp/src/components/Insights/PriceCropContainer/index.js
deleted file mode 100644
index 676917e1e8..0000000000
--- a/packages/webapp/src/components/Insights/PriceCropContainer/index.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import ReactChartKick, { AreaChart } from 'react-chartkick';
-import Chart from 'chart.js';
-import { getMassUnit, roundToTwoDecimal } from '../../../util';
-import { useSelector } from 'react-redux';
-import { userFarmSelector } from '../../../containers/userFarmSlice';
-import { Semibold } from '../../Typography';
-import { useTranslation } from 'react-i18next';
-
-ReactChartKick.addAdapter(Chart);
-
-function PriceCropContainer({ currencySymbol, name, pricePoints }) {
- const [state, setState] = useState({
- max: 0,
- ownPriceSeries: {},
- networkPriceSeries: {},
- });
-
- const {
- units: { measurement },
- } = useSelector(userFarmSelector);
-
- const { t } = useTranslation();
-
- const formatState = () => {
- const ownPriceSeries = {};
- const networkPriceSeries = {};
-
- pricePoints.forEach((pricePoint, index) => {
- // Clean data: format crop_date into YY-MM-DD and round prices to two decimal places
- ownPriceSeries[[pricePoint['crop_date'] + '-01']] = roundToTwoDecimal(
- pricePoint['crop_price'] / (measurement === 'metric' ? 1 : 2.20462),
- );
- networkPriceSeries[[pricePoint['crop_date'] + '-01']] = roundToTwoDecimal(
- pricePoint['network_price'] / (measurement === 'metric' ? 1 : 2.20462),
- );
- });
-
- // Find max datapoint across the two datasets for styling chart
- const ownPriceDataPoints = Object.values(ownPriceSeries);
- const networkPriceDataPoints = Object.values(networkPriceSeries);
- const allDataPoints = ownPriceDataPoints.concat(networkPriceDataPoints);
- const maxDataPoint = allDataPoints.reduce((a, b) => Math.max(a, b));
-
- setState({
- ownPriceSeries,
- networkPriceSeries,
- max: maxDataPoint,
- });
- };
-
- useEffect(() => formatState(), [pricePoints]);
-
- const { ownPriceSeries, networkPriceSeries, max } = state;
-
- const yTitle = t('INSIGHTS.PRICES.Y_TITLE', { currency: currencySymbol, mass: getMassUnit(), interpolation: { escapeValue: false } });
- return (
-
- );
-}
-
-export default PriceCropContainer;
diff --git a/packages/webapp/src/components/Insights/PriceDistanceComponent/index.js b/packages/webapp/src/components/Insights/PriceDistanceComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/PriceDistanceComponent/index.js
rename to packages/webapp/src/components/Insights/PriceDistanceComponent/index.jsx
diff --git a/packages/webapp/src/components/Insights/SoilOMInfo/index.js b/packages/webapp/src/components/Insights/SoilOMInfo/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/SoilOMInfo/index.js
rename to packages/webapp/src/components/Insights/SoilOMInfo/index.jsx
diff --git a/packages/webapp/src/components/Insights/WaterBalanceInfo/WaterBalanceBarComponent/index.js b/packages/webapp/src/components/Insights/WaterBalanceInfo/WaterBalanceBarComponent/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/WaterBalanceInfo/WaterBalanceBarComponent/index.js
rename to packages/webapp/src/components/Insights/WaterBalanceInfo/WaterBalanceBarComponent/index.jsx
diff --git a/packages/webapp/src/components/Insights/WaterBalanceInfo/index.js b/packages/webapp/src/components/Insights/WaterBalanceInfo/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Insights/WaterBalanceInfo/index.js
rename to packages/webapp/src/components/Insights/WaterBalanceInfo/index.jsx
diff --git a/packages/webapp/src/components/InviteSignup/index.js b/packages/webapp/src/components/InviteSignup/index.jsx
similarity index 100%
rename from packages/webapp/src/components/InviteSignup/index.js
rename to packages/webapp/src/components/InviteSignup/index.jsx
diff --git a/packages/webapp/src/components/InviteUser/index.js b/packages/webapp/src/components/InviteUser/index.js
deleted file mode 100644
index 411f757e54..0000000000
--- a/packages/webapp/src/components/InviteUser/index.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import Input, { getInputErrors, integerOnKeyDown } from '../Form/Input';
-import React, { useEffect } from 'react';
-import { Title } from '../Typography';
-import PropTypes from 'prop-types';
-import { Controller, useForm } from 'react-hook-form';
-import ReactSelect from '../Form/ReactSelect';
-import { useTranslation } from 'react-i18next';
-import { getFirstNameLastName } from '../../util';
-
-export default function PureInviteUser({ onInvite, onGoBack, roleOptions = [] }) {
- const {
- register,
- handleSubmit,
- watch,
- control,
- setValue,
- trigger,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onTouched',
- });
- const NAME = 'name';
- const ROLE = 'role';
- const EMAIL = 'email';
- const GENDER = 'gender';
- const BIRTHYEAR = 'birth_year';
- const WAGE = 'wage';
- const PHONE = 'phone_number';
- const name = watch(NAME, undefined);
- const email = watch(EMAIL, undefined);
- const role = watch(ROLE, undefined);
- const selectedRoleId = role?.value;
- useEffect(() => {
- trigger(EMAIL);
- }, [selectedRoleId]);
- const { t } = useTranslation(['translation', 'common', 'gender']);
- const title = t('INVITE_USER.TITLE');
- const genderOptions = [
- { value: 'MALE', label: t('gender:MALE') },
- { value: 'FEMALE', label: t('gender:FEMALE') },
- { value: 'OTHER', label: t('gender:OTHER') },
- { value: 'PREFER_NOT_TO_SAY', label: t('gender:PREFER_NOT_TO_SAY') },
- ];
-
- const disabled = !isValid || !isDirty;
- const onSubmit = (data) => {
- data[GENDER] = data?.[GENDER]?.value || 'PREFER_NOT_TO_SAY';
- data[ROLE] = data?.[ROLE]?.value;
- const { first_name, last_name } = getFirstNameLastName(data.name);
- onInvite({ ...data, email, first_name, last_name });
- };
- const onError = (data) => {
- console.log('error: ', data);
- };
-
- return (
-
- );
-}
-
-PureInviteUser.prototype = {
- onLogin: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/InviteUser/index.jsx b/packages/webapp/src/components/InviteUser/index.jsx
new file mode 100644
index 0000000000..6b99bff60e
--- /dev/null
+++ b/packages/webapp/src/components/InviteUser/index.jsx
@@ -0,0 +1,192 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import Input, { getInputErrors, integerOnKeyDown, numberOnKeyDown } from '../Form/Input';
+import React, { useEffect } from 'react';
+import { Title } from '../Typography';
+import PropTypes from 'prop-types';
+import { Controller, useForm } from 'react-hook-form';
+import ReactSelect from '../Form/ReactSelect';
+import { useTranslation } from 'react-i18next';
+import { getFirstNameLastName } from '../../util';
+
+export default function PureInviteUser({ onInvite, onGoBack, roleOptions = [] }) {
+ const {
+ register,
+ handleSubmit,
+ watch,
+ control,
+ setValue,
+ trigger,
+
+ formState: { isValid, isDirty, errors },
+ } = useForm({
+ mode: 'onTouched',
+ });
+ const NAME = 'name';
+ const ROLE = 'role';
+ const EMAIL = 'email';
+ const GENDER = 'gender';
+ const LANGUAGE = 'language';
+ const BIRTHYEAR = 'birth_year';
+ const WAGE = 'wage';
+ const PHONE = 'phone_number';
+ const name = watch(NAME, undefined);
+ const email = watch(EMAIL, undefined);
+ const role = watch(ROLE, undefined);
+ const selectedRoleId = role?.value;
+ useEffect(() => {
+ selectedRoleId && trigger(EMAIL);
+ }, [selectedRoleId]);
+ const { t } = useTranslation(['translation', 'common', 'gender']);
+ const title = t('INVITE_USER.TITLE');
+ const genderOptions = [
+ { value: 'MALE', label: t('gender:MALE') },
+ { value: 'FEMALE', label: t('gender:FEMALE') },
+ { value: 'OTHER', label: t('gender:OTHER') },
+ { value: 'PREFER_NOT_TO_SAY', label: t('gender:PREFER_NOT_TO_SAY') },
+ ];
+ const languageOptions = [
+ { value: 'en', label: t('PROFILE.ACCOUNT.ENGLISH') },
+ { value: 'es', label: t('PROFILE.ACCOUNT.SPANISH') },
+ { value: 'pt', label: t('PROFILE.ACCOUNT.PORTUGUESE') },
+ { value: 'fr', label: t('PROFILE.ACCOUNT.FRENCH') },
+ ];
+
+ const disabled = !isValid || !isDirty;
+ const onSubmit = (data) => {
+ data[GENDER] = data?.[GENDER]?.value || 'PREFER_NOT_TO_SAY';
+ data[ROLE] = data?.[ROLE]?.value;
+ data[LANGUAGE] = data?.[LANGUAGE]?.value || t('INVITE_USER.DEFAULT_LANGUAGE_VALUE');
+ const { first_name, last_name } = getFirstNameLastName(data.name);
+ onInvite({ ...data, email, first_name, last_name });
+ };
+
+ return (
+
+ );
+}
+
+PureInviteUser.prototype = {
+ onLogin: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/InvitedUserCreateAccount/index.js b/packages/webapp/src/components/InvitedUserCreateAccount/index.jsx
similarity index 100%
rename from packages/webapp/src/components/InvitedUserCreateAccount/index.js
rename to packages/webapp/src/components/InvitedUserCreateAccount/index.jsx
diff --git a/packages/webapp/src/components/JoinFarmSuccessScreen/index.js b/packages/webapp/src/components/JoinFarmSuccessScreen/index.jsx
similarity index 100%
rename from packages/webapp/src/components/JoinFarmSuccessScreen/index.js
rename to packages/webapp/src/components/JoinFarmSuccessScreen/index.jsx
diff --git a/packages/webapp/src/components/JoyrideWrapper/JoyrideTooltip.js b/packages/webapp/src/components/JoyrideWrapper/JoyrideTooltip.js
deleted file mode 100644
index 3c2c73ce2d..0000000000
--- a/packages/webapp/src/components/JoyrideWrapper/JoyrideTooltip.js
+++ /dev/null
@@ -1,97 +0,0 @@
-import { Label, Semibold } from '../Typography';
-import { colors } from '../../assets/theme';
-import React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import Button from '../Form/Button';
-import { useTranslation } from 'react-i18next';
-
-const useStyles = makeStyles((theme) => ({
- container: {
- display: 'flex',
- flexDirection: 'column',
- maxWidth: '500px',
- width: 'calc(100vw - 48px)',
- background: '#fafafd',
- borderRadius: '7.05466px',
- position: 'relative',
- padding: '16px',
- },
- contentsContainer: {
- display: 'grid',
- gap: '8px',
- },
- buttonGroup: {
- marginTop: '16px',
- display: 'flex',
- },
-}));
-
-export default function JoyrideTooltip({
- step: { title, children, contents, isOrdered, list, buttonText, style, icon },
- continuous,
- tooltipProps,
- primaryProps,
- isLastStep,
-}) {
- const { t } = useTranslation();
- const classes = useStyles();
- return (
-
- {!!title && (
-
- {icon && icon}
- {title}
-
- )}
-
- {contents && !!contents.length && (
-
- {contents?.map((line, index) => (
-
- {line}
-
- ))}
-
- )}
- {list && !!list.length && (
-
- {list?.map((line, index) => (
-
- {line}
-
- ))}
-
- )}
-
-
- {children}
- {
-
-
- {buttonText || (isLastStep ? t('common:GOT_IT') : t('common:NEXT'))}
-
-
- }
-
- );
-}
-
-function List({ children, isOrdered, classes }) {
- const style = { marginLeft: '20px' };
- return isOrdered ? (
-
- {children}
-
- ) : (
-
- );
-}
diff --git a/packages/webapp/src/components/JoyrideWrapper/index.js b/packages/webapp/src/components/JoyrideWrapper/index.js
deleted file mode 100644
index c2886e8f77..0000000000
--- a/packages/webapp/src/components/JoyrideWrapper/index.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import JoyrideTooltip from './JoyrideTooltip';
-import Joyride, { STATUS } from 'react-joyride';
-import React from 'react';
-
-export default function JoyrideWrapper({ steps, onFinish, ...props }) {
- const callback = (data) => {
- if (STATUS.FINISHED === data.status) {
- onFinish();
- }
- };
- return (
- ({
- disableBeacon: true,
- disableCloseOnEsc: index !== steps.length - 1,
- ...step,
- }))}
- tooltipComponent={JoyrideTooltip}
- continuous
- floaterProps={{ disableAnimation: true }}
- styles={{
- options: {
- zIndex: 1100,
- overlayColor: 'rgba(25, 25, 40, 0.8)',
- },
- tooltip: {
- padding: '16px',
- },
- }}
- disableBeacon={true}
- spotlightPadding={12}
- callback={onFinish ? callback : props.callback}
- {...props}
- />
- );
-}
diff --git a/packages/webapp/src/components/Layout/TitleLayout.js b/packages/webapp/src/components/Layout/TitleLayout.jsx
similarity index 100%
rename from packages/webapp/src/components/Layout/TitleLayout.js
rename to packages/webapp/src/components/Layout/TitleLayout.jsx
diff --git a/packages/webapp/src/components/Layout/index.js b/packages/webapp/src/components/Layout/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Layout/index.js
rename to packages/webapp/src/components/Layout/index.jsx
diff --git a/packages/webapp/src/components/Loading/Loading.js b/packages/webapp/src/components/Loading/Loading.jsx
similarity index 100%
rename from packages/webapp/src/components/Loading/Loading.js
rename to packages/webapp/src/components/Loading/Loading.jsx
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/AreaDetails.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/AreaDetails.jsx
new file mode 100644
index 0000000000..9ea43cd42b
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/AreaDetails.jsx
@@ -0,0 +1,127 @@
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useFormContext } from 'react-hook-form';
+import Input from '../../Form/Input';
+import PureWarningBox from '../../WarningBox';
+import { Label } from '../../Typography';
+import Unit from '../../Form/Unit';
+import { fieldEnum as areaEnum } from '../../../containers/constants';
+import { area_perimeter, area_total_area } from '../../../util/convert-units/unit';
+import InputAutoSize from '../../Form/InputAutoSize';
+
+export default function AreaDetails({
+ name,
+ showPerimeter,
+ history,
+ children,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ total_area,
+ perimeter,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ getValues,
+ setValue,
+ watch,
+ control,
+ formState: { errors },
+ } = useFormContext();
+ const [errorMessage, setErrorMessage] = useState();
+ useEffect(() => {
+ const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
+ const handleOnline = () => setErrorMessage(null);
+ window.addEventListener('offline', handleOffline);
+ window.addEventListener('online', handleOnline);
+ return () => {
+ window.removeEventListener('offline', handleOffline);
+ window.removeEventListener('online', handleOnline);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (history?.location?.state?.error && !history?.location?.state?.error?.retire) {
+ setErrorMessage(history?.location?.state?.error);
+ }
+ }, [history?.location?.state?.error]);
+
+ return (
+ <>
+ {errorMessage && (
+
+ {errorMessage}
+
+ )}
+
+
+
+ {showPerimeter && (
+
+ )}
+
+ {children}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.js
deleted file mode 100644
index a63f84171c..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.js
+++ /dev/null
@@ -1,198 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import { barnEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-
-import RadioGroup from '../../../Form/RadioGroup';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureBarnWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureBarn({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = false;
- const onSubmit = (data) => {
- const washPackSelection = data[barnEnum.wash_and_pack];
- const coldStorage = data[barnEnum.cold_storage];
- const usedForAnimals = data[barnEnum.used_for_animals];
- data[barnEnum.total_area_unit] = data[barnEnum.total_area_unit]?.value;
- data[barnEnum.perimeter_unit] = data[barnEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- type: 'barn',
- wash_and_pack: washPackSelection,
- cold_storage: coldStorage,
- used_for_animals: usedForAnimals,
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.BARN.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.BARN.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.jsx
new file mode 100644
index 0000000000..01851384ea
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Barn/index.jsx
@@ -0,0 +1,155 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { useFormContext } from 'react-hook-form';
+import { barnEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+
+import RadioGroup from '../../../Form/RadioGroup';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureBarnWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureBarn({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const washPackSelection = data[barnEnum.wash_and_pack];
+ const coldStorage = data[barnEnum.cold_storage];
+ const usedForAnimals = data[barnEnum.used_for_animals];
+ data[barnEnum.total_area_unit] = data[barnEnum.total_area_unit]?.value;
+ data[barnEnum.perimeter_unit] = data[barnEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ type: 'barn',
+ wash_and_pack: washPackSelection,
+ cold_storage: coldStorage,
+ used_for_animals: usedForAnimals,
+ });
+ submitForm({ formData });
+ };
+
+ return (
+ }
+ tabs={['tasks', 'details']}
+ showPerimeter={false}
+ />
+ );
+}
+
+export function BarnDetailChildren({ isViewLocationPage }) {
+ const { t } = useTranslation();
+ const { control } = useFormContext();
+ return (
+ <>
+
+
+
+ {t('FARM_MAP.BARN.WASH_PACK')}
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+
+
+ {t('FARM_MAP.BARN.COLD_STORAGE')}
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+
+
+ {t('FARM_MAP.BARN.ANIMALS')}
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.js
deleted file mode 100644
index 419c0d89e6..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import LocationButtons from '../../LocationButtons';
-import { ceremonialEnum } from '../../../../containers/constants';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureCeremonialAreaWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureCeremonialArea({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- data[ceremonialEnum.total_area_unit] = data[ceremonialEnum.total_area_unit]?.value;
- data[ceremonialEnum.perimeter_unit] = data[ceremonialEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- type: 'ceremonial_area',
- });
- submitForm({ formData });
- };
- const title =
- (isCreateLocationPage && t('FARM_MAP.CEREMONIAL_AREA.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.CEREMONIAL_AREA.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.jsx
new file mode 100644
index 0000000000..edcde284cb
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/CeremonialArea/index.jsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm } from 'react-hook-form';
+import LocationButtons from '../../LocationButtons';
+import { ceremonialEnum } from '../../../../containers/constants';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+import { BarnDetailChildren } from '../Barn';
+
+export default function PureCeremonialAreaWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureCeremonialArea({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ data[ceremonialEnum.total_area_unit] = data[ceremonialEnum.total_area_unit]?.value;
+ data[ceremonialEnum.perimeter_unit] = data[ceremonialEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ type: 'ceremonial_area',
+ });
+ submitForm({ formData });
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.js
deleted file mode 100644
index 67ce963261..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import LocationButtons from '../../LocationButtons';
-import { farmSiteBoundaryEnum } from '../../../../containers/constants';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureFarmSiteBoundaryWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureFarmSiteBoundary({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- data[farmSiteBoundaryEnum.total_area_unit] = data[farmSiteBoundaryEnum.total_area_unit]?.value;
- data[farmSiteBoundaryEnum.perimeter_unit] = data[farmSiteBoundaryEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'farm_site_boundary',
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.FARM_SITE_BOUNDARY.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.FARM_SITE_BOUNDARY.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.jsx
new file mode 100644
index 0000000000..4b146d3822
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/FarmSiteBoundary/index.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { farmSiteBoundaryEnum } from '../../../../containers/constants';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureFarmSiteBoundaryWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureFarmSiteBoundary({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ data[farmSiteBoundaryEnum.total_area_unit] = data[farmSiteBoundaryEnum.total_area_unit]?.value;
+ data[farmSiteBoundaryEnum.perimeter_unit] = data[farmSiteBoundaryEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'farm_site_boundary',
+ });
+ submitForm({ formData });
+ };
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.js
deleted file mode 100644
index 0e2be0007d..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.js
+++ /dev/null
@@ -1,192 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
-import Input from '../../../Form/Input';
-import { fieldEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RouterTab from '../../../RouterTab';
-
-import { getDateInputFormat } from '../../../../util/moment';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import RadioGroup from '../../../Form/RadioGroup';
-import {
- getFormDataWithoutNulls,
- getProcessedFormData,
-} from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureFieldWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureField({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- getProcessedFormData();
- const { t } = useTranslation();
- const getDefaultValues = () => {
- return {
- [fieldEnum.transition_date]: getDateInputFormat(new Date()),
- [fieldEnum.organic_status]: 'Non-Organic',
- ...persistedFormData,
- };
- };
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: getDefaultValues(),
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const fieldTypeSelection = watch(fieldEnum.organic_status);
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- data[fieldEnum.total_area_unit] = data[fieldEnum.total_area_unit]?.value;
- data[fieldEnum.perimeter_unit] = data[fieldEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'field',
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.FIELD.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.FIELD.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.jsx
new file mode 100644
index 0000000000..d372b5ab36
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Field/index.jsx
@@ -0,0 +1,136 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
+import Input from '../../../Form/Input';
+import { fieldEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+import LocationButtons from '../../LocationButtons';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import RouterTab from '../../../RouterTab';
+
+import { getDateInputFormat } from '../../../../util/moment';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import RadioGroup from '../../../Form/RadioGroup';
+import {
+ getFormDataWithoutNulls,
+ getProcessedFormData,
+} from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureFieldWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureField({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ getProcessedFormData();
+ const getDefaultValues = () => {
+ return {
+ [fieldEnum.organic_status]: 'Non-Organic',
+ ...persistedFormData,
+ [fieldEnum.transition_date]: getDateInputFormat(
+ persistedFormData[fieldEnum.transition_date] || new Date(),
+ ),
+ };
+ };
+ const onSubmit = (data) => {
+ data[fieldEnum.total_area_unit] = data[fieldEnum.total_area_unit]?.value;
+ data[fieldEnum.perimeter_unit] = data[fieldEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'field',
+ });
+ submitForm({ formData });
+ };
+
+ return (
+ }
+ showPerimeter={true}
+ tabs={['crops', 'tasks', 'details']}
+ />
+ );
+}
+
+export function FieldDetailsChildren({ isViewLocationPage }) {
+ const { t } = useTranslation();
+ const { control, watch, register } = useFormContext();
+ const fieldTypeSelection = watch(fieldEnum.organic_status);
+ return (
+
+
+
+ {t('FARM_MAP.FIELD.FIELD_TYPE')}
+
+
+
+
+
+
+
+ {fieldTypeSelection === 'Transitional' && (
+
+ )}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.js
deleted file mode 100644
index 1812fa85c4..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.js
+++ /dev/null
@@ -1,192 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
-import Input, { getInputErrors } from '../../../Form/Input';
-import { gardenEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RouterTab from '../../../RouterTab';
-
-import { getDateInputFormat } from '../../../../util/moment';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import RadioGroup from '../../../Form/RadioGroup';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureGardenWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureGarden({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const getDefaultValues = () => {
- return {
- [gardenEnum.transition_date]: getDateInputFormat(new Date()),
- [gardenEnum.organic_status]: 'Non-Organic',
- ...persistedFormData,
- };
- };
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: getDefaultValues(),
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const gardenTypeSelection = watch(gardenEnum.organic_status);
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- data[gardenEnum.total_area_unit] = data[gardenEnum.total_area_unit]?.value;
- data[gardenEnum.perimeter_unit] = data[gardenEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'garden',
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.GARDEN.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.GARDEN.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.jsx
new file mode 100644
index 0000000000..678c187034
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Garden/index.jsx
@@ -0,0 +1,137 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { useFormContext } from 'react-hook-form';
+import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
+import Input, { getInputErrors } from '../../../Form/Input';
+import { gardenEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+import { getDateInputFormat } from '../../../../util/moment';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import RadioGroup from '../../../Form/RadioGroup';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureGardenWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureGarden({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const getDefaultValues = () => {
+ return {
+ [gardenEnum.organic_status]: 'Non-Organic',
+ ...persistedFormData,
+ [gardenEnum.transition_date]: getDateInputFormat(
+ persistedFormData[gardenEnum.transition_date] || new Date(),
+ ),
+ };
+ };
+ const onSubmit = (data) => {
+ data[gardenEnum.total_area_unit] = data[gardenEnum.total_area_unit]?.value;
+ data[gardenEnum.perimeter_unit] = data[gardenEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'garden',
+ });
+ submitForm({ formData });
+ };
+
+ return (
+ }
+ tabs={['crops', 'tasks', 'details']}
+ showPerimeter={true}
+ />
+ );
+}
+
+export function GardenDetailsChildren({ isViewLocationPage }) {
+ const { t } = useTranslation();
+ const {
+ control,
+ watch,
+ register,
+ formState: { errors },
+ } = useFormContext();
+ const gardenTypeSelection = watch(gardenEnum.organic_status);
+ return (
+
+
+
+ {t('FARM_MAP.GARDEN.GARDEN_TYPE')}
+
+
+
+
+
+ {gardenTypeSelection === 'Transitional' && (
+
+ )}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.js
deleted file mode 100644
index da2c3a71a3..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.js
+++ /dev/null
@@ -1,252 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
-import Input from '../../../Form/Input';
-import { greenhouseEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RouterTab from '../../../RouterTab';
-
-import { getDateInputFormat } from '../../../../util/moment';
-import RadioGroup from '../../../Form/RadioGroup';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureGreenhouseWrapper(props) {
- return (
-
-
-
- );
-}
-
-export function PureGreenhouse({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const getDefaultValues = () => {
- return {
- [greenhouseEnum.transition_date]: getDateInputFormat(new Date()),
- [greenhouseEnum.organic_status]: 'Non-Organic',
- ...persistedFormData,
- };
- };
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: getDefaultValues(),
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
-
- const greenhouseTypeSelection = watch(greenhouseEnum.organic_status);
-
- const disabled = !isValid;
- console.log(isValid, isDirty, errors);
- const showPerimeter = false;
- const onSubmit = (data) => {
- const supplementalLighting = data[greenhouseEnum.supplemental_lighting];
- const co2Enrichment = data[greenhouseEnum.co2_enrichment];
- const greenhouseHeated = data[greenhouseEnum.greenhouse_heated];
- data[greenhouseEnum.total_area_unit] = data[greenhouseEnum.total_area_unit]?.value;
- data[greenhouseEnum.perimeter_unit] = data[greenhouseEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'greenhouse',
- supplemental_lighting: supplementalLighting,
- co2_enrichment: co2Enrichment,
- greenhouse_heated: greenhouseHeated,
- });
- submitForm({ formData });
- };
- const title =
- (isCreateLocationPage && t('FARM_MAP.GREENHOUSE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.GREENHOUSE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.jsx
new file mode 100644
index 0000000000..91d2932aab
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Greenhouse/index.jsx
@@ -0,0 +1,194 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
+import Input from '../../../Form/Input';
+import { greenhouseEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+import LocationButtons from '../../LocationButtons';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import RouterTab from '../../../RouterTab';
+
+import { getDateInputFormat } from '../../../../util/moment';
+import RadioGroup from '../../../Form/RadioGroup';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureGreenhouseWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureGreenhouse({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const getDefaultValues = () => {
+ return {
+ [greenhouseEnum.organic_status]: 'Non-Organic',
+ ...persistedFormData,
+ [greenhouseEnum.transition_date]: getDateInputFormat(
+ persistedFormData[greenhouseEnum.transition_date] || new Date(),
+ ),
+ };
+ };
+ const onSubmit = (data) => {
+ const supplementalLighting = data[greenhouseEnum.supplemental_lighting];
+ const co2Enrichment = data[greenhouseEnum.co2_enrichment];
+ const greenhouseHeated = data[greenhouseEnum.greenhouse_heated];
+ data[greenhouseEnum.total_area_unit] = data[greenhouseEnum.total_area_unit]?.value;
+ data[greenhouseEnum.perimeter_unit] = data[greenhouseEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'greenhouse',
+ supplemental_lighting: supplementalLighting,
+ co2_enrichment: co2Enrichment,
+ greenhouse_heated: greenhouseHeated,
+ });
+ submitForm({ formData });
+ };
+
+ return (
+ }
+ showPerimeter={false}
+ tabs={['crops', 'tasks', 'details']}
+ />
+ );
+}
+
+export function GreenhouseDetailsChildren({ isViewLocationPage }) {
+ const { t } = useTranslation();
+ const { register, watch, control } = useFormContext();
+ const greenhouseTypeSelection = watch(greenhouseEnum.organic_status);
+ return (
+
+
+
+ {t('FARM_MAP.GREENHOUSE.GREENHOUSE_TYPE')}
+
+
+
+
+
+
+ {greenhouseTypeSelection === 'Transitional' && (
+
+ )}
+
+
+ {greenhouseTypeSelection === 'Organic' && (
+
+
+
+ {t('FARM_MAP.GREENHOUSE.SUPPLEMENTAL_LIGHTING')}
+
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+ {t('FARM_MAP.GREENHOUSE.CO2_ENRICHMENT')}
+
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+ {t('FARM_MAP.GREENHOUSE.GREENHOUSE_HEATED')}
+
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+ )}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.js
deleted file mode 100644
index df4b8c6e85..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import LocationButtons from '../../LocationButtons';
-import { naturalAreaEnum } from '../../../../containers/constants';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureNaturalAreaWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureNaturalArea({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- data[naturalAreaEnum.total_area_unit] = data[naturalAreaEnum.total_area_unit]?.value;
- data[naturalAreaEnum.perimeter_unit] = data[naturalAreaEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'natural_area',
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.NATURAL_AREA.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.NATURAL_AREA.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.jsx
new file mode 100644
index 0000000000..482693ef4d
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/NaturalArea/index.jsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm } from 'react-hook-form';
+import LocationButtons from '../../LocationButtons';
+import { naturalAreaEnum } from '../../../../containers/constants';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+import { FieldDetailsChildren } from '../Field';
+
+export default function PureNaturalAreaWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureNaturalArea({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const { t } = useTranslation();
+ const onSubmit = (data) => {
+ data[naturalAreaEnum.total_area_unit] = data[naturalAreaEnum.total_area_unit]?.value;
+ data[naturalAreaEnum.perimeter_unit] = data[naturalAreaEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'natural_area',
+ });
+ submitForm({ formData });
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.js
deleted file mode 100644
index e92a210f3e..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import LocationButtons from '../../LocationButtons';
-import { residenceEnum } from '../../../../containers/constants';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureResidenceWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureResidence({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = false;
- const onSubmit = (data) => {
- data[residenceEnum.total_area_unit] = data[residenceEnum.total_area_unit]?.value;
-
- data[residenceEnum.perimeter_unit] = data[residenceEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
-
- type: 'residence',
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.RESIDENCE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.RESIDENCE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.jsx
new file mode 100644
index 0000000000..440d626ac0
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/Residence/index.jsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm } from 'react-hook-form';
+import LocationButtons from '../../LocationButtons';
+import { residenceEnum } from '../../../../containers/constants';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+import { FieldDetailsChildren } from '../Field';
+
+export default function PureResidenceWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureResidence({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ data[residenceEnum.total_area_unit] = data[residenceEnum.total_area_unit]?.value;
+
+ data[residenceEnum.perimeter_unit] = data[residenceEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+
+ type: 'residence',
+ });
+ submitForm({ formData });
+ };
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.js
deleted file mode 100644
index 903a5b4c09..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import AreaDetails from '../index';
-import { useForm } from 'react-hook-form';
-import { surfaceWaterEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-
-import RadioGroup from '../../../Form/RadioGroup';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureSurfaceWaterWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureSurfaceWater({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const showPerimeter = true;
- const onSubmit = (data) => {
- const usedForIrrigation = data[surfaceWaterEnum.used_for_irrigation];
- data[surfaceWaterEnum.total_area_unit] = data[surfaceWaterEnum.total_area_unit]?.value;
- data[surfaceWaterEnum.perimeter_unit] = data[surfaceWaterEnum.perimeter_unit]?.value;
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- type: 'surface_water',
- used_for_irrigation: usedForIrrigation,
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.SURFACE_WATER.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.SURFACE_WATER.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.jsx b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.jsx
new file mode 100644
index 0000000000..85300e4752
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/SurfaceWater/index.jsx
@@ -0,0 +1,97 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import AreaDetails from '../AreaDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import { surfaceWaterEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+import LocationButtons from '../../LocationButtons';
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+
+import RadioGroup from '../../../Form/RadioGroup';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+import { FieldDetailsChildren } from '../Field';
+
+export default function PureSurfaceWaterWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureSurfaceWater({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const usedForIrrigation = data[surfaceWaterEnum.used_for_irrigation];
+ data[surfaceWaterEnum.total_area_unit] = data[surfaceWaterEnum.total_area_unit]?.value;
+ data[surfaceWaterEnum.perimeter_unit] = data[surfaceWaterEnum.perimeter_unit]?.value;
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ type: 'surface_water',
+ used_for_irrigation: usedForIrrigation,
+ });
+ submitForm({ formData });
+ };
+
+ return (
+ }
+ showPerimeter={true}
+ tabs={['tasks', 'details']}
+ />
+ );
+}
+
+export function SurfaceWaterDetailsChildren({ isViewLocationPage }) {
+ const { t } = useTranslation();
+ const { control } = useFormContext();
+ return (
+
+
+
+ {t('FARM_MAP.SURFACE_WATER.IRRIGATION')}
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/index.js b/packages/webapp/src/components/LocationDetailLayout/AreaDetails/index.js
deleted file mode 100644
index d31c529972..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/AreaDetails/index.js
+++ /dev/null
@@ -1,124 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import Input from '../../Form/Input';
-import PureWarningBox from '../../WarningBox';
-import { Label } from '../../Typography';
-import Unit from '../../Form/Unit';
-import { fieldEnum as areaEnum } from '../../../containers/constants';
-import { area_perimeter, area_total_area } from '../../../util/unit';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export default function AreaDetails({
- name,
- register,
- showPerimeter,
- setValue,
- getValues,
- setError,
- control,
- watch,
- history,
- children,
- errors,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- total_area,
- perimeter,
-}) {
- const { t } = useTranslation();
- const [errorMessage, setErrorMessage] = useState();
- useEffect(() => {
- const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
- const handleOnline = () => setErrorMessage(null);
- window.addEventListener('offline', handleOffline);
- window.addEventListener('online', handleOnline);
- return () => {
- window.removeEventListener('offline', handleOffline);
- window.removeEventListener('online', handleOnline);
- };
- }, []);
-
- useEffect(() => {
- if (history?.location?.state?.error && !history?.location?.state?.error?.retire) {
- setErrorMessage(history?.location?.state?.error);
- }
- }, [history?.location?.state?.error]);
-
- return (
- <>
- {errorMessage && (
-
- {errorMessage}
-
- )}
-
-
-
- {showPerimeter && (
-
- )}
-
- {children}
-
- >
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.js b/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.js
deleted file mode 100644
index e31ca5f5a7..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.js
+++ /dev/null
@@ -1,178 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import LineDetails from '../index';
-import { useForm } from 'react-hook-form';
-import { bufferZoneEnum } from '../../../../containers/constants';
-import Unit from '../../../Form/Unit';
-import { area_total_area, line_width } from '../../../../util/unit';
-import LocationButtons from '../../LocationButtons';
-
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RouterTab from '../../../RouterTab';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureBufferZoneWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureBufferZone({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- setValue,
- getValues,
- setError,
- control,
- watch,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const onSubmit = (data) => {
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- type: 'buffer_zone',
- });
- formData[bufferZoneEnum.width_unit] = formData[bufferZoneEnum.width_unit]?.value;
- formData[bufferZoneEnum.length_unit] = formData[bufferZoneEnum.length_unit]?.value;
- formData[bufferZoneEnum.total_area_unit] = formData[bufferZoneEnum.total_area_unit]?.value;
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.BUFFER_ZONE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.BUFFER_ZONE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.jsx b/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.jsx
new file mode 100644
index 0000000000..f52cc521c2
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LineDetails/BufferZone/index.jsx
@@ -0,0 +1,136 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import LineDetails from '../LineDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import { bufferZoneEnum } from '../../../../containers/constants';
+import Unit from '../../../Form/Unit';
+import { area_total_area, line_width } from '../../../../util/convert-units/unit';
+import LocationButtons from '../../LocationButtons';
+
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import RouterTab from '../../../RouterTab';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+import { FieldDetailsChildren } from '../../AreaDetails/Field';
+
+export default function PureBufferZoneWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureBufferZone({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ type: 'buffer_zone',
+ });
+ formData[bufferZoneEnum.width_unit] = formData[bufferZoneEnum.width_unit]?.value;
+ formData[bufferZoneEnum.length_unit] = formData[bufferZoneEnum.length_unit]?.value;
+ formData[bufferZoneEnum.total_area_unit] = formData[bufferZoneEnum.total_area_unit]?.value;
+ submitForm({ formData });
+ };
+
+ return (
+
+ }
+ tabs={['crops', 'tasks', 'details']}
+ />
+ );
+}
+
+export function BufferZoneDetailsChildren({ isViewLocationPage, isEditLocationPage, system }) {
+ const { t } = useTranslation();
+ const {
+ register,
+ setValue,
+ getValues,
+ watch,
+ control,
+ formState: { errors },
+ } = useFormContext();
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.js b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.js
deleted file mode 100644
index be24dcf72b..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.js
+++ /dev/null
@@ -1,162 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import LineDetails from '../index';
-import { useForm } from 'react-hook-form';
-import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
-import { bufferZoneEnum, fenceEnum } from '../../../../containers/constants';
-import { Label } from '../../../Typography';
-import { line_length } from '../../../../util/unit';
-import Unit from '../../../Form/Unit';
-import LocationButtons from '../../LocationButtons';
-
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RadioGroup from '../../../Form/RadioGroup';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureFenceWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureFence({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const onSubmit = (data) => {
- const isPressureTreated = data[fenceEnum.pressure_treated];
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- pressure_treated: isPressureTreated,
- type: 'fence',
- });
- formData[fenceEnum.width] = 0;
- formData[fenceEnum.width_unit] = formData[fenceEnum.width_unit]?.value;
- formData[fenceEnum.length_unit] = formData[fenceEnum.length_unit]?.value;
- delete formData[bufferZoneEnum.total_area_unit];
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.FENCE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.FENCE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.jsx b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.jsx
new file mode 100644
index 0000000000..29477bb00f
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Fence/index.jsx
@@ -0,0 +1,131 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import LineDetails from '../LineDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import Leaf from '../../../../assets/images/farmMapFilter/Leaf.svg';
+import { bufferZoneEnum, fenceEnum } from '../../../../containers/constants';
+import { Label } from '../../../Typography';
+import { line_length } from '../../../../util/convert-units/unit';
+import Unit from '../../../Form/Unit';
+import LocationButtons from '../../LocationButtons';
+
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import RadioGroup from '../../../Form/RadioGroup';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureFenceWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureFence({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const isPressureTreated = data[fenceEnum.pressure_treated];
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ pressure_treated: isPressureTreated,
+ type: 'fence',
+ });
+ formData[fenceEnum.width] = 0;
+ formData[fenceEnum.width_unit] = formData[fenceEnum.width_unit]?.value;
+ formData[fenceEnum.length_unit] = formData[fenceEnum.length_unit]?.value;
+ delete formData[bufferZoneEnum.total_area_unit];
+ submitForm({ formData });
+ };
+
+ return (
+
+ }
+ tabs={['tasks', 'details']}
+ />
+ );
+}
+
+export function FenceDetailsChildren({ system, isViewLocationPage }) {
+ const { t } = useTranslation();
+ const {
+ register,
+ setValue,
+ getValues,
+ watch,
+ control,
+ formState: { errors },
+ } = useFormContext();
+ return (
+
+
+
+
+
+
+
+ {t('FARM_MAP.FENCE.PRESSURE_TREATED')}
+
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/LineDetails.jsx b/packages/webapp/src/components/LocationDetailLayout/LineDetails/LineDetails.jsx
new file mode 100644
index 0000000000..90e10e5caf
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LineDetails/LineDetails.jsx
@@ -0,0 +1,72 @@
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import Input from '../../Form/Input';
+import { fenceEnum as lineEnum } from '../../../containers/constants';
+import PureWarningBox from '../../WarningBox';
+import { Label } from '../../Typography';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { useFormContext } from 'react-hook-form';
+
+export default function LineDetails({
+ name,
+ history,
+ children,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ setValue,
+ formState: { errors },
+ } = useFormContext();
+ const [errorMessage, setErrorMessage] = useState();
+
+ useEffect(() => {
+ const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
+ const handleOnline = () => setErrorMessage(null);
+ window.addEventListener('offline', handleOffline);
+ window.addEventListener('online', handleOnline);
+ return () => {
+ window.removeEventListener('offline', handleOffline);
+ window.removeEventListener('online', handleOnline);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (history?.location?.state?.error && !history?.location?.state?.error?.retire) {
+ setErrorMessage(history?.location?.state?.error);
+ }
+ }, [history?.location?.state?.error]);
+
+ return (
+ <>
+ {errorMessage && !isViewLocationPage && (
+
+ {errorMessage}
+
+ )}
+
+ {children}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.js b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.js
deleted file mode 100644
index 01b84c4576..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import LineDetails from '../index';
-import { useForm } from 'react-hook-form';
-import { Label } from '../../../Typography';
-import { area_total_area, line_length, line_width, watercourse_width } from '../../../../util/unit';
-import Unit from '../../../Form/Unit';
-import { watercourseEnum } from '../../../../containers/constants';
-import LocationButtons from '../../LocationButtons';
-
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import RadioGroup from '../../../Form/RadioGroup';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureWatercourseWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureWatercourse({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const unit = system === 'metric' ? 'm' : 'ft';
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
- const onSubmit = (data) => {
- const usedForIrrigation = data[watercourseEnum.used_for_irrigation];
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- type: 'watercourse',
- used_for_irrigation: usedForIrrigation,
- });
- formData[watercourseEnum.length_unit] = formData[watercourseEnum.length_unit]?.value;
- formData[watercourseEnum.width_unit] = formData[watercourseEnum.width_unit]?.value;
- formData[watercourseEnum.buffer_width_unit] =
- formData[watercourseEnum.buffer_width_unit]?.value;
- formData[watercourseEnum.total_area_unit] = formData[watercourseEnum.total_area_unit]?.value;
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.WATERCOURSE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.WATERCOURSE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.jsx b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.jsx
new file mode 100644
index 0000000000..b6d53cf0b0
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LineDetails/Watercourse/index.jsx
@@ -0,0 +1,195 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import LineDetails from '../LineDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import { Label } from '../../../Typography';
+import {
+ area_total_area,
+ line_length,
+ line_width,
+ watercourse_width,
+} from '../../../../util/convert-units/unit';
+import Unit from '../../../Form/Unit';
+import { watercourseEnum } from '../../../../containers/constants';
+import RadioGroup from '../../../Form/RadioGroup';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureWatercourseWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureWatercourse({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const usedForIrrigation = data[watercourseEnum.used_for_irrigation];
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ type: 'watercourse',
+ used_for_irrigation: usedForIrrigation,
+ });
+ formData[watercourseEnum.length_unit] = formData[watercourseEnum.length_unit]?.value;
+ formData[watercourseEnum.width_unit] = formData[watercourseEnum.width_unit]?.value;
+ formData[watercourseEnum.buffer_width_unit] =
+ formData[watercourseEnum.buffer_width_unit]?.value;
+ formData[watercourseEnum.total_area_unit] = formData[watercourseEnum.total_area_unit]?.value;
+ submitForm({ formData });
+ };
+
+ return (
+
+ }
+ tabs={['tasks', 'details']}
+ />
+ );
+}
+
+export function WatercourseDetailsChildren({ system, isViewLocationPage, isEditLocationPage }) {
+ const { t } = useTranslation();
+ const {
+ register,
+ setValue,
+ getValues,
+ watch,
+ control,
+ formState: { errors },
+ } = useFormContext();
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('FARM_MAP.WATERCOURSE.IRRIGATION')}
+
+
+ {t('common:OPTIONAL')}
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LineDetails/index.js b/packages/webapp/src/components/LocationDetailLayout/LineDetails/index.js
deleted file mode 100644
index 675320ab4e..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LineDetails/index.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import Input from '../../Form/Input';
-import { fenceEnum as lineEnum, fieldEnum as areaEnum } from '../../../containers/constants';
-import PureWarningBox from '../../WarningBox';
-import { Label } from '../../Typography';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export default function LineDetails({
- name,
- register,
- setValue,
- history,
- children,
- errors,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
-}) {
- const { t } = useTranslation();
- const [errorMessage, setErrorMessage] = useState();
-
- useEffect(() => {
- const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
- const handleOnline = () => setErrorMessage(null);
- window.addEventListener('offline', handleOffline);
- window.addEventListener('online', handleOnline);
- return () => {
- window.removeEventListener('offline', handleOffline);
- window.removeEventListener('online', handleOnline);
- };
- }, []);
-
- useEffect(() => {
- if (history?.location?.state?.error && !history?.location?.state?.error?.retire) {
- setErrorMessage(history?.location?.state?.error);
- }
- }, [history?.location?.state?.error]);
-
- return (
- <>
- {errorMessage && !isViewLocationPage && (
-
- {errorMessage}
-
- )}
-
- {children}
-
- >
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LocationButtons.js b/packages/webapp/src/components/LocationDetailLayout/LocationButtons.js
deleted file mode 100644
index d20f26d4d3..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LocationButtons.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import Button from '../Form/Button';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-
-export default function SubmitButton({
- disabled,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- onRetire,
- isAdmin,
- onEdit,
-}) {
- const { t } = useTranslation();
- return (
- <>
- {isCreateLocationPage && (
-
- {t('common:SAVE')}
-
- )}
- {isViewLocationPage && isAdmin && (
- <>
-
- {t('common:RETIRE')}
-
-
- {t('common:EDIT')}
-
- >
- )}
- {isEditLocationPage && (
-
- {t('common:UPDATE')}
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LocationButtons.jsx b/packages/webapp/src/components/LocationDetailLayout/LocationButtons.jsx
new file mode 100644
index 0000000000..6bf5455f44
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LocationButtons.jsx
@@ -0,0 +1,39 @@
+import Button from '../Form/Button';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+export default function SubmitButton({
+ disabled,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ onRetire,
+ isAdmin,
+ onEdit,
+}) {
+ const { t } = useTranslation();
+ return (
+ <>
+ {isCreateLocationPage && (
+
+ {t('common:SAVE')}
+
+ )}
+ {isViewLocationPage && isAdmin && (
+ <>
+
+ {t('common:RETIRE')}
+
+
+ {t('common:EDIT')}
+
+ >
+ )}
+ {isEditLocationPage && (
+
+ {t('common:UPDATE')}
+
+ )}
+ >
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.js b/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.js
deleted file mode 100644
index 98f8b0ecb3..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import PageTitle from '../PageTitle/v2';
-import React from 'react';
-import {
- setPosition,
- setPositionSelector,
- setZoomLevel,
- setZoomLevelSelector,
-} from '../../containers/mapSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import { useTranslation } from 'react-i18next';
-
-export default function LocationPageHeader({
- history,
- isCreateLocationPage,
- match,
- isViewLocationPage,
- isEditLocationPage,
- title,
- onCancel,
-}) {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const currentZoomLevel = useSelector(setZoomLevelSelector);
- const position = useSelector(setPositionSelector);
- const onGoBack = () => {
- dispatch(setZoomLevel(null));
- dispatch(setPosition(null));
- isCreateLocationPage &&
- history.replace({
- pathname: '/map',
- isStepBack: true,
- });
- isViewLocationPage &&
- history.replace({
- pathname: '/map',
- cameraInfo: { zoom: currentZoomLevel, location: position },
- });
- isEditLocationPage && history.goBack();
- };
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.jsx b/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.jsx
new file mode 100644
index 0000000000..84d20fb90d
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/LocationPageHeader.jsx
@@ -0,0 +1,42 @@
+import PageTitle from '../PageTitle/v2';
+import React from 'react';
+import {
+ setPosition,
+ setPositionSelector,
+ setZoomLevel,
+ setZoomLevelSelector,
+} from '../../containers/mapSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+
+export default function LocationPageHeader({
+ history,
+ isCreateLocationPage,
+ match,
+ isViewLocationPage,
+ isEditLocationPage,
+ title,
+ onCancel,
+}) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const currentZoomLevel = useSelector(setZoomLevelSelector);
+ const position = useSelector(setPositionSelector);
+ const onGoBack = () => {
+ dispatch(setZoomLevel(null));
+ dispatch(setPosition(null));
+ isCreateLocationPage && history.replace('/map', { isStepBack: true, hideLocationPin: true });
+ isViewLocationPage &&
+ history.replace('/map', { cameraInfo: { zoom: currentZoomLevel, location: position } });
+ isEditLocationPage && history.back();
+ };
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PersistedFormWrapper.js b/packages/webapp/src/components/LocationDetailLayout/PersistedFormWrapper.jsx
similarity index 100%
rename from packages/webapp/src/components/LocationDetailLayout/PersistedFormWrapper.js
rename to packages/webapp/src/components/LocationDetailLayout/PersistedFormWrapper.jsx
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.js b/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.js
deleted file mode 100644
index f67d39358a..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PointDetails from '../index';
-import { useForm } from 'react-hook-form';
-import LocationButtons from '../../LocationButtons';
-
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureGateWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureGate({
- history,
- match,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- submitForm,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const {
- handleSubmit,
- setValue,
- register,
- getValues,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const disabled = !isValid;
-
- const onError = (data) => {};
- const onSubmit = (data) => {
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- });
- submitForm({ formData });
- };
-
- const title =
- (isCreateLocationPage && t('FARM_MAP.GATE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.GATE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.jsx b/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.jsx
new file mode 100644
index 0000000000..5fae1ef897
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/PointDetails/Gate/index.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PointDetails from '../PointDetails';
+import { useForm } from 'react-hook-form';
+import LocationButtons from '../../LocationButtons';
+
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureGateWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureGate({
+ history,
+ match,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ submitForm,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ });
+ submitForm({ formData });
+ };
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/PointDetails.jsx b/packages/webapp/src/components/LocationDetailLayout/PointDetails/PointDetails.jsx
new file mode 100644
index 0000000000..928607fd5f
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/PointDetails/PointDetails.jsx
@@ -0,0 +1,72 @@
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import Input from '../../Form/Input';
+import { gateEnum as pointEnum } from '../../../containers/constants';
+import PureWarningBox from '../../WarningBox';
+import { Label } from '../../Typography';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { useFormContext } from 'react-hook-form';
+
+export default function PointDetails({
+ name,
+ children,
+ history,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+}) {
+ const { t } = useTranslation();
+ const {
+ register,
+ setValue,
+ formState: { errors },
+ } = useFormContext();
+ const [errorMessage, setErrorMessage] = useState();
+
+ useEffect(() => {
+ const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
+ const handleOnline = () => setErrorMessage(null);
+ window.addEventListener('offline', handleOffline);
+ window.addEventListener('online', handleOnline);
+ return () => {
+ window.removeEventListener('offline', handleOffline);
+ window.removeEventListener('online', handleOnline);
+ };
+ }, []);
+
+ useEffect(() => {
+ if (history?.location?.state?.error) {
+ setErrorMessage(history?.location?.state?.error);
+ }
+ }, [history?.location?.state?.error]);
+
+ return (
+ <>
+ {errorMessage && !isViewLocationPage && (
+
+ {errorMessage}
+
+ )}
+
+
+ {children}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.js b/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.js
deleted file mode 100644
index d42fb740ad..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.js
+++ /dev/null
@@ -1,163 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PointDetails from '../index';
-import { useForm } from 'react-hook-form';
-import Unit from '../../../Form/Unit';
-import { waterValveEnum } from '../../../../containers/constants';
-import { water_valve_flow_rate } from '../../../../util/unit';
-import { Label } from '../../../Typography';
-import LocationButtons from '../../LocationButtons';
-
-import Form from '../../../Form';
-import LocationPageHeader from '../../LocationPageHeader';
-import { PersistedFormWrapper } from '../../PersistedFormWrapper';
-import RadioGroup from '../../../Form/RadioGroup';
-import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
-
-export default function PureWaterValveWrapper(props) {
- return (
-
-
-
- );
-}
-export function PureWaterValve({
- history,
- match,
- submitForm,
- system,
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
- persistedFormData,
- useHookFormPersist,
- handleRetire,
- isAdmin,
-}) {
- const { t } = useTranslation();
-
- const {
- handleSubmit,
- setValue,
- register,
- watch,
- getValues,
- setError,
- control,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: { [waterValveEnum.source]: 'Municipal water', ...persistedFormData },
- });
-
- const { historyCancel } = useHookFormPersist?.(getValues) || {};
-
- const onError = (data) => {};
- const disabled = !isValid;
-
- const onSubmit = (data) => {
- const formData = getFormDataWithoutNulls({
- ...persistedFormData,
- ...data,
- });
- formData[waterValveEnum.flow_rate_unit] = formData[waterValveEnum.flow_rate_unit]?.value;
- submitForm({ formData });
- };
- const title =
- (isCreateLocationPage && t('FARM_MAP.WATER_VALVE.TITLE')) ||
- (isEditLocationPage && t('FARM_MAP.WATER_VALVE.EDIT_TITLE')) ||
- (isViewLocationPage && persistedFormData.name);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.jsx b/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.jsx
new file mode 100644
index 0000000000..5d339168b8
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/PointDetails/WaterValve/index.jsx
@@ -0,0 +1,127 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PointDetails from '../PointDetails';
+import { useForm, useFormContext } from 'react-hook-form';
+import Unit from '../../../Form/Unit';
+import { waterValveEnum } from '../../../../containers/constants';
+import { water_valve_flow_rate } from '../../../../util/convert-units/unit';
+import { Label } from '../../../Typography';
+import LocationButtons from '../../LocationButtons';
+
+import Form from '../../../Form';
+import LocationPageHeader from '../../LocationPageHeader';
+import { PersistedFormWrapper } from '../../PersistedFormWrapper';
+import RadioGroup from '../../../Form/RadioGroup';
+import { getFormDataWithoutNulls } from '../../../../containers/hooks/useHookFormPersist/utils';
+import { PureLocationDetailLayout } from '../../PureLocationDetailLayout';
+
+export default function PureWaterValveWrapper(props) {
+ return (
+
+
+
+ );
+}
+
+export function PureWaterValve({
+ history,
+ match,
+ submitForm,
+ system,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+}) {
+ const onSubmit = (data) => {
+ const formData = getFormDataWithoutNulls({
+ ...persistedFormData,
+ ...data,
+ });
+ formData[waterValveEnum.flow_rate_unit] = formData[waterValveEnum.flow_rate_unit]?.value;
+ submitForm({ formData });
+ };
+ return (
+
+ }
+ tabs={['tasks', 'details']}
+ />
+ );
+}
+
+export function WaterValveDetailsChildren({ isViewLocationPage, system }) {
+ const { t } = useTranslation();
+ const {
+ control,
+ register,
+ setValue,
+ getValues,
+ watch,
+ formState: { errors },
+ } = useFormContext();
+ return (
+
+ {t('FARM_MAP.WATER_VALVE.WATER_VALVE_TYPE')}
+
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PointDetails/index.js b/packages/webapp/src/components/LocationDetailLayout/PointDetails/index.js
deleted file mode 100644
index 6a7ccbb4b5..0000000000
--- a/packages/webapp/src/components/LocationDetailLayout/PointDetails/index.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import Input from '../../Form/Input';
-import { gateEnum as pointEnum } from '../../../containers/constants';
-import PureWarningBox from '../../WarningBox';
-import { Label } from '../../Typography';
-import InputAutoSize from '../../Form/InputAutoSize';
-
-export default function PointDetailsLayout({
- name,
-
- children,
- setValue,
-
- history,
-
- register,
- errors,
-
- isCreateLocationPage,
- isViewLocationPage,
- isEditLocationPage,
-}) {
- const { t } = useTranslation();
- const [errorMessage, setErrorMessage] = useState();
-
- useEffect(() => {
- const handleOffline = () => setErrorMessage(t('FARM_MAP.AREA_DETAILS.NETWORK'));
- const handleOnline = () => setErrorMessage(null);
- window.addEventListener('offline', handleOffline);
- window.addEventListener('online', handleOnline);
- return () => {
- window.removeEventListener('offline', handleOffline);
- window.removeEventListener('online', handleOnline);
- };
- }, []);
-
- useEffect(() => {
- if (history?.location?.state?.error) {
- setErrorMessage(history?.location?.state?.error);
- }
- }, [history?.location?.state?.error]);
-
- return (
- <>
- {errorMessage && !isViewLocationPage && (
-
- {errorMessage}
-
- )}
-
-
- {children}
-
- >
- );
-}
diff --git a/packages/webapp/src/components/LocationDetailLayout/PureLocationDetailLayout.jsx b/packages/webapp/src/components/LocationDetailLayout/PureLocationDetailLayout.jsx
new file mode 100644
index 0000000000..b39109c170
--- /dev/null
+++ b/packages/webapp/src/components/LocationDetailLayout/PureLocationDetailLayout.jsx
@@ -0,0 +1,134 @@
+import React, { useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import { useForm, FormProvider } from 'react-hook-form';
+import { Label } from '../Typography';
+import LocationButtons from './LocationButtons';
+import LocationPageHeader from './LocationPageHeader';
+import Form from '../Form';
+import AreaDetails from './AreaDetails/AreaDetails';
+import LineDetails from './LineDetails/LineDetails';
+import PointDetails from './PointDetails/PointDetails';
+import RouterTab from '../RouterTab';
+
+export function PureLocationDetailLayout({
+ history,
+ match,
+ system,
+ locationType,
+ locationCategory,
+ isCreateLocationPage,
+ isViewLocationPage,
+ isEditLocationPage,
+ persistedFormData,
+ useHookFormPersist,
+ handleRetire,
+ isAdmin,
+ onSubmit,
+ translationKey,
+ detailsChildren,
+ showPerimeter,
+ tabs,
+}) {
+ const { t } = useTranslation();
+ const formMethods = useForm({
+ mode: 'onChange',
+ shouldUnregister: true,
+ defaultValues: persistedFormData,
+ });
+ const historyCancel = () => {
+ history.push('/map', { hideLocationPin: true });
+ };
+
+ const onError = (data) => {};
+ const disabled = !formMethods.formState.isValid;
+
+ const title =
+ (isCreateLocationPage && t(`FARM_MAP.${translationKey}.TITLE`)) ||
+ (isEditLocationPage && t(`FARM_MAP.${translationKey}.EDIT_TITLE`)) ||
+ (isViewLocationPage && persistedFormData.name);
+
+ const routerTabs = tabs.map((tab) => ({
+ label: t(`FARM_MAP.TAB.${tab.toUpperCase()}`),
+ path: `/${locationType}/${match.params.location_id}/${tab}`,
+ }));
+
+ const details = useMemo(() => {
+ if (locationCategory === 'area') {
+ return (
+
+ {detailsChildren && detailsChildren}
+
+ );
+ } else if (locationCategory === 'line') {
+ return (
+
+ {detailsChildren && detailsChildren}
+
+ );
+ } else if (locationCategory === 'point') {
+ return (
+
+ {detailsChildren && detailsChildren}
+
+ );
+ }
+ }, [locationCategory]);
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/LocationPicker/SingleLocationPicker/PureMapLocationSelectionModal.js b/packages/webapp/src/components/LocationPicker/SingleLocationPicker/PureMapLocationSelectionModal.jsx
similarity index 100%
rename from packages/webapp/src/components/LocationPicker/SingleLocationPicker/PureMapLocationSelectionModal.js
rename to packages/webapp/src/components/LocationPicker/SingleLocationPicker/PureMapLocationSelectionModal.jsx
diff --git a/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.js b/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.js
deleted file mode 100644
index dcba08343a..0000000000
--- a/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.js
+++ /dev/null
@@ -1,313 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import ReactDOM from 'react-dom';
-import PropTypes from 'prop-types';
-import CustomZoom from '../../Map/CustomZoom';
-import CustomCompass from '../../Map/CustomCompass';
-import GoogleMap from 'google-map-react';
-import { DEFAULT_ZOOM, GMAPS_API_KEY, isPoint } from '../../../containers/Map/constants';
-import MapPin from '../../../assets/images/map/map_pin.svg';
-import {
- createMarkerClusters,
- DEFAULT_POLYGON_OPACITY,
- drawCropLocation,
- SELECTED_POLYGON_OPACITY,
-} from './drawLocations';
-import { usePropRef } from './usePropRef';
-import { getOverlappedAreaAndLines } from './getOverlappedAreaAndLines';
-import PureSelectionHandler from './PureMapLocationSelectionModal';
-import styles from './styles.module.scss';
-import { icons, selectedIcons } from '../../../containers/Map/mapStyles';
-
-const LocationPicker = ({
- onSelectLocation,
- clearLocations = onSelectLocation,
- selectedLocationIds,
- isPinMode,
- setPinCoordinate,
- pinCoordinate,
- locations,
- farmCenterCoordinate,
- style,
- readOnlyPinCoordinates,
- maxZoomRef,
- getMaxZoom,
-}) => {
- const [isGoogleMapInitiated, setGoogleMapInitiated] = useState(false);
- const geometriesRef = useRef({});
- const markerClusterRef = useRef();
-
- const onSelectLocationRef = usePropRef(onSelectLocation);
- const setPinCoordinateRef = usePropRef(setPinCoordinate);
- const clearLocationsRef = usePropRef(clearLocations);
-
- const pinMarkerRef = useRef();
- useEffect(() => {
- if (pinMarkerRef.current) {
- pinMarkerRef.current.isPinMode = isPinMode;
- pinMarkerRef.current.setOptions({ visible: !!isPinMode && !!pinCoordinate });
- pinCoordinate && pinMarkerRef.current.setOptions({ position: pinCoordinate });
- !isPinMode && setPinCoordinate?.(null);
- }
- for (const location_id in geometriesRef.current) {
- const { polygon } = geometriesRef.current[location_id];
- polygon?.setOptions({ clickable: !isPinMode });
- }
- overlappedPositions.length && dismissSelectionModal();
- }, [isPinMode, isGoogleMapInitiated]);
-
- const prevSelectedLocationIdsRef = useRef([]);
- useEffect(() => {
- for (const location_id of selectedLocationIds) {
- if (
- geometriesRef.current[location_id] &&
- !prevSelectedLocationIdsRef.current?.includes(location_id)
- ) {
- setSelectedGeometryStyle(geometriesRef.current[location_id]);
- }
- }
- for (const location_id of prevSelectedLocationIdsRef.current) {
- if (geometriesRef.current[location_id] && !selectedLocationIds?.includes(location_id)) {
- resetGeometryStyle(geometriesRef.current[location_id]);
- }
- }
- prevSelectedLocationIdsRef.current = selectedLocationIds;
- }, [selectedLocationIds, isGoogleMapInitiated]);
-
- const [overlappedPositions, setOverlappedPositions] = useState([]);
-
- function areaOnClick(latLng, maps) {
- const overlappedLocations = getOverlappedAreaAndLines(
- latLng,
- Object.values(geometriesRef.current),
- maps,
- );
- if (overlappedLocations.length > 1) {
- setOverlappedPositions(overlappedLocations);
- } else if (overlappedLocations.length === 1) {
- onSelectLocationRef.current(overlappedLocations[0].location_id);
- }
- }
-
- function mapOnClick(latLng, maps) {
- if (pinMarkerRef.current?.isPinMode) {
- pinMarkerRef.current?.setOptions({ position: latLng, visible: true });
- setPinCoordinateRef.current?.(latLng.toJSON());
- clearLocationsRef.current();
- }
- }
-
- const dismissSelectionModal = () => setOverlappedPositions([]);
- const onSelectionModalClick = (location_id) => {
- onSelectLocationRef.current(location_id);
- dismissSelectionModal();
- };
-
- const drawWildCropPins = (map, maps, mapBounds) => {
- for (const pinCoordinate of readOnlyPinCoordinates || []) {
- new maps.Marker({
- icon: MapPin,
- position: pinCoordinate,
- map: map,
- });
- mapBounds.extend(pinCoordinate);
- }
- };
-
- const drawLocations = (map, maps, mapBounds) => {
- locations.forEach((location) => {
- const assetGeometry = drawCropLocation(map, maps, mapBounds, location);
- geometriesRef.current[assetGeometry.location.location_id] = assetGeometry;
- if (selectedLocationIds.includes(assetGeometry.location.location_id)) {
- setSelectedGeometryStyle(assetGeometry);
- }
- if (isPoint(assetGeometry.location.type)) {
- maps.event.addListener(assetGeometry.marker, 'click', (e) =>
- onSelectLocationRef.current(assetGeometry.location.location_id),
- );
- } else {
- maps.event.addListener(assetGeometry.polygon, 'click', (e) => areaOnClick(e.latLng, maps));
- }
- });
- markerClusterRef.current = createMarkerClusters(
- maps,
- map,
- Object.values(geometriesRef.current).filter(({ location: { type } }) => isPoint(type)),
- );
- maps.event.addListener(markerClusterRef.current, 'click', (cluster) => {
- if (map.getZoom() >= (maxZoomRef?.current || 20) && cluster.markers_.length > 1) {
- setOverlappedPositions(
- cluster.markers_.map((marker) => ({
- location_id: marker.location_id,
- name: marker.name,
- type: marker.type,
- })),
- );
- }
- });
- markerClusterRef.current.setCalculator(function (markers, numStyles) {
- const isSelected = !!markers.find(({ location_id }) =>
- prevSelectedLocationIdsRef.current.includes(location_id),
- );
- return {
- text: markers.length,
- index: isSelected ? 2 : 1,
- };
- });
- };
-
- const setSelectedGeometryStyle = (assetGeometry) => {
- if (isPoint(assetGeometry.location.type)) {
- assetGeometry?.marker?.setOptions({ icon: selectedIcons[assetGeometry.location.type] });
- } else {
- assetGeometry?.marker?.setOptions({
- label: { ...(assetGeometry?.marker?.label || {}), color: 'black' },
- });
- assetGeometry.polygon.setOptions({
- fillColor: assetGeometry.styles.selectedColour || 'white',
- fillOpacity: SELECTED_POLYGON_OPACITY,
- });
- }
- };
-
- const resetGeometryStyle = (assetGeometry) => {
- if (isPoint(assetGeometry.location.type)) {
- assetGeometry?.marker?.setOptions({ icon: icons[assetGeometry.location.type] });
- } else {
- assetGeometry?.marker?.setOptions({
- label: { ...(assetGeometry?.marker?.label || {}), color: 'white' },
- });
- assetGeometry?.polygon?.setOptions({
- fillColor: assetGeometry.styles.colour,
- fillOpacity: DEFAULT_POLYGON_OPACITY,
- });
- }
- };
-
- const getMapOptions = (maps) => {
- return {
- styles: [
- {
- featureType: 'poi.business',
- elementType: 'labels',
- stylers: [
- {
- visibility: 'off',
- },
- ],
- },
- ],
- gestureHandling: 'greedy',
- disableDoubleClickZoom: false,
- minZoom: 1,
- maxZoom: 80,
- tilt: 0,
- mapTypeId: maps.MapTypeId.SATELLITE,
- mapTypeControlOptions: {
- style: maps.MapTypeControlStyle.HORIZONTAL_BAR,
- position: maps.ControlPosition.BOTTOM_CENTER,
- mapTypeIds: [maps.MapTypeId.ROADMAP, maps.MapTypeId.SATELLITE],
- },
- clickableIcons: false,
- streetViewControl: false,
- scaleControl: false,
- mapTypeControl: false,
- panControl: false,
- zoomControl: false,
- rotateControl: false,
- fullscreenControl: false,
- };
- };
-
- const handleGoogleMapApi = (map, maps) => {
- getMaxZoom?.(maps);
- const mapBounds = new maps.LatLngBounds();
- mapBounds.extend(farmCenterCoordinate);
- pinMarkerRef.current = new maps.Marker({
- icon: MapPin,
- position: pinCoordinate || farmCenterCoordinate,
- map: map,
- visible: !!pinCoordinate,
- isPinMode,
- });
- pinCoordinate && mapBounds.extend(pinCoordinate);
- map.addListener('click', (e) => {
- mapOnClick(e.latLng, maps);
- });
-
- //TODO: move to mapUtil.polygonGetAveragePoint
- maps.Polygon.prototype.getAveragePoint = function () {
- const latLngArray = this.getPath().getArray();
- const { latSum, lngSum } = latLngArray.reduce(
- (latLngSum, latLng) => {
- latLngSum.latSum += latLng.lat();
- latLngSum.lngSum += latLng.lng();
- return latLngSum;
- },
- { latSum: 0, lngSum: 0 },
- );
- return new maps.LatLng(latSum / latLngArray.length, lngSum / latLngArray.length);
- };
-
- const zoomControlDiv = document.createElement('div');
- ReactDOM.render(
- map.setZoom(map.getZoom() + 1)}
- onClickZoomOut={() => map.setZoom(map.getZoom() - 1)}
- />,
- zoomControlDiv,
- );
- map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(zoomControlDiv);
-
- const compassControlDiv = document.createElement('div');
- ReactDOM.render( , compassControlDiv);
- map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(compassControlDiv);
-
- // Drawing locations on map
- drawWildCropPins(map, maps, mapBounds);
- drawLocations(map, maps, mapBounds);
- map.fitBounds(mapBounds);
-
- setGoogleMapInitiated(true);
- };
-
- return (
-
-
handleGoogleMapApi(map, maps)}
- options={getMapOptions}
- />
- {overlappedPositions.length > 1 && !isPinMode && (
-
- )}
-
- );
-};
-
-LocationPicker.prototype = {
- className: PropTypes.string,
- setSelectedLocation: PropTypes.object,
- selectedLocationIds: PropTypes.arrayOf(PropTypes.string),
- farmCenterCoordinate: PropTypes.object,
- readOnlyPinCoordinates: PropTypes.arrayOf(
- PropTypes.shape({ lat: PropTypes.number, lng: PropTypes.number }),
- ),
- maxZoomRef: PropTypes.object,
- getMaxZoom: PropTypes.func,
-};
-
-export default LocationPicker;
diff --git a/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.jsx b/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.jsx
new file mode 100644
index 0000000000..6728b44ecf
--- /dev/null
+++ b/packages/webapp/src/components/LocationPicker/SingleLocationPicker/index.jsx
@@ -0,0 +1,320 @@
+import React, { useEffect, useRef, useState } from 'react';
+import ReactDOM from 'react-dom';
+import PropTypes from 'prop-types';
+import CustomZoom from '../../Map/CustomZoom';
+import CustomCompass from '../../Map/CustomCompass';
+import GoogleMap from 'google-map-react';
+import { DEFAULT_ZOOM, GMAPS_API_KEY, isPoint } from '../../../containers/Map/constants';
+import MapPin from '../../../assets/images/map/map_pin.svg';
+import {
+ createMarkerClusters,
+ DEFAULT_POLYGON_OPACITY,
+ drawCropLocation,
+ SELECTED_POLYGON_OPACITY,
+} from './drawLocations';
+import { usePropRef } from './usePropRef';
+import { getOverlappedAreaAndLines } from './getOverlappedAreaAndLines';
+import PureSelectionHandler from './PureMapLocationSelectionModal';
+import styles from './styles.module.scss';
+import { icons, selectedIcons } from '../../../containers/Map/mapStyles';
+
+const LocationPicker = ({
+ onSelectLocation,
+ clearLocations = onSelectLocation,
+ selectedLocationIds,
+ isPinMode,
+ setPinCoordinate,
+ pinCoordinate,
+ locations,
+ farmCenterCoordinate,
+ style,
+ readOnlyPinCoordinates,
+ maxZoomRef,
+ getMaxZoom,
+}) => {
+ const [isGoogleMapInitiated, setGoogleMapInitiated] = useState(false);
+ const geometriesRef = useRef({});
+ const markerClusterRef = useRef();
+ const mapRef = useRef();
+
+ const onSelectLocationRef = usePropRef(onSelectLocation);
+ const setPinCoordinateRef = usePropRef(setPinCoordinate);
+ const clearLocationsRef = usePropRef(clearLocations);
+
+ const pinMarkerRef = useRef();
+ useEffect(() => {
+ if (pinMarkerRef.current) {
+ pinMarkerRef.current.isPinMode = isPinMode;
+ pinMarkerRef.current.setOptions({ visible: !!isPinMode && !!pinCoordinate });
+ pinCoordinate && pinMarkerRef.current.setOptions({ position: pinCoordinate });
+ !isPinMode && setPinCoordinate?.(null);
+ }
+ for (const location_id in geometriesRef.current) {
+ const { polygon } = geometriesRef.current[location_id];
+ polygon?.setOptions({ clickable: !isPinMode });
+ }
+ overlappedPositions.length && dismissSelectionModal();
+ if (mapRef.current) {
+ mapRef.current.setOptions({
+ draggableCursor: isPinMode ? 'crosshair' : '',
+ });
+ }
+ }, [isPinMode, isGoogleMapInitiated]);
+
+ const prevSelectedLocationIdsRef = useRef([]);
+ useEffect(() => {
+ for (const location_id of selectedLocationIds) {
+ if (
+ geometriesRef.current[location_id] &&
+ !prevSelectedLocationIdsRef.current?.includes(location_id)
+ ) {
+ setSelectedGeometryStyle(geometriesRef.current[location_id]);
+ }
+ }
+ for (const location_id of prevSelectedLocationIdsRef.current) {
+ if (geometriesRef.current[location_id] && !selectedLocationIds?.includes(location_id)) {
+ resetGeometryStyle(geometriesRef.current[location_id]);
+ }
+ }
+ prevSelectedLocationIdsRef.current = selectedLocationIds;
+ }, [selectedLocationIds, isGoogleMapInitiated]);
+
+ const [overlappedPositions, setOverlappedPositions] = useState([]);
+
+ function areaOnClick(latLng, maps) {
+ const overlappedLocations = getOverlappedAreaAndLines(
+ latLng,
+ Object.values(geometriesRef.current),
+ maps,
+ );
+ if (overlappedLocations.length > 1) {
+ setOverlappedPositions(overlappedLocations);
+ } else if (overlappedLocations.length === 1) {
+ onSelectLocationRef.current(overlappedLocations[0].location_id);
+ }
+ }
+
+ function mapOnClick(latLng, maps) {
+ if (pinMarkerRef.current?.isPinMode) {
+ pinMarkerRef.current?.setOptions({ position: latLng, visible: true });
+ setPinCoordinateRef.current?.(latLng.toJSON());
+ clearLocationsRef.current();
+ }
+ }
+
+ const dismissSelectionModal = () => setOverlappedPositions([]);
+ const onSelectionModalClick = (location_id) => {
+ onSelectLocationRef.current(location_id);
+ dismissSelectionModal();
+ };
+
+ const drawWildCropPins = (map, maps, mapBounds) => {
+ for (const pinCoordinate of readOnlyPinCoordinates || []) {
+ new maps.Marker({
+ icon: MapPin,
+ position: pinCoordinate,
+ map: map,
+ });
+ mapBounds.extend(pinCoordinate);
+ }
+ };
+
+ const drawLocations = (map, maps, mapBounds) => {
+ locations.forEach((location) => {
+ const assetGeometry = drawCropLocation(map, maps, mapBounds, location);
+ geometriesRef.current[assetGeometry.location.location_id] = assetGeometry;
+ if (selectedLocationIds.includes(assetGeometry.location.location_id)) {
+ setSelectedGeometryStyle(assetGeometry);
+ }
+ if (isPoint(assetGeometry.location.type)) {
+ maps.event.addListener(assetGeometry.marker, 'click', (e) =>
+ onSelectLocationRef.current(assetGeometry.location.location_id),
+ );
+ } else {
+ maps.event.addListener(assetGeometry.polygon, 'click', (e) => areaOnClick(e.latLng, maps));
+ }
+ });
+ markerClusterRef.current = createMarkerClusters(
+ maps,
+ map,
+ Object.values(geometriesRef.current).filter(({ location: { type } }) => isPoint(type)),
+ );
+ maps.event.addListener(markerClusterRef.current, 'click', (cluster) => {
+ if (map.getZoom() >= (maxZoomRef?.current || 20) && cluster.markers_.length > 1) {
+ setOverlappedPositions(
+ cluster.markers_.map((marker) => ({
+ location_id: marker.location_id,
+ name: marker.name,
+ type: marker.type,
+ })),
+ );
+ }
+ });
+ markerClusterRef.current.setCalculator(function (markers, numStyles) {
+ const isSelected = !!markers.find(({ location_id }) =>
+ prevSelectedLocationIdsRef.current.includes(location_id),
+ );
+ return {
+ text: markers.length,
+ index: isSelected ? 2 : 1,
+ };
+ });
+ };
+
+ const setSelectedGeometryStyle = (assetGeometry) => {
+ if (isPoint(assetGeometry.location.type)) {
+ assetGeometry?.marker?.setOptions({ icon: selectedIcons[assetGeometry.location.type] });
+ } else {
+ assetGeometry?.marker?.setOptions({
+ label: { ...(assetGeometry?.marker?.label || {}), color: 'black' },
+ });
+ assetGeometry.polygon.setOptions({
+ fillColor: assetGeometry.styles.selectedColour || 'white',
+ fillOpacity: SELECTED_POLYGON_OPACITY,
+ });
+ }
+ };
+
+ const resetGeometryStyle = (assetGeometry) => {
+ if (isPoint(assetGeometry.location.type)) {
+ assetGeometry?.marker?.setOptions({ icon: icons[assetGeometry.location.type] });
+ } else {
+ assetGeometry?.marker?.setOptions({
+ label: { ...(assetGeometry?.marker?.label || {}), color: 'white' },
+ });
+ assetGeometry?.polygon?.setOptions({
+ fillColor: assetGeometry.styles.colour,
+ fillOpacity: DEFAULT_POLYGON_OPACITY,
+ });
+ }
+ };
+
+ const getMapOptions = (maps) => {
+ return {
+ styles: [
+ {
+ featureType: 'poi.business',
+ elementType: 'labels',
+ stylers: [
+ {
+ visibility: 'off',
+ },
+ ],
+ },
+ ],
+ gestureHandling: 'greedy',
+ disableDoubleClickZoom: false,
+ minZoom: 1,
+ maxZoom: 80,
+ tilt: 0,
+ mapTypeId: maps.MapTypeId.SATELLITE,
+ mapTypeControlOptions: {
+ style: maps.MapTypeControlStyle.HORIZONTAL_BAR,
+ position: maps.ControlPosition.BOTTOM_CENTER,
+ mapTypeIds: [maps.MapTypeId.ROADMAP, maps.MapTypeId.SATELLITE],
+ },
+ clickableIcons: false,
+ streetViewControl: false,
+ scaleControl: false,
+ mapTypeControl: false,
+ panControl: false,
+ zoomControl: false,
+ rotateControl: false,
+ fullscreenControl: false,
+ };
+ };
+
+ const handleGoogleMapApi = (map, maps) => {
+ mapRef.current = map;
+ getMaxZoom?.(maps);
+ const mapBounds = new maps.LatLngBounds();
+ mapBounds.extend(farmCenterCoordinate);
+ pinMarkerRef.current = new maps.Marker({
+ icon: MapPin,
+ position: pinCoordinate || farmCenterCoordinate,
+ map: map,
+ visible: !!pinCoordinate,
+ isPinMode,
+ });
+ pinCoordinate && mapBounds.extend(pinCoordinate);
+ map.addListener('click', (e) => {
+ mapOnClick(e.latLng, maps);
+ });
+
+ //TODO: move to mapUtil.polygonGetAveragePoint
+ maps.Polygon.prototype.getAveragePoint = function () {
+ const latLngArray = this.getPath().getArray();
+ const { latSum, lngSum } = latLngArray.reduce(
+ (latLngSum, latLng) => {
+ latLngSum.latSum += latLng.lat();
+ latLngSum.lngSum += latLng.lng();
+ return latLngSum;
+ },
+ { latSum: 0, lngSum: 0 },
+ );
+ return new maps.LatLng(latSum / latLngArray.length, lngSum / latLngArray.length);
+ };
+
+ const zoomControlDiv = document.createElement('div');
+ ReactDOM.render(
+ map.setZoom(map.getZoom() + 1)}
+ onClickZoomOut={() => map.setZoom(map.getZoom() - 1)}
+ />,
+ zoomControlDiv,
+ );
+ map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(zoomControlDiv);
+
+ const compassControlDiv = document.createElement('div');
+ ReactDOM.render( , compassControlDiv);
+ map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(compassControlDiv);
+
+ // Drawing locations on map
+ drawWildCropPins(map, maps, mapBounds);
+ drawLocations(map, maps, mapBounds);
+ map.fitBounds(mapBounds);
+
+ setGoogleMapInitiated(true);
+ };
+
+ return (
+
+
handleGoogleMapApi(map, maps)}
+ options={getMapOptions}
+ />
+ {overlappedPositions.length > 1 && !isPinMode && (
+
+ )}
+
+ );
+};
+
+LocationPicker.prototype = {
+ className: PropTypes.string,
+ setSelectedLocation: PropTypes.object,
+ selectedLocationIds: PropTypes.arrayOf(PropTypes.string),
+ farmCenterCoordinate: PropTypes.object,
+ readOnlyPinCoordinates: PropTypes.arrayOf(
+ PropTypes.shape({ lat: PropTypes.number, lng: PropTypes.number }),
+ ),
+ maxZoomRef: PropTypes.object,
+ getMaxZoom: PropTypes.func,
+};
+
+export default LocationPicker;
diff --git a/packages/webapp/src/components/LocationTasks/index.jsx b/packages/webapp/src/components/LocationTasks/index.jsx
new file mode 100644
index 0000000000..4fef484089
--- /dev/null
+++ b/packages/webapp/src/components/LocationTasks/index.jsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import Layout from '../Layout';
+import PageTitle from '../PageTitle/v2';
+import RouterTab from '../RouterTab';
+import { useTranslation } from 'react-i18next';
+import { Semibold } from '../Typography';
+import TaskCount from '../Task/TaskCount';
+import TaskCard from '../../containers/Task/TaskCard';
+import PageBreak from '../PageBreak';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+import { onAddTask } from '../../containers/Task/onAddTask';
+import { useDispatch } from 'react-redux';
+
+export default function PureLocationTasks({ location, history, match, hasCrops, tasks, count }) {
+ const language = getLanguageFromLocalStorage();
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const renderTasksForDay = (dateString, tasksForDate) => (
+ <>
+
+ {tasksForDate.map((t) => (
+ history.push(`/tasks/${t.task_id}/read_only`)}
+ style={{ marginBottom: '14px' }}
+ {...t}
+ />
+ ))}
+ >
+ );
+
+ const renderTasksByDay = (tasks) => {
+ return Object.keys(tasks)
+ .sort((a, b) => {
+ const dateA = Date.parse(a);
+ const dateB = Date.parse(b);
+ if (dateA < dateB) {
+ return -1;
+ } else if (dateB > dateA) {
+ return 1;
+ } else {
+ return 0;
+ }
+ })
+ .map((key) => renderTasksForDay(key, tasks[key]));
+ };
+
+ const routerTabs = hasCrops
+ ? [
+ {
+ label: t('FARM_MAP.TAB.CROPS'),
+ path: match.url.replace('tasks', 'crops'),
+ },
+ {
+ label: t('FARM_MAP.TAB.TASKS'),
+ path: match.url,
+ },
+ {
+ label: t('FARM_MAP.TAB.DETAILS'),
+ path: match.url.replace('tasks', 'details'),
+ },
+ ]
+ : [
+ {
+ label: t('FARM_MAP.TAB.TASKS'),
+ path: match.url,
+ },
+ {
+ label: t('FARM_MAP.TAB.DETAILS'),
+ path: match.url.replace('tasks', 'details'),
+ },
+ ];
+
+ return (
+
+ history.push('/map')} />
+
+
+ {count > 0 ? (
+ renderTasksByDay(tasks)
+ ) : (
+ {t('TASK.NO_TASKS_TO_DISPLAY')}
+ )}
+
+ );
+}
diff --git a/packages/webapp/src/components/LogFooter/index.js b/packages/webapp/src/components/LogFooter/index.jsx
similarity index 100%
rename from packages/webapp/src/components/LogFooter/index.js
rename to packages/webapp/src/components/LogFooter/index.jsx
diff --git a/packages/webapp/src/components/Logs/HarvestAllocation/index.js b/packages/webapp/src/components/Logs/HarvestAllocation/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Logs/HarvestAllocation/index.js
rename to packages/webapp/src/components/Logs/HarvestAllocation/index.jsx
diff --git a/packages/webapp/src/components/Logs/HarvestLog/index.js b/packages/webapp/src/components/Logs/HarvestLog/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Logs/HarvestLog/index.js
rename to packages/webapp/src/components/Logs/HarvestLog/index.jsx
diff --git a/packages/webapp/src/components/Logs/HarvestUseType/index.js b/packages/webapp/src/components/Logs/HarvestUseType/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Logs/HarvestUseType/index.js
rename to packages/webapp/src/components/Logs/HarvestUseType/index.jsx
diff --git a/packages/webapp/src/components/Logs/PureAddHarvestUse/index.js b/packages/webapp/src/components/Logs/PureAddHarvestUse/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Logs/PureAddHarvestUse/index.js
rename to packages/webapp/src/components/Logs/PureAddHarvestUse/index.jsx
diff --git a/packages/webapp/src/components/Map/CustomCompass/index.js b/packages/webapp/src/components/Map/CustomCompass/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/CustomCompass/index.js
rename to packages/webapp/src/components/Map/CustomCompass/index.jsx
diff --git a/packages/webapp/src/components/Map/CustomZoom/index.js b/packages/webapp/src/components/Map/CustomZoom/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/CustomZoom/index.js
rename to packages/webapp/src/components/Map/CustomZoom/index.jsx
diff --git a/packages/webapp/src/components/Map/DrawingManager/index.js b/packages/webapp/src/components/Map/DrawingManager/index.js
deleted file mode 100644
index 2303a9c2a5..0000000000
--- a/packages/webapp/src/components/Map/DrawingManager/index.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import { ReactComponent as BackIcon } from '../../../assets/images/map/back.svg';
-import clsx from 'clsx';
-import PureWarningBox from '../../WarningBox';
-import Button from '../../Form/Button';
-import { Label } from '../../Typography';
-import PureLineBox from '../LineMapBoxes';
-import { watercourseEnum } from '../../../containers/constants';
-
-export default function PureDrawingManager({
- className,
- style,
- isDrawing,
- drawingType,
- onClickBack,
- onClickTryAgain,
- onClickConfirm,
- showZeroAreaWarning,
- showLineModal,
- confirmLine,
- updateLineWidth,
- system,
- typeOfLine,
- lineData,
-}) {
- const { t } = useTranslation();
- const showConfirmButtons = !showZeroAreaWarning && !showLineModal && !isDrawing;
- // ASSUMING AREA CANNOT IMPLEMENT UNDO (reset drawing)
- return (
-
- {!showLineModal && (
-
-
-
- )}
- {!isDrawing && (
- <>
- {showZeroAreaWarning && (
-
-
- {t('FARM_MAP.DRAWING_MANAGER.ZERO_AREA_DETECTED')}
-
-
- {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
-
-
- )}
- {showLineModal && lineData?.hasOwnProperty(watercourseEnum.width) && (
- <>
-
- >
- )}
- >
- )}
- {showConfirmButtons && (
-
-
- {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
-
-
- {t('common:CONFIRM')}
-
-
- )}
- {!showLineModal &&
}
-
- );
-}
-
-PureDrawingManager.prototype = {
- className: PropTypes.string,
- style: PropTypes.object,
- farmName: PropTypes.string,
- showVideo: PropTypes.func,
- showZeroAreaWarning: PropTypes.bool,
- showLineModal: PropTypes.bool,
- confirmLine: PropTypes.func,
- updateLineWidth: PropTypes.func,
- system: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/Map/DrawingManager/index.jsx b/packages/webapp/src/components/Map/DrawingManager/index.jsx
new file mode 100644
index 0000000000..903e41a223
--- /dev/null
+++ b/packages/webapp/src/components/Map/DrawingManager/index.jsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import { ReactComponent as BackIcon } from '../../../assets/images/map/back.svg';
+import clsx from 'clsx';
+import PureWarningBox from '../../WarningBox';
+import Button from '../../Form/Button';
+import { Label } from '../../Typography';
+import PureLineBox from '../LineMapBoxes';
+import { watercourseEnum } from '../../../containers/constants';
+
+export default function PureDrawingManager({
+ className,
+ style,
+ isDrawing,
+ drawingType,
+ onClickBack,
+ onClickTryAgain,
+ onClickConfirm,
+ showZeroAreaWarning,
+ showLineModal,
+ confirmLine,
+ updateLineWidth,
+ system,
+ typeOfLine,
+ lineData,
+}) {
+ const { t } = useTranslation();
+ const showConfirmButtons = !showZeroAreaWarning && !showLineModal && !isDrawing;
+ // ASSUMING AREA CANNOT IMPLEMENT UNDO (reset drawing)
+ return (
+
+ {!showLineModal && (
+
+
+
+ )}
+ {!isDrawing && (
+ <>
+ {showZeroAreaWarning && (
+
+
+ {t('FARM_MAP.DRAWING_MANAGER.ZERO_AREA_DETECTED')}
+
+
+ {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
+
+
+ )}
+ {showLineModal && lineData?.hasOwnProperty(watercourseEnum.width) && (
+ <>
+
+ >
+ )}
+ >
+ )}
+ {showConfirmButtons && (
+
+
+ {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
+
+
+ {t('common:CONFIRM')}
+
+
+ )}
+ {!showLineModal &&
}
+
+ );
+}
+
+PureDrawingManager.prototype = {
+ className: PropTypes.string,
+ style: PropTypes.object,
+ farmName: PropTypes.string,
+ showVideo: PropTypes.func,
+ showZeroAreaWarning: PropTypes.bool,
+ showLineModal: PropTypes.bool,
+ confirmLine: PropTypes.func,
+ updateLineWidth: PropTypes.func,
+ system: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Map/Footer/index.js b/packages/webapp/src/components/Map/Footer/index.js
deleted file mode 100644
index db37757b84..0000000000
--- a/packages/webapp/src/components/Map/Footer/index.js
+++ /dev/null
@@ -1,263 +0,0 @@
-import React, { useState } from 'react';
-import Joyride, { ACTIONS, LIFECYCLE } from 'react-joyride';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import { ReactComponent as AddLogo } from '../../../assets/images/map/add.svg';
-import { ReactComponent as FilterLogo } from '../../../assets/images/map/filter.svg';
-import { ReactComponent as ExportLogo } from '../../../assets/images/map/export.svg';
-import clsx from 'clsx';
-import { useTranslation } from 'react-i18next';
-import MapDrawer from '../../MapDrawer';
-import { locationEnum } from '../../../containers/Map/constants';
-
-export default function PureMapFooter({
- className,
- style,
- isAdmin,
- showSpotlight,
- resetSpotlight,
- onClickAdd,
- onClickExport,
- handleClickFilter,
- showModal,
- setShowMapFilter,
- showMapFilter,
- setShowAddDrawer,
- showAddDrawer,
- drawerDefaultHeight,
- filterSettings,
- onFilterMenuClick,
- onAddMenuClick,
- availableFilterSettings = {
- area: [
- locationEnum.barn,
- locationEnum.ceremonial_area,
- locationEnum.farm_site_boundary,
- locationEnum.field,
- locationEnum.garden,
- locationEnum.greenhouse,
- locationEnum.surface_water,
- locationEnum.natural_area,
- locationEnum.residence,
- ],
- line: [locationEnum.buffer_zone, locationEnum.watercourse, locationEnum.fence],
- point: [locationEnum.gate, locationEnum.water_valve],
- },
-}) {
- const { t } = useTranslation();
- const [stepSpotlighted, setStepSpotlighted] = useState(null);
-
- const resetSpotlightStatus = (data) => {
- const { action, status, lifecycle } = data;
- const CLICK_OUT = action === ACTIONS.CLOSE && lifecycle === LIFECYCLE.COMPLETE;
- const FINISH = action === ACTIONS.NEXT && lifecycle === LIFECYCLE.INIT;
- if (CLICK_OUT || FINISH) {
- setStepSpotlighted(null);
- resetSpotlight();
- } else if ([ACTIONS.UPDATE].includes(action) && lifecycle === LIFECYCLE.TOOLTIP) {
- setStepSpotlighted(data.index);
- }
- };
- const steps = [
- {
- target: '#mapFirstStep',
- title: TitleContent(t('FARM_MAP.SPOTLIGHT.ADD_TITLE')),
- content: BodyContent(t('FARM_MAP.SPOTLIGHT.ADD')),
- locale: {
- next: NextButtonContent(t('common:NEXT')),
- },
- showCloseButton: false,
- disableBeacon: true,
- placement: 'top-start',
- styles: {
- options: {
- width: 240,
- },
- },
- },
- {
- target: '#mapSecondStep',
- title: TitleContent(t('FARM_MAP.SPOTLIGHT.FILTER_TITLE')),
- content: BodyContent(t('FARM_MAP.SPOTLIGHT.FILTER')),
- locale: {
- next: NextButtonContent(t('common:NEXT')),
- },
- showCloseButton: false,
- placement: 'top-start',
- styles: {
- options: {
- width: 260,
- },
- },
- },
- {
- target: '#mapThirdStep',
- title: TitleContent(t('FARM_MAP.SPOTLIGHT.EXPORT_TITLE')),
- content: BodyContent(t('FARM_MAP.SPOTLIGHT.EXPORT')),
- locale: {
- last: NextButtonContent(t('common:GOT_IT')),
- },
- placement: 'top-start',
- showCloseButton: false,
- styles: {
- options: {
- width: 240,
- },
- },
- },
- ];
-
- const { container, button, svg, spotlighted } = styles;
- return (
- <>
- {showSpotlight && (
- //Deprecated
-
- )}
-
- {isAdmin && (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
- >
- );
-}
-
-PureMapFooter.prototype = {
- className: PropTypes.string,
- style: PropTypes.object,
- isAdmin: PropTypes.bool,
- showSpotlight: PropTypes.bool,
- resetSpotlight: PropTypes.func,
- onClickAdd: PropTypes.func,
- onClickFilter: PropTypes.func,
- onClickExport: PropTypes.func,
- showModal: PropTypes.bool,
- setShowMapFilter: PropTypes.func,
- showMapFilter: PropTypes.bool,
- drawerDefaultHeight: PropTypes.number,
- filterSettings: PropTypes.func,
- onFilterMenuClick: PropTypes.func,
- onAddMenuClick: PropTypes.func,
- setShowAddDrawer: PropTypes.func,
- availableFilterSettings: PropTypes.shape({
- area: PropTypes.array,
- point: PropTypes.array,
- line: PropTypes.array,
- }),
-};
-
-const TitleContent = (text) => {
- return (
-
- {text}
-
- );
-};
-
-const BodyContent = (text) => {
- const { t } = useTranslation();
- return (
- <>
-
- {t('FARM_MAP.SPOTLIGHT.HERE_YOU_CAN')}
-
-
- {text.split(',').map(function (item, key) {
- return (
-
- {item}
-
- );
- })}
-
- >
- );
-};
-
-const NextButtonContent = (text) => {
- return {text} ;
-};
diff --git a/packages/webapp/src/components/Map/Footer/index.jsx b/packages/webapp/src/components/Map/Footer/index.jsx
new file mode 100644
index 0000000000..149f05c0b9
--- /dev/null
+++ b/packages/webapp/src/components/Map/Footer/index.jsx
@@ -0,0 +1,149 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import { ReactComponent as AddLogo } from '../../../assets/images/map/add.svg';
+import { ReactComponent as FilterLogo } from '../../../assets/images/map/filter.svg';
+import { ReactComponent as ExportLogo } from '../../../assets/images/map/export.svg';
+import clsx from 'clsx';
+import { useTranslation } from 'react-i18next';
+import MapDrawer from '../../MapDrawer';
+import { locationEnum } from '../../../containers/Map/constants';
+import { TourProviderWrapper } from '../../TourProviderWrapper/TourProviderWrapper';
+
+export default function PureMapFooter({
+ style,
+ isAdmin,
+ showSpotlight,
+ resetSpotlight,
+ onClickAdd,
+ onClickExport,
+ handleClickFilter,
+ showModal,
+ setShowMapFilter,
+ showMapFilter,
+ setShowAddDrawer,
+ showAddDrawer,
+ drawerDefaultHeight,
+ filterSettings,
+ onFilterMenuClick,
+ onAddMenuClick,
+ availableFilterSettings = {
+ area: [
+ locationEnum.barn,
+ locationEnum.ceremonial_area,
+ locationEnum.farm_site_boundary,
+ locationEnum.field,
+ locationEnum.garden,
+ locationEnum.greenhouse,
+ locationEnum.surface_water,
+ locationEnum.natural_area,
+ locationEnum.residence,
+ ],
+ line: [locationEnum.buffer_zone, locationEnum.watercourse, locationEnum.fence],
+ point: [locationEnum.gate, locationEnum.water_valve],
+ },
+}) {
+ const { t } = useTranslation();
+ const [stepSpotlighted, setStepSpotlighted] = useState(null);
+
+ const { container, button, svg, spotlighted } = styles;
+ return (
+
+
+ {isAdmin && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+PureMapFooter.prototype = {
+ className: PropTypes.string,
+ style: PropTypes.object,
+ isAdmin: PropTypes.bool,
+ showSpotlight: PropTypes.bool,
+ resetSpotlight: PropTypes.func,
+ onClickAdd: PropTypes.func,
+ onClickFilter: PropTypes.func,
+ onClickExport: PropTypes.func,
+ showModal: PropTypes.bool,
+ setShowMapFilter: PropTypes.func,
+ showMapFilter: PropTypes.bool,
+ drawerDefaultHeight: PropTypes.number,
+ filterSettings: PropTypes.func,
+ onFilterMenuClick: PropTypes.func,
+ onAddMenuClick: PropTypes.func,
+ setShowAddDrawer: PropTypes.func,
+ availableFilterSettings: PropTypes.shape({
+ area: PropTypes.array,
+ point: PropTypes.array,
+ line: PropTypes.array,
+ }),
+};
diff --git a/packages/webapp/src/components/Map/Footer/styles.module.scss b/packages/webapp/src/components/Map/Footer/styles.module.scss
index c101a25c10..24c0514504 100644
--- a/packages/webapp/src/components/Map/Footer/styles.module.scss
+++ b/packages/webapp/src/components/Map/Footer/styles.module.scss
@@ -1,6 +1,6 @@
.container {
display: flex;
-
+ order: 3;
height: 64px;
box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.25);
z-index: 1301;
diff --git a/packages/webapp/src/components/Map/Header/index.js b/packages/webapp/src/components/Map/Header/index.js
deleted file mode 100644
index 0675812452..0000000000
--- a/packages/webapp/src/components/Map/Header/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import styles from './styles.module.scss';
-import { useTranslation } from 'react-i18next';
-import VideoLogo from '../../../assets/images/map/video.svg';
-import clsx from 'clsx';
-
-export default function PureMapHeader({ className, style, farmName, showVideo, isAdmin }) {
- const { t } = useTranslation();
-
- return (
-
-
- {farmName}
- {' | '}
- {t('FARM_MAP.TITLE')}
-
- {isAdmin && (
-
- )}
-
- );
-}
-
-PureMapHeader.prototype = {
- className: PropTypes.string,
- style: PropTypes.object,
- farmName: PropTypes.string,
- showVideo: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Map/Header/index.jsx b/packages/webapp/src/components/Map/Header/index.jsx
new file mode 100644
index 0000000000..9fb2459160
--- /dev/null
+++ b/packages/webapp/src/components/Map/Header/index.jsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import VideoLogo from '../../../assets/images/map/video.svg';
+import clsx from 'clsx';
+
+export default function PureMapHeader({ className, style, farmName, showVideo, isAdmin }) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {farmName.length > 77 ? `${farmName.substring(0, 77).trim()}...` : farmName}
+
+ {' | '}
+ {t('FARM_MAP.TITLE')}
+
+ {isAdmin && (
+
+ )}
+
+ );
+}
+
+PureMapHeader.prototype = {
+ className: PropTypes.string,
+ style: PropTypes.object,
+ farmName: PropTypes.string,
+ showVideo: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Map/Header/styles.module.scss b/packages/webapp/src/components/Map/Header/styles.module.scss
index db7564fb38..4fa8682900 100644
--- a/packages/webapp/src/components/Map/Header/styles.module.scss
+++ b/packages/webapp/src/components/Map/Header/styles.module.scss
@@ -1,10 +1,12 @@
.container {
display: flex;
- height: 48px;
+ min-height: 48px;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 15px 24px;
+ overflow: hidden;
+ word-break: break-word;
}
.headerText {
@@ -13,6 +15,7 @@
font-style: normal;
font-size: 14px;
line-height: 18px;
+ margin-right: 12px;
}
.farmName {
diff --git a/packages/webapp/src/components/Map/LineMapBoxes/index.js b/packages/webapp/src/components/Map/LineMapBoxes/index.js
deleted file mode 100644
index d5cc57c5f5..0000000000
--- a/packages/webapp/src/components/Map/LineMapBoxes/index.js
+++ /dev/null
@@ -1,130 +0,0 @@
-import React, { useEffect } from 'react';
-import styles from './styles.module.scss';
-import clsx from 'clsx';
-import { locationEnum } from '../../../containers/Map/constants';
-import { useForm } from 'react-hook-form';
-import { Main } from '../../Typography';
-import BackArrow from '../../../assets/images/miscs/arrow.svg';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import { watercourseEnum } from '../../../containers/constants';
-import Unit from '../../Form/Unit';
-import { line_width } from '../../../util/unit';
-import { cloneObject } from '../../../util';
-
-export default function PureLineBox({
- typeOfLine,
- system,
- confirmLine,
- updateWidth,
- onClickTryAgain,
- onClickBack,
- locationData,
- ...props
-}) {
- const {
- register,
- handleSubmit,
- setValue,
- getValues,
- setError,
- control,
- watch,
- trigger,
-
- formState: { isValid, isDirty, errors },
- } = useForm({
- mode: 'onChange',
- defaultValues: cloneObject(locationData),
- });
-
- const { t } = useTranslation();
-
- const widthLabel =
- typeOfLine === locationEnum.watercourse
- ? t('FARM_MAP.LINE_DETAILS.WATERCOURSE')
- : t('FARM_MAP.LINE_DETAILS.BUFFER_ZONE_WIDTH');
- const title =
- typeOfLine === locationEnum.watercourse
- ? t('FARM_MAP.LINE_DETAILS.WATERCOURSE_TITLE')
- : t('FARM_MAP.LINE_DETAILS.BUFFER_TITLE');
-
- const onSubmit = (data) => {
- confirmLine(data);
- };
-
- const widthValue = watch(watercourseEnum.width);
- const bufferWidthValue = watch(watercourseEnum.buffer_width);
-
- useEffect(() => {
- trigger();
- updateWidth((widthValue || 0) + (bufferWidthValue || 0));
- }, [widthValue, bufferWidthValue]);
-
- return (
-
-
-
-
-
- {title}
-
-
-
-
-
-
-
- {typeOfLine === locationEnum.watercourse && (
-
-
-
- )}
-
-
-
-
- {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
-
-
- {t('common:CONFIRM')}
-
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Map/LineMapBoxes/index.jsx b/packages/webapp/src/components/Map/LineMapBoxes/index.jsx
new file mode 100644
index 0000000000..5f6574d78d
--- /dev/null
+++ b/packages/webapp/src/components/Map/LineMapBoxes/index.jsx
@@ -0,0 +1,130 @@
+import React, { useEffect } from 'react';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+import { locationEnum } from '../../../containers/Map/constants';
+import { useForm } from 'react-hook-form';
+import { Main } from '../../Typography';
+import BackArrow from '../../../assets/images/miscs/arrow.svg';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import { watercourseEnum } from '../../../containers/constants';
+import Unit from '../../Form/Unit';
+import { line_width } from '../../../util/convert-units/unit';
+import { cloneObject } from '../../../util';
+
+export default function PureLineBox({
+ typeOfLine,
+ system,
+ confirmLine,
+ updateWidth,
+ onClickTryAgain,
+ onClickBack,
+ locationData,
+ ...props
+}) {
+ const {
+ register,
+ handleSubmit,
+ setValue,
+ getValues,
+ setError,
+ control,
+ watch,
+ trigger,
+
+ formState: { isValid, isDirty, errors },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: cloneObject(locationData),
+ });
+
+ const { t } = useTranslation();
+
+ const widthLabel =
+ typeOfLine === locationEnum.watercourse
+ ? t('FARM_MAP.LINE_DETAILS.WATERCOURSE')
+ : t('FARM_MAP.LINE_DETAILS.BUFFER_ZONE_WIDTH');
+ const title =
+ typeOfLine === locationEnum.watercourse
+ ? t('FARM_MAP.LINE_DETAILS.WATERCOURSE_TITLE')
+ : t('FARM_MAP.LINE_DETAILS.BUFFER_TITLE');
+
+ const onSubmit = (data) => {
+ confirmLine(data);
+ };
+
+ const widthValue = watch(watercourseEnum.width);
+ const bufferWidthValue = watch(watercourseEnum.buffer_width);
+
+ useEffect(() => {
+ trigger();
+ updateWidth((widthValue || 0) + (bufferWidthValue || 0));
+ }, [widthValue, bufferWidthValue]);
+
+ return (
+
+
+
+
+
+ {title}
+
+
+
+
+
+
+
+ {typeOfLine === locationEnum.watercourse && (
+
+
+
+ )}
+
+
+
+
+ {t('FARM_MAP.DRAWING_MANAGER.REDRAW')}
+
+
+ {t('common:CONFIRM')}
+
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Map/LocationMapping/index.js b/packages/webapp/src/components/Map/LocationMapping/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/LocationMapping/index.js
rename to packages/webapp/src/components/Map/LocationMapping/index.jsx
diff --git a/packages/webapp/src/components/Map/Modals/AdjustArea/index.js b/packages/webapp/src/components/Map/Modals/AdjustArea/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/Modals/AdjustArea/index.js
rename to packages/webapp/src/components/Map/Modals/AdjustArea/index.jsx
diff --git a/packages/webapp/src/components/Map/Modals/AdjustLine/index.js b/packages/webapp/src/components/Map/Modals/AdjustLine/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/Modals/AdjustLine/index.js
rename to packages/webapp/src/components/Map/Modals/AdjustLine/index.jsx
diff --git a/packages/webapp/src/components/Map/Modals/DrawArea/index.js b/packages/webapp/src/components/Map/Modals/DrawArea/index.js
deleted file mode 100644
index 6e2b24b80d..0000000000
--- a/packages/webapp/src/components/Map/Modals/DrawArea/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import MapTutorialModal from '../../../Modals/MapTutorialModal';
-import PropTypes from 'prop-types';
-
-export default function DrawAreaModal({ dismissModal }) {
- const { t } = useTranslation();
-
- const steps = [
- t('FARM_MAP.TUTORIAL.AREA.STEP_ONE'),
- t('FARM_MAP.TUTORIAL.AREA.STEP_TWO'),
- t('FARM_MAP.TUTORIAL.AREA.STEP_THREE'),
- ];
-
- return (
-
- );
-}
-
-DrawAreaModal.prototype = {
- dismissModal: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Map/Modals/DrawArea/index.jsx b/packages/webapp/src/components/Map/Modals/DrawArea/index.jsx
new file mode 100644
index 0000000000..bb8b4d324c
--- /dev/null
+++ b/packages/webapp/src/components/Map/Modals/DrawArea/index.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import MapTutorialModal from '../../../Modals/MapTutorialModal';
+import PropTypes from 'prop-types';
+
+export default function DrawAreaModal({ dismissModal }) {
+ const { t } = useTranslation();
+
+ const steps = [
+ t('FARM_MAP.TUTORIAL.AREA.STEP_ONE'),
+ t('FARM_MAP.TUTORIAL.AREA.STEP_TWO'),
+ t('FARM_MAP.TUTORIAL.AREA.STEP_THREE'),
+ ];
+
+ return (
+
+ );
+}
+
+DrawAreaModal.prototype = {
+ dismissModal: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Map/Modals/DrawLine/index.js b/packages/webapp/src/components/Map/Modals/DrawLine/index.js
deleted file mode 100644
index 38fd1b8a47..0000000000
--- a/packages/webapp/src/components/Map/Modals/DrawLine/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import MapTutorialModal from '../../../Modals/MapTutorialModal';
-import PropTypes from 'prop-types';
-
-export default function DrawLineModal({ dismissModal }) {
- const { t } = useTranslation();
-
- const steps = [
- t('FARM_MAP.TUTORIAL.LINE.STEP_ONE'),
- t('FARM_MAP.TUTORIAL.LINE.STEP_TWO'),
- t('FARM_MAP.TUTORIAL.LINE.STEP_THREE'),
- t('FARM_MAP.TUTORIAL.LINE.STEP_FOUR'),
- ];
-
- return (
-
- );
-}
-
-DrawLineModal.prototype = {
- dismissModal: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Map/Modals/DrawLine/index.jsx b/packages/webapp/src/components/Map/Modals/DrawLine/index.jsx
new file mode 100644
index 0000000000..e49158fca5
--- /dev/null
+++ b/packages/webapp/src/components/Map/Modals/DrawLine/index.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import MapTutorialModal from '../../../Modals/MapTutorialModal';
+import PropTypes from 'prop-types';
+
+export default function DrawLineModal({ dismissModal }) {
+ const { t } = useTranslation();
+
+ const steps = [
+ t('FARM_MAP.TUTORIAL.LINE.STEP_ONE'),
+ t('FARM_MAP.TUTORIAL.LINE.STEP_TWO'),
+ t('FARM_MAP.TUTORIAL.LINE.STEP_THREE'),
+ t('FARM_MAP.TUTORIAL.LINE.STEP_FOUR'),
+ ];
+
+ return (
+
+ );
+}
+
+DrawLineModal.prototype = {
+ dismissModal: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Map/ProgressBar/index.js b/packages/webapp/src/components/Map/ProgressBar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/ProgressBar/index.js
rename to packages/webapp/src/components/Map/ProgressBar/index.jsx
diff --git a/packages/webapp/src/components/Map/SelectionHandler/index.js b/packages/webapp/src/components/Map/SelectionHandler/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Map/SelectionHandler/index.js
rename to packages/webapp/src/components/Map/SelectionHandler/index.jsx
diff --git a/packages/webapp/src/components/Map/Videos/index.js b/packages/webapp/src/components/Map/Videos/index.js
deleted file mode 100644
index 29be2ace85..0000000000
--- a/packages/webapp/src/components/Map/Videos/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import AreaVideo from '../../../assets/videos/AreaDrawing.mp4';
-import LineVideo from '../../../assets/videos/LineDrawing.mp4';
-import PointVideo from '../../../assets/videos/AddingPoints.mp4';
-import styles from './styles.module.scss';
-import TitleLayout from '../../Layout/TitleLayout';
-
-function PureVideoView({ history }) {
- return (
- history.push('/map')}>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-export default PureVideoView;
diff --git a/packages/webapp/src/components/Map/Videos/index.jsx b/packages/webapp/src/components/Map/Videos/index.jsx
new file mode 100644
index 0000000000..07c4b02030
--- /dev/null
+++ b/packages/webapp/src/components/Map/Videos/index.jsx
@@ -0,0 +1,62 @@
+import React, { useRef, useEffect } from 'react';
+import AreaVideo from '../../../assets/videos/AreaDrawing.mp4';
+import LineVideo from '../../../assets/videos/LineDrawing.mp4';
+import PointVideo from '../../../assets/videos/AddingPoints.mp4';
+import styles from './styles.module.scss';
+import TitleLayout from '../../Layout/TitleLayout';
+import { useTranslation } from 'react-i18next';
+const VIDEO_START_TIME = '#t=0.001';
+
+function PureVideoView({ history }) {
+ const { t } = useTranslation();
+ const areaVideoRef = useRef(null);
+ const lineVideoRef = useRef(null);
+ const pointVideoRef = useRef(null);
+
+ useEffect(() => {
+ areaVideoRef.current.src += VIDEO_START_TIME;
+ lineVideoRef.current.src += VIDEO_START_TIME;
+ pointVideoRef.current.src += VIDEO_START_TIME;
+ }, []);
+
+ return (
+ history.push('/map')}>
+
+
+ );
+}
+
+export default PureVideoView;
diff --git a/packages/webapp/src/components/Map/constants.js b/packages/webapp/src/components/Map/constants.js
index 501a6055f5..1b1b104cd7 100644
--- a/packages/webapp/src/components/Map/constants.js
+++ b/packages/webapp/src/components/Map/constants.js
@@ -1,8 +1,8 @@
-require('dotenv').config();
+
export const DEFAULT_CENTER = {
lat: 49.24966,
lng: -123.237421,
};
export const DEFAULT_ZOOM = 15;
-export const GMAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;
+export const GMAPS_API_KEY = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
diff --git a/packages/webapp/src/components/Map/index.js b/packages/webapp/src/components/Map/index.js
deleted file mode 100644
index e25b0b1583..0000000000
--- a/packages/webapp/src/components/Map/index.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import styles from './styles.module.scss';
-import GoogleMap from 'google-map-react';
-import { DEFAULT_ZOOM, GMAPS_API_KEY } from './constants';
-import PureMapHeader from './Header';
-import PureMapFooter from './Footer';
-
-export default function PureMap({ isAdmin, farmName, handleGoogleMapApi, center }) {
- const { t } = useTranslation();
- let [roadview, setRoadview] = useState(false);
-
- const getMapOptions = (maps) => {
- return {
- streetViewControl: false,
- scaleControl: true,
- fullscreenControl: false,
- styles: [
- {
- featureType: 'poi.business',
- elementType: 'labels',
- stylers: [
- {
- visibility: 'off',
- },
- ],
- },
- ],
- gestureHandling: 'greedy',
- disableDoubleClickZoom: true,
- minZoom: 1,
- maxZoom: 80,
- tilt: 0,
- mapTypeControl: true,
- mapTypeId: !roadview ? maps.MapTypeId.SATELLITE : maps.MapTypeId.ROADMAP,
- mapTypeControlOptions: {
- style: maps.MapTypeControlStyle.HORIZONTAL_BAR,
- position: maps.ControlPosition.BOTTOM_CENTER,
- mapTypeIds: [maps.MapTypeId.ROADMAP, maps.MapTypeId.SATELLITE],
- },
- zoomControl: true,
- clickableIcons: false,
- };
- };
-
- return (
-
-
-
-
- {/*TODO: move to container*/}
- handleGoogleMapApi(map, maps)}
- options={getMapOptions}
- >
-
-
-
-
- );
-}
-
-PureMap.prototype = {
- isAdmin: PropTypes.bool,
- farmName: PropTypes.string,
- handleGoogleMapApi: PropTypes.func,
- center: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Map/styles.module.scss b/packages/webapp/src/components/Map/styles.module.scss
deleted file mode 100644
index dd8d406665..0000000000
--- a/packages/webapp/src/components/Map/styles.module.scss
+++ /dev/null
@@ -1,33 +0,0 @@
-.pageWrapper {
- display: flex;
- flex-direction: column;
- width: 100%;
- // height: 100vh;
- min-height: 100%;
- align-items: stretch;
-}
-
-.mapHeader {
- order: 1;
-}
-
-.mapContainer {
- // flex: 1;
- position: relative;
- min-height: 500px;
- order: 2;
- flex-grow: 1;
- display: flex;
-}
-
-.workaround {
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- bottom: 0;
-}
-
-.mapFooter {
- order: 3;
-}
diff --git a/packages/webapp/src/components/MapDrawer/MapDrawerMenuItem.js b/packages/webapp/src/components/MapDrawer/MapDrawerMenuItem.jsx
similarity index 100%
rename from packages/webapp/src/components/MapDrawer/MapDrawerMenuItem.js
rename to packages/webapp/src/components/MapDrawer/MapDrawerMenuItem.jsx
diff --git a/packages/webapp/src/components/MapDrawer/index.js b/packages/webapp/src/components/MapDrawer/index.js
deleted file mode 100644
index d95457f103..0000000000
--- a/packages/webapp/src/components/MapDrawer/index.js
+++ /dev/null
@@ -1,401 +0,0 @@
-import React, { useMemo, useState } from 'react';
-import clsx from 'clsx';
-import { makeStyles } from '@material-ui/core/styles';
-import List from '@material-ui/core/List';
-import Divider from '@material-ui/core/Divider';
-import { Label, Semibold, Underlined } from '../Typography';
-import { ReactComponent as MapBackground } from '../../assets/images/farmMapFilter/MapBackground.svg';
-import { ReactComponent as LabelIcon } from '../../assets/images/farmMapFilter/Label.svg';
-import { ReactComponent as Barn } from '../../assets/images/farmMapFilter/Barn.svg';
-import { ReactComponent as CeremonialArea } from '../../assets/images/farmMapFilter/CA.svg';
-import { ReactComponent as FarmSiteBoundary } from '../../assets/images/farmMapFilter/FSB.svg';
-import { ReactComponent as Field } from '../../assets/images/farmMapFilter/Field.svg';
-import { ReactComponent as Garden } from '../../assets/images/farmMapFilter/Garden.svg';
-import { ReactComponent as Greenhouse } from '../../assets/images/farmMapFilter/Greenhouse.svg';
-import { ReactComponent as SurfaceWater } from '../../assets/images/farmMapFilter/SurfaceWater.svg';
-import { ReactComponent as NaturalArea } from '../../assets/images/farmMapFilter/NA.svg';
-import { ReactComponent as Residence } from '../../assets/images/farmMapFilter/Residence.svg';
-import { ReactComponent as BufferZone } from '../../assets/images/farmMapFilter/BufferZone.svg';
-import { ReactComponent as Watercourse } from '../../assets/images/farmMapFilter/Creek.svg';
-import { ReactComponent as Fence } from '../../assets/images/farmMapFilter/Fence.svg';
-import { ReactComponent as Gate } from '../../assets/images/farmMapFilter/Gate.svg';
-import { ReactComponent as WaterValve } from '../../assets/images/farmMapFilter/WaterValve.svg';
-import { Drawer } from '@material-ui/core';
-import { colors } from '../../assets/theme';
-import { useTranslation } from 'react-i18next';
-import { motion, useAnimation } from 'framer-motion';
-import PropTypes from 'prop-types';
-import { locationEnum } from '../../containers/Map/constants';
-import MapDrawerMenuItem from './MapDrawerMenuItem';
-
-const useStyles = makeStyles({
- fullList: {
- width: 'auto',
- marginBottom: '60px',
- elevation: 0,
- backgroundColor: 'white',
- borderRadius: '16px 16px 0px 0px',
- boxShadow: '0px 0px 4px rgba(0, 0, 0, 0.25)',
- },
- greenbar: {
- height: '4px',
- width: '36px',
- backgroundColor: colors.teal700,
- borderRadius: '2px',
- },
- handleBarContainer: {
- width: '100%',
- display: 'flex',
- justifyContent: 'center',
- padding: '14px 0',
- },
- MuiDrawer: {
- backgroundColor: colors.teal700,
- },
- BackdropProps: {
- background: 'transparent',
- },
- header: {
- '-webkit-user-select': 'none',
- '-moz-user-select': 'none',
- '-ms-user-select': 'none',
- 'user-select': 'none',
- 'touch-action': 'none',
- },
- headerTitle: {
- marginBottom: '16px',
- },
- headerContentContainer: {
- padding: '0 24px 8px 24px',
- },
- headerTextContainer: {
- textDecoration: 'underline',
- display: 'flex',
- flexDirection: 'row',
- },
- icon: {},
- underlined: {
- color: colors.brown700,
- },
- verticalDivider: {
- borderLeft: '1px solid',
- margin: '0 8px',
- color: colors.grey400,
- },
- label: {
- marginLeft: '24px',
- height: '24px',
- },
- labelDivider: {
- display: 'inline-block',
- borderTop: '1px solid',
- width: 'calc(100% - 80px)',
- transform: 'translate(11px, -3px)',
- color: '#C4C4C4',
- },
-});
-
-export default function MapDrawer({
- showMapDrawer,
- setShowMapDrawer,
- onMenuItemClick,
- filterSettings,
- availableFilterSettings,
- drawerDefaultHeight = window.innerHeight / 2 - 156,
- headerTitle,
-}) {
- const { t } = useTranslation();
-
- const classes = useStyles();
-
- const areaImgDict = useMemo(
- () =>
- [
- {
- name: t('FARM_MAP.MAP_FILTER.BARN'),
- icon: () => ,
- key: locationEnum.barn,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.CA'),
- icon: () => ,
- key: locationEnum.ceremonial_area,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.FSB'),
- icon: () => ,
- key: locationEnum.farm_site_boundary,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.FIELD'),
- icon: () => ,
- key: locationEnum.field,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.GARDEN'),
- icon: () => ,
- key: locationEnum.garden,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.GREENHOUSE'),
- icon: () => ,
- key: locationEnum.greenhouse,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.SURFACE_WATER'),
- icon: () => ,
- key: locationEnum.surface_water,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.NA'),
- icon: () => ,
- key: locationEnum.natural_area,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.RESIDENCE'),
- icon: () => ,
- key: locationEnum.residence,
- },
- ]
- .sort((firstLocationType, secondLocationType) =>
- firstLocationType.name.localeCompare(secondLocationType.name),
- )
- .filter(
- ({ key }) => !availableFilterSettings || availableFilterSettings.area.includes(key),
- ),
- [availableFilterSettings?.area],
- );
-
- const lineImgDict = useMemo(
- () =>
- [
- {
- name: t('FARM_MAP.MAP_FILTER.BZ'),
- icon: () => ,
- key: locationEnum.buffer_zone,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.WATERCOURSE'),
- icon: () => ,
- key: locationEnum.watercourse,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.FENCE'),
- icon: () => ,
- key: locationEnum.fence,
- },
- ]
- .sort((firstLocationType, secondLocationType) =>
- firstLocationType.name.localeCompare(secondLocationType.name),
- )
- .filter(
- ({ key }) => !availableFilterSettings || availableFilterSettings.line.includes(key),
- ),
- [availableFilterSettings?.line],
- );
-
- const pointImgDict = useMemo(
- () =>
- [
- {
- name: t('FARM_MAP.MAP_FILTER.GATE'),
- icon: () => ,
- key: locationEnum.gate,
- },
- {
- name: t('FARM_MAP.MAP_FILTER.WV'),
- icon: () => ,
- key: locationEnum.water_valve,
- },
- ]
- .sort((firstLocationType, secondLocationType) =>
- firstLocationType.name.localeCompare(secondLocationType.name),
- )
- .filter(
- ({ key }) => !availableFilterSettings || availableFilterSettings.point.includes(key),
- ),
- [availableFilterSettings?.point],
- );
-
- const [initHeight, setInitHeight] = useState(drawerDefaultHeight);
- const controls = useAnimation();
- const onPan = (event, info) =>
- controls.start({
- height: window.innerHeight - info.point.y - 142,
- });
- const onPanEnd = (event, info) => {
- if (info.point.y > window.innerHeight / 2 + 156) {
- setShowMapDrawer(false);
- } else if (info.point.y < 156) {
- const newHeight = window.innerHeight - 156;
- controls.start({
- height: newHeight,
- });
- setInitHeight(newHeight);
- } else {
- setInitHeight(window.innerHeight - info.point.y - 60);
- }
- };
-
- const list = () => (
-
-
-
-
-
-
{headerTitle}
- {!!filterSettings && (
-
- {
- onMenuItemClick('show_all');
- }}
- className={classes.underlined}
- >
- {t('FARM_MAP.MAP_FILTER.SHOW_ALL')}
-
-
- {
- onMenuItemClick('hide_all');
- }}
- className={classes.underlined}
- >
- {t('FARM_MAP.MAP_FILTER.HIDE_ALL')}
-
-
- )}
-
-
-
-
-
- {!!filterSettings && (
- onMenuItemClick('map_background')}
- isFiltered={!filterSettings['map_background']}
- >
-
-
- )}
-
- {!!filterSettings && !!areaImgDict.length && (
- onMenuItemClick('label')}
- isFiltered={!filterSettings['label']}
- >
-
-
- )}
-
- {!!areaImgDict.length && (
-
- {t('FARM_MAP.MAP_FILTER.AREAS')}
-
-
- )}
- {areaImgDict.map(({ key, name, icon }) => {
- return (
- onMenuItemClick(key)}
- isFiltered={filterSettings && !filterSettings?.[key]}
- >
- {icon()}
-
- );
- })}
-
- {!!lineImgDict.length && (
-
- {t('FARM_MAP.MAP_FILTER.LINES')}
-
-
- )}
- {lineImgDict.map(({ key, name, icon }) => (
- onMenuItemClick(key)}
- isFiltered={filterSettings && !filterSettings?.[key]}
- >
- {icon()}
-
- ))}
-
- {!!pointImgDict.length && (
-
- {t('FARM_MAP.MAP_FILTER.POINTS')}
-
-
- )}
- {pointImgDict.map(({ key, name, icon }) => (
- onMenuItemClick(key)}
- isFiltered={filterSettings && !filterSettings?.[key]}
- >
- {icon()}
-
- ))}
-
-
-
-
- );
-
- return (
-
- setShowMapDrawer(false)}
- PaperProps={{
- style: { backgroundColor: 'transparent' },
- square: false,
- }}
- ModalProps={{
- classes: { paddingBottom: '20px' },
- BackdropProps: {
- classes: {
- root: classes.BackdropProps,
- },
- },
- }}
- >
- {list()}
-
-
- );
-}
-
-function HandleBar({ classes }) {
- return (
-
- );
-}
-
-MapDrawer.prototype = {
- showMapDrawer: PropTypes.bool,
- setShowMapDrawer: PropTypes.func,
- onMenuItemClick: PropTypes.func,
- drawerDefaultHeight: PropTypes.number,
- filterSettings: PropTypes.object,
- headerTitle: PropTypes.string,
- availableFilterSettings: PropTypes.shape({
- area: PropTypes.array,
- point: PropTypes.array,
- line: PropTypes.array,
- }),
-};
diff --git a/packages/webapp/src/components/MapDrawer/index.jsx b/packages/webapp/src/components/MapDrawer/index.jsx
new file mode 100644
index 0000000000..f9489f886b
--- /dev/null
+++ b/packages/webapp/src/components/MapDrawer/index.jsx
@@ -0,0 +1,402 @@
+import React, { useMemo, useState } from 'react';
+import clsx from 'clsx';
+import { makeStyles } from '@material-ui/core/styles';
+import List from '@material-ui/core/List';
+import Divider from '@material-ui/core/Divider';
+import { Label, Semibold, Underlined } from '../Typography';
+import { ReactComponent as MapBackground } from '../../assets/images/farmMapFilter/MapBackground.svg';
+import { ReactComponent as LabelIcon } from '../../assets/images/farmMapFilter/Label.svg';
+import { ReactComponent as Barn } from '../../assets/images/farmMapFilter/Barn.svg';
+import { ReactComponent as CeremonialArea } from '../../assets/images/farmMapFilter/CA.svg';
+import { ReactComponent as FarmSiteBoundary } from '../../assets/images/farmMapFilter/FSB.svg';
+import { ReactComponent as Field } from '../../assets/images/farmMapFilter/Field.svg';
+import { ReactComponent as Garden } from '../../assets/images/farmMapFilter/Garden.svg';
+import { ReactComponent as Greenhouse } from '../../assets/images/farmMapFilter/Greenhouse.svg';
+import { ReactComponent as SurfaceWater } from '../../assets/images/farmMapFilter/SurfaceWater.svg';
+import { ReactComponent as NaturalArea } from '../../assets/images/farmMapFilter/NA.svg';
+import { ReactComponent as Residence } from '../../assets/images/farmMapFilter/Residence.svg';
+import { ReactComponent as BufferZone } from '../../assets/images/farmMapFilter/BufferZone.svg';
+import { ReactComponent as Watercourse } from '../../assets/images/farmMapFilter/Creek.svg';
+import { ReactComponent as Fence } from '../../assets/images/farmMapFilter/Fence.svg';
+import { ReactComponent as Gate } from '../../assets/images/farmMapFilter/Gate.svg';
+import { ReactComponent as WaterValve } from '../../assets/images/farmMapFilter/WaterValve.svg';
+import { Drawer } from '@material-ui/core';
+import { colors } from '../../assets/theme';
+import { useTranslation } from 'react-i18next';
+import { motion, useAnimation } from 'framer-motion';
+import PropTypes from 'prop-types';
+import { locationEnum } from '../../containers/Map/constants';
+import MapDrawerMenuItem from './MapDrawerMenuItem';
+
+const useStyles = makeStyles({
+ fullList: {
+ width: 'auto',
+ marginBottom: '60px',
+ elevation: 0,
+ backgroundColor: 'white',
+ borderRadius: '16px 16px 0px 0px',
+ boxShadow: '0px 0px 4px rgba(0, 0, 0, 0.25)',
+ },
+ greenbar: {
+ height: '4px',
+ width: '36px',
+ backgroundColor: colors.teal700,
+ borderRadius: '2px',
+ },
+ handleBarContainer: {
+ width: '100%',
+ display: 'flex',
+ justifyContent: 'center',
+ padding: '14px 0',
+ },
+ MuiDrawer: {
+ backgroundColor: colors.teal700,
+ },
+ BackdropProps: {
+ background: 'transparent',
+ },
+ header: {
+ '-webkit-user-select': 'none',
+ '-moz-user-select': 'none',
+ '-ms-user-select': 'none',
+ 'user-select': 'none',
+ 'touch-action': 'none',
+ },
+ headerTitle: {
+ marginBottom: '16px',
+ },
+ headerContentContainer: {
+ padding: '0 24px 8px 24px',
+ },
+ headerTextContainer: {
+ textDecoration: 'underline',
+ display: 'flex',
+ flexDirection: 'row',
+ },
+ icon: {},
+ underlined: {
+ color: colors.brown700,
+ },
+ verticalDivider: {
+ borderLeft: '1px solid',
+ margin: '0 8px',
+ color: colors.grey400,
+ },
+ label: {
+ marginLeft: '24px',
+ height: '24px',
+ },
+ labelDivider: {
+ display: 'inline-block',
+ borderTop: '1px solid',
+ width: 'calc(100% - 80px)',
+ transform: 'translate(11px, -3px)',
+ color: '#C4C4C4',
+ },
+});
+
+export default function MapDrawer({
+ showMapDrawer,
+ setShowMapDrawer,
+ onMenuItemClick,
+ filterSettings,
+ availableFilterSettings,
+ drawerDefaultHeight = window.innerHeight / 2 - 156,
+ headerTitle,
+}) {
+ const { t } = useTranslation();
+
+ const classes = useStyles();
+
+ const areaImgDict = useMemo(
+ () =>
+ [
+ {
+ name: t('FARM_MAP.MAP_FILTER.BARN'),
+ icon: () => ,
+ key: locationEnum.barn,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.CA'),
+ icon: () => ,
+ key: locationEnum.ceremonial_area,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.FSB'),
+ icon: () => ,
+ key: locationEnum.farm_site_boundary,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.FIELD'),
+ icon: () => ,
+ key: locationEnum.field,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.GARDEN'),
+ icon: () => ,
+ key: locationEnum.garden,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.GREENHOUSE'),
+ icon: () => ,
+ key: locationEnum.greenhouse,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.SURFACE_WATER'),
+ icon: () => ,
+ key: locationEnum.surface_water,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.NA'),
+ icon: () => ,
+ key: locationEnum.natural_area,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.RESIDENCE'),
+ icon: () => ,
+ key: locationEnum.residence,
+ },
+ ]
+ .sort((firstLocationType, secondLocationType) =>
+ firstLocationType.name.localeCompare(secondLocationType.name),
+ )
+ .filter(
+ ({ key }) => !availableFilterSettings || availableFilterSettings.area.includes(key),
+ ),
+ [availableFilterSettings?.area],
+ );
+
+ const lineImgDict = useMemo(
+ () =>
+ [
+ {
+ name: t('FARM_MAP.MAP_FILTER.BZ'),
+ icon: () => ,
+ key: locationEnum.buffer_zone,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.WATERCOURSE'),
+ icon: () => ,
+ key: locationEnum.watercourse,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.FENCE'),
+ icon: () => ,
+ key: locationEnum.fence,
+ },
+ ]
+ .sort((firstLocationType, secondLocationType) =>
+ firstLocationType.name.localeCompare(secondLocationType.name),
+ )
+ .filter(
+ ({ key }) => !availableFilterSettings || availableFilterSettings.line.includes(key),
+ ),
+ [availableFilterSettings?.line],
+ );
+
+ const pointImgDict = useMemo(
+ () =>
+ [
+ {
+ name: t('FARM_MAP.MAP_FILTER.GATE'),
+ icon: () => ,
+ key: locationEnum.gate,
+ },
+ {
+ name: t('FARM_MAP.MAP_FILTER.WV'),
+ icon: () => ,
+ key: locationEnum.water_valve,
+ },
+ ]
+ .sort((firstLocationType, secondLocationType) =>
+ firstLocationType.name.localeCompare(secondLocationType.name),
+ )
+ .filter(
+ ({ key }) => !availableFilterSettings || availableFilterSettings.point.includes(key),
+ ),
+ [availableFilterSettings?.point],
+ );
+
+ const [initHeight, setInitHeight] = useState(drawerDefaultHeight);
+ const controls = useAnimation();
+ const onPan = (event, info) =>
+ controls.start({
+ height: window.innerHeight - info.point.y - 142,
+ });
+ const onPanEnd = (event, info) => {
+ if (info.point.y > window.innerHeight / 2 + 156) {
+ setShowMapDrawer(false);
+ } else if (info.point.y < 156) {
+ const newHeight = window.innerHeight - 156;
+ controls.start({
+ height: newHeight,
+ });
+ setInitHeight(newHeight);
+ } else {
+ setInitHeight(window.innerHeight - info.point.y - 60);
+ }
+ };
+
+ const list = () => (
+
+
+
+
+
+
{headerTitle}
+ {!!filterSettings && (
+
+ {
+ onMenuItemClick('show_all');
+ }}
+ className={classes.underlined}
+ >
+ {t('FARM_MAP.MAP_FILTER.SHOW_ALL')}
+
+
+ {
+ onMenuItemClick('hide_all');
+ }}
+ className={classes.underlined}
+ >
+ {t('FARM_MAP.MAP_FILTER.HIDE_ALL')}
+
+
+ )}
+
+
+
+
+
+ {!!filterSettings && (
+ onMenuItemClick('map_background')}
+ isFiltered={!filterSettings['map_background']}
+ >
+
+
+ )}
+
+ {!!filterSettings && !!areaImgDict.length && (
+ onMenuItemClick('label')}
+ isFiltered={!filterSettings['label']}
+ >
+
+
+ )}
+
+ {!!areaImgDict.length && (
+
+ {t('FARM_MAP.MAP_FILTER.AREAS')}
+
+
+ )}
+ {areaImgDict.map(({ key, name, icon }) => {
+ return (
+ onMenuItemClick(key)}
+ isFiltered={filterSettings && !filterSettings?.[key]}
+ >
+ {icon()}
+
+ );
+ })}
+
+ {!!lineImgDict.length && (
+
+ {t('FARM_MAP.MAP_FILTER.LINES')}
+
+
+ )}
+ {lineImgDict.map(({ key, name, icon }) => (
+ onMenuItemClick(key)}
+ isFiltered={filterSettings && !filterSettings?.[key]}
+ >
+ {icon()}
+
+ ))}
+
+ {!!pointImgDict.length && (
+
+ {t('FARM_MAP.MAP_FILTER.POINTS')}
+
+
+ )}
+ {pointImgDict.map(({ key, name, icon }) => (
+ onMenuItemClick(key)}
+ isFiltered={filterSettings && !filterSettings?.[key]}
+ >
+ {icon()}
+
+ ))}
+
+
+
+
+ );
+
+ return (
+
+ setShowMapDrawer(false)}
+ PaperProps={{
+ style: { backgroundColor: 'transparent' },
+ square: false,
+ }}
+ ModalProps={{
+ classes: { paddingBottom: '20px' },
+ BackdropProps: {
+ classes: {
+ root: classes.BackdropProps,
+ },
+ },
+ }}
+ >
+ {list()}
+
+
+ );
+}
+
+function HandleBar({ classes }) {
+ return (
+
+ );
+}
+
+MapDrawer.prototype = {
+ showMapDrawer: PropTypes.bool,
+ setShowMapDrawer: PropTypes.func,
+ onMenuItemClick: PropTypes.func,
+ drawerDefaultHeight: PropTypes.number,
+ filterSettings: PropTypes.object,
+ headerTitle: PropTypes.string,
+ availableFilterSettings: PropTypes.shape({
+ area: PropTypes.array,
+ point: PropTypes.array,
+ line: PropTypes.array,
+ }),
+};
diff --git a/packages/webapp/src/components/Modals/AbandonManagementPlanModal/index.js b/packages/webapp/src/components/Modals/AbandonManagementPlanModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/AbandonManagementPlanModal/index.js
rename to packages/webapp/src/components/Modals/AbandonManagementPlanModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.js b/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.js
deleted file mode 100644
index eecec8f182..0000000000
--- a/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import ModalComponent from '../ModalComponent/v2';
-import styles from './styles.module.scss';
-import Button from '../../Form/Button';
-
-export default function ArchiveDocumentModal({ onArchive, dismissModal }) {
- const { t } = useTranslation();
-
- return (
-
-
- {t('DOCUMENTS.CANCEL')}
-
-
-
- {t('DOCUMENTS.ARCHIVE')}
-
- >
- }
- >
- {t('DOCUMENTS.ARCHIVE_DOCUMENT_TEXT')}
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.jsx b/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.jsx
new file mode 100644
index 0000000000..80a3391331
--- /dev/null
+++ b/packages/webapp/src/components/Modals/ArchiveDocumentModal/index.jsx
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import ModalComponent from '../ModalComponent/v2';
+import styles from './styles.module.scss';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+
+export default function ArchiveDocumentModal({ onSetArchive, dismissModal, isForArchiving }) {
+ const { t } = useTranslation();
+ const archiveStr = isForArchiving ? 'ARCHIVE' : 'UNARCHIVE';
+
+ return (
+
+
+ {t('DOCUMENTS.CANCEL')}
+
+
+
+ {t(`DOCUMENTS.${archiveStr}`)}
+
+ >
+ }
+ >
+ {t(`DOCUMENTS.${archiveStr}_DOCUMENT_TEXT`)}
+
+ );
+}
+
+ArchiveDocumentModal.propTypes = {
+ onSetArchive: PropTypes.func,
+ dismissModal: PropTypes.func,
+ isForArchiving: PropTypes.bool, // whether this is an archive modal or unarchive modal
+};
diff --git a/packages/webapp/src/components/Modals/BiodiversityLoadingModal/BiodiversityLoadingModal.jsx b/packages/webapp/src/components/Modals/BiodiversityLoadingModal/BiodiversityLoadingModal.jsx
new file mode 100644
index 0000000000..de0c8f1f2e
--- /dev/null
+++ b/packages/webapp/src/components/Modals/BiodiversityLoadingModal/BiodiversityLoadingModal.jsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React from 'react';
+import ModalComponent from '../ModalComponent/v2';
+import Button from '../../Form/Button';
+import styles from './styles.module.scss';
+import { useTranslation } from 'react-i18next';
+import { ReactComponent as HazardIcon } from '../../../assets/images/warning.svg';
+
+const BiodiversityLoadingModal = ({ dismissModal, loadingError, minutes }) => {
+ const { t } = useTranslation();
+ return loadingError ? (
+
+
+ {t('common:OK')}
+
+ >
+ }
+ error
+ />
+ ) : (
+
+
+ {t('common:CANCEL')}
+
+ >
+ }
+ />
+ );
+};
+
+export default BiodiversityLoadingModal;
diff --git a/packages/webapp/src/components/Insights/PriceCropContainer/styles.scss b/packages/webapp/src/components/Modals/BiodiversityLoadingModal/styles.module.scss
similarity index 100%
rename from packages/webapp/src/components/Insights/PriceCropContainer/styles.scss
rename to packages/webapp/src/components/Modals/BiodiversityLoadingModal/styles.module.scss
diff --git a/packages/webapp/src/components/Modals/CancelFlowModal/index.js b/packages/webapp/src/components/Modals/CancelFlowModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/CancelFlowModal/index.js
rename to packages/webapp/src/components/Modals/CancelFlowModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/CertificationsModal/index.js b/packages/webapp/src/components/Modals/CertificationsModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/CertificationsModal/index.js
rename to packages/webapp/src/components/Modals/CertificationsModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/Confirm/index.js b/packages/webapp/src/components/Modals/Confirm/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/Confirm/index.js
rename to packages/webapp/src/components/Modals/Confirm/index.jsx
diff --git a/packages/webapp/src/components/Modals/CropModals/RetireCropWarningModal.js b/packages/webapp/src/components/Modals/CropModals/RetireCropWarningModal.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/CropModals/RetireCropWarningModal.js
rename to packages/webapp/src/components/Modals/CropModals/RetireCropWarningModal.jsx
diff --git a/packages/webapp/src/components/Modals/CropModals/UnableToRetireCropModal.js b/packages/webapp/src/components/Modals/CropModals/UnableToRetireCropModal.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/CropModals/UnableToRetireCropModal.js
rename to packages/webapp/src/components/Modals/CropModals/UnableToRetireCropModal.jsx
diff --git a/packages/webapp/src/components/Modals/EditCropVarietyModal/index.js b/packages/webapp/src/components/Modals/EditCropVarietyModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/EditCropVarietyModal/index.js
rename to packages/webapp/src/components/Modals/EditCropVarietyModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/ExportMapModal/index.js b/packages/webapp/src/components/Modals/ExportMapModal/index.js
deleted file mode 100644
index 4935892fad..0000000000
--- a/packages/webapp/src/components/Modals/ExportMapModal/index.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Modal } from '../';
-import { ReactComponent as DownloadIcon } from '../../../assets/images/map/download.svg';
-import { AiOutlineMail } from 'react-icons/all';
-import styles from './styles.module.scss';
-import { Main, Title } from '../../Typography';
-import Button from '../../Form/Button';
-
-export function PureExportMapModal({
- onClickDownload: download,
- onClickShare: share,
- dismissModal,
-}) {
- const { t } = useTranslation();
- const [isEmailing, setEmailing] = useState();
- const onClickEmail = () => {
- share();
- setEmailing(true);
- };
- useEffect(() => {
- let timer;
- if (isEmailing) {
- timer = setTimeout(() => {
- if (isEmailing) {
- setEmailing(false);
- dismissModal();
- }
- }, 3000);
- }
- return () => clearTimeout(timer);
- }, [isEmailing]);
-
- const onClickDownload = () => {
- download();
- dismissModal();
- };
-
- return (
-
-
{t('FARM_MAP.EXPORT_MODAL.TITLE')}
-
{t('FARM_MAP.EXPORT_MODAL.BODY')}
-
-
- {t('FARM_MAP.EXPORT_MODAL.DOWNLOAD')}
-
-
-
-
- {isEmailing
- ? `${t('FARM_MAP.EXPORT_MODAL.EMAILING')}...`
- : t('FARM_MAP.EXPORT_MODAL.EMAIL_TO_ME')}
-
-
-
- );
-}
-
-export default function ExportMapModal({ onClickDownload, onClickShare, dismissModal }) {
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/ExportMapModal/index.jsx b/packages/webapp/src/components/Modals/ExportMapModal/index.jsx
new file mode 100644
index 0000000000..97191e6bfe
--- /dev/null
+++ b/packages/webapp/src/components/Modals/ExportMapModal/index.jsx
@@ -0,0 +1,87 @@
+import React, { useEffect, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Modal } from '../';
+import { ReactComponent as DownloadIcon } from '../../../assets/images/map/download.svg';
+import { AiOutlineMail } from 'react-icons/all';
+import styles from './styles.module.scss';
+import { Main, Title } from '../../Typography';
+import Button from '../../Form/Button';
+
+const isiOS = () => {
+ return (
+ ['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(
+ navigator.platform,
+ ) ||
+ (navigator.userAgent.includes('Mac') && 'ontouchend' in document)
+ );
+};
+
+export function PureExportMapModal({
+ onClickDownload: download,
+ onClickShare: share,
+ dismissModal,
+}) {
+ const { t } = useTranslation();
+ const [isEmailing, setEmailing] = useState(false);
+ const onClickEmail = () => {
+ share();
+ setEmailing(true);
+ };
+ useEffect(() => {
+ let timer;
+ if (isEmailing) {
+ timer = setTimeout(() => {
+ if (isEmailing) {
+ setEmailing(false);
+ dismissModal();
+ }
+ }, 3000);
+ }
+ return () => clearTimeout(timer);
+ }, [isEmailing]);
+
+ const onClickDownload = () => {
+ download();
+ dismissModal();
+ };
+
+ return (
+
+
{t('FARM_MAP.EXPORT_MODAL.TITLE')}
+ {!isiOS() && (
+ <>
+
{t('FARM_MAP.EXPORT_MODAL.BODY')}
+
+
+ {t('FARM_MAP.EXPORT_MODAL.DOWNLOAD')}
+
+ >
+ )}
+
+
+
+ {isEmailing
+ ? `${t('FARM_MAP.EXPORT_MODAL.EMAILING')}...`
+ : t('FARM_MAP.EXPORT_MODAL.EMAIL_TO_ME')}
+
+
+
+ );
+}
+
+export default function ExportMapModal({ onClickDownload, onClickShare, dismissModal }) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/FileSizeExceedModal/index.js b/packages/webapp/src/components/Modals/FileSizeExceedModal/index.js
deleted file mode 100644
index 478539c765..0000000000
--- a/packages/webapp/src/components/Modals/FileSizeExceedModal/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import ModalComponent from '../ModalComponent/v2';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import styles from './styles.module.scss';
-
-export default function FileSizeExceedModal({ dismissModal, handleRetry }) {
- const { t } = useTranslation();
- return (
-
- );
-}
\ No newline at end of file
diff --git a/packages/webapp/src/components/Modals/FileSizeExceedModal/index.jsx b/packages/webapp/src/components/Modals/FileSizeExceedModal/index.jsx
new file mode 100644
index 0000000000..e2db9b8e03
--- /dev/null
+++ b/packages/webapp/src/components/Modals/FileSizeExceedModal/index.jsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import ModalComponent from '../ModalComponent/v2';
+import { useTranslation } from 'react-i18next';
+
+export default function FileSizeExceedModal({ dismissModal, handleRetry }) {
+ const { t } = useTranslation();
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/ImageModal/index.js b/packages/webapp/src/components/Modals/ImageModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/ImageModal/index.js
rename to packages/webapp/src/components/Modals/ImageModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/IncompleteTaskModal/index.js b/packages/webapp/src/components/Modals/IncompleteTaskModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/IncompleteTaskModal/index.js
rename to packages/webapp/src/components/Modals/IncompleteTaskModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/MapTutorialModal/index.js b/packages/webapp/src/components/Modals/MapTutorialModal/index.js
deleted file mode 100644
index 0c20da14d0..0000000000
--- a/packages/webapp/src/components/Modals/MapTutorialModal/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { Modal } from '../';
-import styles from './styles.module.scss';
-import { Title } from '../../Typography';
-import Button from '../../Form/Button';
-import PropTypes from 'prop-types';
-import clsx from 'clsx';
-
-export default function MapTutorialModal({ title, steps, dismissModal, children, hasNoBullet }) {
- const { t } = useTranslation();
-
- return (
-
-
-
{title}
- {steps?.length && (
-
- {steps.map((step) => (
- {step}
- ))}
-
- )}
- {children}
-
- {t('common:GOT_IT')}
-
-
-
- );
-}
-
-MapTutorialModal.prototype = {
- title: PropTypes.string,
- steps: PropTypes.array,
- dismissModal: PropTypes.func,
- hasNoBullet: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Modals/MapTutorialModal/index.jsx b/packages/webapp/src/components/Modals/MapTutorialModal/index.jsx
new file mode 100644
index 0000000000..0ebb98b898
--- /dev/null
+++ b/packages/webapp/src/components/Modals/MapTutorialModal/index.jsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Modal } from '../';
+import styles from './styles.module.scss';
+import { Title } from '../../Typography';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+
+export default function MapTutorialModal({ title, steps, dismissModal, children, hasNoBullet }) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
{title}
+ {steps?.length && (
+
+ {steps.map((step) => (
+ {step}
+ ))}
+
+ )}
+ {children}
+
+ {t('common:GOT_IT')}
+
+
+
+ );
+}
+
+MapTutorialModal.prototype = {
+ title: PropTypes.string,
+ steps: PropTypes.array,
+ dismissModal: PropTypes.func,
+ hasNoBullet: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Modals/ModalComponent/v1/index.js b/packages/webapp/src/components/Modals/ModalComponent/v1/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/ModalComponent/v1/index.js
rename to packages/webapp/src/components/Modals/ModalComponent/v1/index.jsx
diff --git a/packages/webapp/src/components/Modals/ModalComponent/v2/index.js b/packages/webapp/src/components/Modals/ModalComponent/v2/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/ModalComponent/v2/index.js
rename to packages/webapp/src/components/Modals/ModalComponent/v2/index.jsx
diff --git a/packages/webapp/src/components/Modals/MuiModalContainer/index.js b/packages/webapp/src/components/Modals/MuiModalContainer/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/MuiModalContainer/index.js
rename to packages/webapp/src/components/Modals/MuiModalContainer/index.jsx
diff --git a/packages/webapp/src/components/Modals/NoCropManagementPlanModal/index.js b/packages/webapp/src/components/Modals/NoCropManagementPlanModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/NoCropManagementPlanModal/index.js
rename to packages/webapp/src/components/Modals/NoCropManagementPlanModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.js b/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.js
deleted file mode 100644
index 88a28d3a7d..0000000000
--- a/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import ModalComponent from '../ModalComponent/v2'
-import { useTranslation } from 'react-i18next';
-
-export default function NotifyUpdatedFarmModal({ dismissModal }) {
- const { t } = useTranslation();
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.jsx b/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.jsx
new file mode 100644
index 0000000000..190479917c
--- /dev/null
+++ b/packages/webapp/src/components/Modals/NotifyUpdatedFarmModal/index.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import ModalComponent from '../ModalComponent/v2';
+import { useTranslation } from 'react-i18next';
+
+export default function NotifyUpdatedFarmModal({ dismissModal }) {
+ const { t } = useTranslation();
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/PlantingTaskModal/index.js b/packages/webapp/src/components/Modals/PlantingTaskModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/PlantingTaskModal/index.js
rename to packages/webapp/src/components/Modals/PlantingTaskModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/PopUp/index.js b/packages/webapp/src/components/Modals/PopUp/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/PopUp/index.js
rename to packages/webapp/src/components/Modals/PopUp/index.jsx
diff --git a/packages/webapp/src/components/Modals/PreparingExportModal/index.js b/packages/webapp/src/components/Modals/PreparingExportModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/PreparingExportModal/index.js
rename to packages/webapp/src/components/Modals/PreparingExportModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/QuickAssignModal/index.js b/packages/webapp/src/components/Modals/QuickAssignModal/index.js
deleted file mode 100644
index 3d44c24638..0000000000
--- a/packages/webapp/src/components/Modals/QuickAssignModal/index.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import React, { useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import ModalComponent from '../ModalComponent/v2';
-import styles from './styles.module.scss';
-import Button from '../../Form/Button';
-import ReactSelect from '../../Form/ReactSelect';
-import Checkbox from '../../Form/Checkbox';
-import { ReactComponent as Person } from '../../../assets/images/task/Person.svg';
-
-export default function TaskQuickAssignModal({
- dismissModal,
- task_id,
- due_date,
- isAssigned,
- onAssignTasksOnDate,
- onAssignTask,
- users,
- user,
-}) {
- const { t } = useTranslation();
- const selfOption = { label: `${user.first_name} ${user.last_name}`, value: user.user_id };
- const unAssignedOption = { label: t('TASK.UNASSIGNED'), value: null };
- const options = useMemo(() => {
- if (user.is_admin) {
- const options = users.map(({ first_name, last_name, user_id }) => ({
- label: `${first_name} ${last_name}`,
- value: user_id,
- }));
- options.unshift(unAssignedOption);
- return options;
- } else return [selfOption, unAssignedOption];
- }, []);
-
- const [selectedWorker, setWorker] = useState(isAssigned ? unAssignedOption : selfOption);
- const [assignAll, setAssignAll] = useState(false);
-
- const onAssign = () => {
- assignAll
- ? onAssignTasksOnDate({
- task_id: task_id,
- date: due_date,
- assignee_user_id: selectedWorker.value,
- })
- : onAssignTask({
- task_id: task_id,
- assignee_user_id: selectedWorker.value,
- });
- dismissModal();
- };
-
- const disabled = selectedWorker === null;
-
- return (
-
-
- {t('common:CANCEL')}
-
-
-
- {t('common:UPDATE')}
-
- >
- }
- icon={ }
- >
-
- {/*TODO: properly fix checkbox label overflow ST-272*/}
- setAssignAll(!assignAll)}
- />
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/QuickAssignModal/index.jsx b/packages/webapp/src/components/Modals/QuickAssignModal/index.jsx
new file mode 100644
index 0000000000..d328052a43
--- /dev/null
+++ b/packages/webapp/src/components/Modals/QuickAssignModal/index.jsx
@@ -0,0 +1,122 @@
+import React, { useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import ModalComponent from '../ModalComponent/v2';
+import styles from './styles.module.scss';
+import Button from '../../Form/Button';
+import ReactSelect from '../../Form/ReactSelect';
+import Checkbox from '../../Form/Checkbox';
+import { ReactComponent as Person } from '../../../assets/images/task/Person.svg';
+import { tasksSelector } from '../../../containers/taskSlice';
+import { useSelector } from 'react-redux';
+
+export default function TaskQuickAssignModal({
+ dismissModal,
+ task_id,
+ due_date,
+ isAssigned,
+ onAssignTasksOnDate,
+ onAssignTask,
+ users,
+ user,
+}) {
+ const { t } = useTranslation();
+ const selfOption = { label: `${user.first_name} ${user.last_name}`, value: user.user_id };
+ const unAssignedOption = { label: t('TASK.UNASSIGNED'), value: null, isDisabled: false };
+ const options = useMemo(() => {
+ if (user.is_admin) {
+ const options = users.map(({ first_name, last_name, user_id }) => ({
+ label: `${first_name} ${last_name}`,
+ value: user_id,
+ }));
+ unAssignedOption.isDisabled = !isAssigned;
+ options.unshift(unAssignedOption);
+ return options;
+ } else return [selfOption, unAssignedOption];
+ }, []);
+
+ const [selectedWorker, setWorker] = useState(isAssigned ? unAssignedOption : selfOption);
+ const [assignAll, setAssignAll] = useState(false);
+
+ const tasks = useSelector(tasksSelector);
+
+ const checkUnassignedTaskForSameDate = () => {
+ console.log(tasks);
+ const selectedTask = tasks.find((t) => t.task_id == task_id);
+ let isUnassignedTaskPresent = false;
+ for (let task of tasks) {
+ if (
+ task.due_date === selectedTask.due_date &&
+ !task.assignee &&
+ task.task_id !== task_id &&
+ task.complete_date === null
+ ) {
+ isUnassignedTaskPresent = true;
+ break;
+ }
+ }
+ return isUnassignedTaskPresent;
+ };
+
+ const onAssign = () => {
+ assignAll && checkUnassignedTaskForSameDate() && selectedWorker.value !== null
+ ? onAssignTasksOnDate({
+ task_id: task_id,
+ date: due_date,
+ assignee_user_id: selectedWorker.value,
+ })
+ : onAssignTask({
+ task_id: task_id,
+ assignee_user_id: selectedWorker.value,
+ });
+ dismissModal();
+ };
+
+ const onCheckedAll = () => {
+ setAssignAll(!assignAll);
+ };
+
+ const disabled = selectedWorker === null;
+
+ return (
+
+
+ {t('common:CANCEL')}
+
+
+
+ {t('common:UPDATE')}
+
+ >
+ }
+ icon={ }
+ >
+
+ {/*TODO: properly fix checkbox label overflow ST-272*/}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/RequestConfirmationModal/index.js b/packages/webapp/src/components/Modals/RequestConfirmationModal/index.js
deleted file mode 100644
index f3f2047809..0000000000
--- a/packages/webapp/src/components/Modals/RequestConfirmationModal/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { ReactComponent as Success } from '../../../assets/images/requestConfirmation/success.svg';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { ModalComponent, Modal } from '../';
-
-export function PureRequestConfirmationComponent({ onClick }) {
- const { t } = useTranslation();
- const title = t('REQUEST_CONFIRMATION_MODAL.TITLE');
- const description = t('REQUEST_CONFIRMATION_MODAL.DESCRIPTION');
- const buttonLabel = t('REQUEST_CONFIRMATION_MODAL.BUTTON');
-
- return (
- }
- />
- );
-}
-
-export default function RequestConfirmationComponent({ onClick, dismissModal }) {
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/RequestConfirmationModal/index.jsx b/packages/webapp/src/components/Modals/RequestConfirmationModal/index.jsx
new file mode 100644
index 0000000000..e9fd816a5f
--- /dev/null
+++ b/packages/webapp/src/components/Modals/RequestConfirmationModal/index.jsx
@@ -0,0 +1,29 @@
+import { ReactComponent as Success } from '../../../assets/images/requestConfirmation/success.svg';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Modal, ModalComponent } from '../';
+
+export function PureRequestConfirmationComponent({ onClick }) {
+ const { t } = useTranslation();
+ const title = t('REQUEST_CONFIRMATION_MODAL.TITLE');
+ const description = t('REQUEST_CONFIRMATION_MODAL.DESCRIPTION');
+ const buttonLabel = t('REQUEST_CONFIRMATION_MODAL.BUTTON');
+
+ return (
+ }
+ />
+ );
+}
+
+export default function RequestConfirmationComponent({ onClick, dismissModal }) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/ResetPassword/index.js b/packages/webapp/src/components/Modals/ResetPassword/index.js
deleted file mode 100644
index 1eab3ecd78..0000000000
--- a/packages/webapp/src/components/Modals/ResetPassword/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { ReactComponent as MailIconImg } from '../../../assets/images/resetPassword/mail-icon.svg';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { ModalComponent, Modal } from '../';
-
-export function PureResetPasswordComponent({ onClick, changeText }) {
- const { t } = useTranslation();
- const title = t('PASSWORD_RESET.TITLE');
- const descriptionTop = t('PASSWORD_RESET.DESCRIPTION_TOP');
- const descriptionBottom = t('PASSWORD_RESET.DESCRIPTION_BOTTOM');
- const buttonLabel = changeText ? t('PASSWORD_RESET.BUTTON_SENDING') : t('PASSWORD_RESET.BUTTON');
- return (
- }
- />
- );
-}
-
-export default function ResetPasswordModal({ onClick, dismissModal, changeText }) {
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/ResetPassword/index.jsx b/packages/webapp/src/components/Modals/ResetPassword/index.jsx
new file mode 100644
index 0000000000..fe81b361aa
--- /dev/null
+++ b/packages/webapp/src/components/Modals/ResetPassword/index.jsx
@@ -0,0 +1,31 @@
+import { ReactComponent as MailIconImg } from '../../../assets/images/resetPassword/mail-icon.svg';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Modal, ModalComponent } from '../';
+
+export function PureResetPasswordComponent({ onClick, changeText }) {
+ const { t } = useTranslation();
+ const title = t('PASSWORD_RESET.TITLE');
+ const descriptionTop = t('PASSWORD_RESET.DESCRIPTION_TOP');
+ const descriptionBottom = t('PASSWORD_RESET.DESCRIPTION_BOTTOM');
+ const buttonLabel = changeText ? t('PASSWORD_RESET.BUTTON_SENDING') : t('PASSWORD_RESET.BUTTON');
+ return (
+ }
+ />
+ );
+}
+
+export default function ResetPasswordModal({ onClick, dismissModal, changeText }) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.js b/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.js
deleted file mode 100644
index 19b1247d11..0000000000
--- a/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { ReactComponent as Success } from '../../../assets/images/resetPassword/success.svg';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { ModalComponent, Modal } from '../';
-
-export function PureResetSuccessComponent({ onClick }) {
- const { t } = useTranslation();
- const title = t('PASSWORD_RESET_SUCCESS_MODAL.TITLE');
- const descriptionTop = t('PASSWORD_RESET_SUCCESS_MODAL.DESCRIPTION');
- const buttonLabel = t('PASSWORD_RESET_SUCCESS_MODAL.BUTTON');
-
- return (
- }
- />
- );
-}
-
-export default function ResetSuccessModal({ onClick, dismissModal }) {
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.jsx b/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.jsx
new file mode 100644
index 0000000000..f1352f4fd1
--- /dev/null
+++ b/packages/webapp/src/components/Modals/ResetPasswordSuccess/index.jsx
@@ -0,0 +1,29 @@
+import { ReactComponent as Success } from '../../../assets/images/resetPassword/success.svg';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { Modal, ModalComponent } from '../';
+
+export function PureResetSuccessComponent({ onClick }) {
+ const { t } = useTranslation();
+ const title = t('PASSWORD_RESET_SUCCESS_MODAL.TITLE');
+ const descriptionTop = t('PASSWORD_RESET_SUCCESS_MODAL.DESCRIPTION');
+ const buttonLabel = t('PASSWORD_RESET_SUCCESS_MODAL.BUTTON');
+
+ return (
+ }
+ />
+ );
+}
+
+export default function ResetSuccessModal({ onClick, dismissModal }) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Modals/RetireConfirmationModal/index.js b/packages/webapp/src/components/Modals/RetireConfirmationModal/index.js
deleted file mode 100644
index 965b537f9a..0000000000
--- a/packages/webapp/src/components/Modals/RetireConfirmationModal/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import ModalComponent from '../ModalComponent/v2'
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import styles from './styles.module.scss';
-
-export default function ConfirmRetireModal({ dismissModal, handleRetire }) {
- const { t } = useTranslation();
- return (
-
-
- {t('common:CANCEL')}
-
-
- {t('common:RETIRE')}
-
- >
- }
- />
- );
-}
diff --git a/packages/webapp/src/components/Modals/RetireConfirmationModal/index.jsx b/packages/webapp/src/components/Modals/RetireConfirmationModal/index.jsx
new file mode 100644
index 0000000000..419582eee0
--- /dev/null
+++ b/packages/webapp/src/components/Modals/RetireConfirmationModal/index.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import ModalComponent from '../ModalComponent/v2';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import styles from './styles.module.scss';
+
+export default function ConfirmRetireModal({ dismissModal, handleRetire }) {
+ const { t } = useTranslation();
+ return (
+
+
+ {t('common:CANCEL')}
+
+
+ {t('common:RETIRE')}
+
+ >
+ }
+ />
+ );
+}
diff --git a/packages/webapp/src/components/Modals/RetireCustomTaskModal/index.js b/packages/webapp/src/components/Modals/RetireCustomTaskModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/RetireCustomTaskModal/index.js
rename to packages/webapp/src/components/Modals/RetireCustomTaskModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/RevokeUserAccessModal/index.jsx b/packages/webapp/src/components/Modals/RevokeUserAccessModal/index.jsx
new file mode 100644
index 0000000000..02b99e0b95
--- /dev/null
+++ b/packages/webapp/src/components/Modals/RevokeUserAccessModal/index.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import ModalComponent from '../ModalComponent/v2';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import styles from './styles.module.scss';
+
+export default function RevokeUserAccessModal({ dismissModal, onRevoke }) {
+ const { t } = useTranslation();
+ return (
+
+
+ {t('common:NO')}
+
+
+ {t('common:YES')}
+
+ >
+ }
+ warning
+ />
+ );
+}
diff --git a/packages/webapp/src/components/Modals/RevokeUserAccessModal/styles.module.scss b/packages/webapp/src/components/Modals/RevokeUserAccessModal/styles.module.scss
new file mode 100644
index 0000000000..e500e87737
--- /dev/null
+++ b/packages/webapp/src/components/Modals/RevokeUserAccessModal/styles.module.scss
@@ -0,0 +1,3 @@
+.button {
+ width: 96px;
+}
diff --git a/packages/webapp/src/components/Modals/UnableToRetireModal/index.js b/packages/webapp/src/components/Modals/UnableToRetireModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/UnableToRetireModal/index.js
rename to packages/webapp/src/components/Modals/UnableToRetireModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/UpdateTaskDateModal/index.jsx b/packages/webapp/src/components/Modals/UpdateTaskDateModal/index.jsx
new file mode 100644
index 0000000000..4e06ba57ef
--- /dev/null
+++ b/packages/webapp/src/components/Modals/UpdateTaskDateModal/index.jsx
@@ -0,0 +1,62 @@
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import ModalComponent from '../ModalComponent/v2';
+import styles from './styles.module.scss';
+import Button from '../../Form/Button';
+import Input from '../../Form/Input';
+import { ReactComponent as CalendarIcon } from '../../../assets/images/task/CalendarIcon.svg';
+import { getDateInputFormat } from '../../../util/moment';
+import PropTypes from 'prop-types';
+
+export default function DateQuickAssignModal({ dismissModal, due_date, onChangeTaskDate }) {
+ const { t } = useTranslation();
+
+ const [date, setDate] = useState(getDateInputFormat(due_date));
+
+ const disabled = date === getDateInputFormat(due_date);
+
+ return (
+
+
+ {t('common:CANCEL')}
+
+
+ {
+ onChangeTaskDate(date);
+ dismissModal();
+ }}
+ disabled={disabled}
+ className={styles.button}
+ color="primary"
+ sm
+ >
+ {t('common:UPDATE')}
+
+ >
+ }
+ icon={ }
+ >
+ {
+ setDate(e.target.value);
+ }}
+ />
+
+ );
+}
+DateQuickAssignModal.propTypes = {
+ dismissModal: PropTypes.func,
+ due_date: PropTypes.string,
+ onChangeTaskDate: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Modals/UpdateTaskDateModal/styles.module.scss b/packages/webapp/src/components/Modals/UpdateTaskDateModal/styles.module.scss
new file mode 100644
index 0000000000..2ab998183c
--- /dev/null
+++ b/packages/webapp/src/components/Modals/UpdateTaskDateModal/styles.module.scss
@@ -0,0 +1,32 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ max-width: 312px;
+ width: 90vw;
+ background: #fafafd;
+ border-radius: 7.05466px;
+ position: relative;
+ padding: 24px;
+ }
+
+ .title {
+ color: var(--teal700);
+ line-height: 24px;
+ margin-bottom: 16px;
+ }
+
+ .stepList {
+ color: var(--grey600);
+ line-height: 18px;
+ margin-bottom: 8px;
+ }
+
+ .stepListItem {
+ margin-bottom: 16px;
+ }
+
+ .button {
+ width: 96px;
+ }
+
+
\ No newline at end of file
diff --git a/packages/webapp/src/components/Modals/YearSelectorModal/index.js b/packages/webapp/src/components/Modals/YearSelectorModal/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Modals/YearSelectorModal/index.js
rename to packages/webapp/src/components/Modals/YearSelectorModal/index.jsx
diff --git a/packages/webapp/src/components/Modals/index.js b/packages/webapp/src/components/Modals/index.js
deleted file mode 100644
index 250fb33174..0000000000
--- a/packages/webapp/src/components/Modals/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import Floater from 'react-floater';
-import React from 'react';
-import ModalComponent from './ModalComponent/v1';
-
-function Modal({ children, dismissModal }) {
- return (
- <>
-
-
-
- >
- );
-}
-
-export { Modal, ModalComponent };
diff --git a/packages/webapp/src/components/Modals/index.jsx b/packages/webapp/src/components/Modals/index.jsx
new file mode 100644
index 0000000000..1bc44e4c55
--- /dev/null
+++ b/packages/webapp/src/components/Modals/index.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import ModalComponent from './ModalComponent/v1';
+import { Dialog } from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme) => ({
+ paper: {
+ overflow: 'inherit',
+ },
+
+}));
+
+function Modal({ children, dismissModal }) {
+ const classes = useStyles();
+ return (
+
+ {children}
+
+ );
+}
+
+export { Modal, ModalComponent };
diff --git a/packages/webapp/src/components/MonthCalendar/index.js b/packages/webapp/src/components/MonthCalendar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/MonthCalendar/index.js
rename to packages/webapp/src/components/MonthCalendar/index.jsx
diff --git a/packages/webapp/src/components/MuiFullPagePopup/index.js b/packages/webapp/src/components/MuiFullPagePopup/index.jsx
similarity index 100%
rename from packages/webapp/src/components/MuiFullPagePopup/index.js
rename to packages/webapp/src/components/MuiFullPagePopup/index.jsx
diff --git a/packages/webapp/src/components/MuiFullPagePopup/v2/index.js b/packages/webapp/src/components/MuiFullPagePopup/v2/index.jsx
similarity index 100%
rename from packages/webapp/src/components/MuiFullPagePopup/v2/index.js
rename to packages/webapp/src/components/MuiFullPagePopup/v2/index.jsx
diff --git a/packages/webapp/src/components/MyFarmFloater/index.js b/packages/webapp/src/components/MyFarmFloater/index.js
deleted file mode 100644
index fc478ce642..0000000000
--- a/packages/webapp/src/components/MyFarmFloater/index.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import React from 'react';
-import { ReactComponent as FarmMapIcon } from '../../assets/images/farm-profile/farm-map.svg';
-import { ReactComponent as FarmInfoIcon } from '../../assets/images/farm-profile/farm-info.svg';
-import { ReactComponent as PeopleIcon } from '../../assets/images/farm-profile/people.svg';
-import { ReactComponent as CertificationsIcon } from '../../assets/images/farm-profile/certificate.svg';
-import ListOption from '../Navigation/NavBar/ListOption';
-import { useTranslation } from 'react-i18next';
-
-import Floater from 'react-floater';
-import { useSelector } from 'react-redux';
-import { userFarmSelector } from '../../containers/userFarmSlice';
-
-export function PureMyFarmFloaterComponent({
- farmInfo,
- farmMap,
- people,
- certification,
- isIntroducingFarmMap,
- isIntroducingCertifications,
- isAdmin,
-}) {
- const { t } = useTranslation();
- const isIntroductionActive = isIntroducingFarmMap || isIntroducingCertifications;
- return (
-
- }
- isIntroductionActive={isIntroductionActive}
- />
- }
- isIntroductionActive={isIntroductionActive}
- isBeingIntroduced={isIntroducingFarmMap}
- />
- }
- isIntroductionActive={isIntroductionActive}
- />
- {isAdmin && (
- }
- isIntroductionActive={isIntroductionActive}
- isBeingIntroduced={isIntroducingCertifications}
- />
- )}
-
- );
-}
-
-export default function PureMyFarmFloater({
- children,
- openProfile,
- farmInfoClick,
- farmMapClick,
- peopleClick,
- certificationClick,
- isIntroducingFarmMap,
- isIntroducingCertifications,
-}) {
- const { is_admin } = useSelector(userFarmSelector);
- const isIntroductionActive = isIntroducingFarmMap || isIntroducingCertifications;
- const Wrapper = (
-
- );
- return (
-
- {children}
-
- );
-}
diff --git a/packages/webapp/src/components/Navigation/Floater/Floater.jsx b/packages/webapp/src/components/Navigation/Floater/Floater.jsx
new file mode 100644
index 0000000000..bcb4980434
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/Floater/Floater.jsx
@@ -0,0 +1,53 @@
+import { makeStyles, Tooltip } from '@material-ui/core';
+import React from 'react';
+import { colors } from '../../../assets/theme';
+
+const useStyle = makeStyles((theme) => ({
+ arrow: {
+ zIndex: -1,
+ color: 'white',
+ overflow: 'initial',
+ width: '32px',
+ height: '16px',
+ marginTop: '-16px !important',
+ '&::before': {
+ transform: `translate(4px, 0) rotate(45deg)`,
+ },
+ },
+ tooltip: {
+ top: '-8px',
+ [theme.breakpoints.up('sm')]: {
+ top: '4px',
+ },
+ pointerEvents: 'initial',
+ zIndex: 1000,
+ backgroundColor: 'white',
+ boxShadow: '2px 6px 12px rgba(102, 115, 138, 0.2)',
+ padding: 0,
+ borderRadius: '4px',
+ maxWidth: '264px',
+ textAlign: 'left',
+ userSelect: 'none',
+ color: colors.grey900,
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: 'Open Sans, SansSerif, serif',
+ },
+}));
+
+export function Floater({
+ body, children, open, arrow = true,
+ ...props
+}) {
+ const classes = useStyle();
+ return
+ {children}
+ ;
+}
diff --git a/packages/webapp/src/components/Navigation/Floater/MyFarmFloater.jsx b/packages/webapp/src/components/Navigation/Floater/MyFarmFloater.jsx
new file mode 100644
index 0000000000..9d4382bb82
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/Floater/MyFarmFloater.jsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { ReactComponent as FarmMapIcon } from '../../../assets/images/farm-profile/farm-map.svg';
+import { ReactComponent as FarmInfoIcon } from '../../../assets/images/farm-profile/farm-info.svg';
+import { ReactComponent as PeopleIcon } from '../../../assets/images/farm-profile/people.svg';
+import { ReactComponent as CertificationsIcon } from '../../../assets/images/farm-profile/certificate.svg';
+import ListOption from '../NavBar/ListOption';
+import { useTranslation } from 'react-i18next';
+import { useSelector } from 'react-redux';
+import { userFarmSelector } from '../../../containers/userFarmSlice';
+import { Floater } from './Floater';
+
+export function PureMyFarmFloaterComponent({
+ farmInfo,
+ farmMap,
+ people,
+ certification,
+ isAdmin,
+}) {
+ const { t } = useTranslation();
+ return (
+
+ }
+ />
+ }
+ />
+ }
+ />
+ {isAdmin && (
+ }
+ />
+ )}
+
+ );
+}
+
+export default function PureMyFarmFloater({
+ children,
+ farmInfoClick,
+ farmMapClick,
+ peopleClick,
+ certificationClick,
+ openProfile,
+}) {
+ const { is_admin } = useSelector(userFarmSelector);
+ const Wrapper = (
+
+ );
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/webapp/src/components/Navigation/Floater/ProfileFloater.jsx b/packages/webapp/src/components/Navigation/Floater/ProfileFloater.jsx
new file mode 100644
index 0000000000..517e6a1f35
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/Floater/ProfileFloater.jsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import { ReactComponent as LogoutIcon } from '../../../assets/images/navbar/logout.svg';
+import { ReactComponent as MyInfoIcon } from '../../../assets/images/navbar/my-info.svg';
+import { ReactComponent as HelpIcon } from '../../../assets/images/navbar/help-profile.svg';
+import { ReactComponent as VideoIcon } from '../../../assets/images/video_icon.svg';
+import { ReactComponent as SwitchFarmIcon } from '../../../assets/images/navbar/switch-farm.svg';
+import ListOption from '../NavBar/ListOption';
+import { useTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+import { Floater } from './Floater';
+
+export function PureProfileFloaterComponent({
+ onInfo, onSwitchFarm, onHelp,
+ onTutorials, onLogout,
+}) {
+ const { t } = useTranslation();
+ return (
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ />
+
+ }
+ customParagraphStyle={{ paddingBottom: '0.5rem', paddingTop: '0.4rem' }}
+ />
+
+ );
+}
+
+export default function PureProfileFloater({
+ children,
+ openProfile,
+ helpClick,
+ myInfoClick,
+ logOutClick,
+ switchFarmClick,
+ tutorialsClick,
+}) {
+ return (
+
+ }
+ placement={'bottom-end'}
+ open={openProfile}
+ >
+ {children}
+
+ );
+}
+
+PureProfileFloaterComponent.prototype = {
+ onInfo: PropTypes.func,
+ onSwitchFarm: PropTypes.func,
+ onHelp: PropTypes.func,
+ onLogout: PropTypes.func,
+};
+
+PureProfileFloater.prototype = {
+ myInfoClick: PropTypes.func,
+ switchFarmClick: PropTypes.func,
+ helpClick: PropTypes.func,
+ logOutClick: PropTypes.func,
+ children: PropTypes.node,
+ openProfile: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Navigation/NavBar/Alert.jsx b/packages/webapp/src/components/Navigation/NavBar/Alert.jsx
new file mode 100644
index 0000000000..fbeafc3a7b
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/NavBar/Alert.jsx
@@ -0,0 +1,39 @@
+import { makeStyles } from '@material-ui/core/styles';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+import { ReactComponent as AlertIcon } from '../../../assets/images/alert.svg';
+
+export default function PureAlert({ alertCount }) {
+ const useStyles = makeStyles({
+ alert: {
+ position: 'absolute',
+ left: '13px',
+ top: '2px',
+ width: '12px',
+ height: '12px',
+ },
+ alertCount: {
+ fontFamily: '"Open Sans"," SansSerif", serif',
+ fontWeight: 700,
+ fontSize: '8px',
+ textAlign: 'center',
+ color: 'white',
+ },
+ });
+ const classes = useStyles();
+
+ return (
+ alertCount && (
+ <>
+
+
+ {alertCount <= 9 ? alertCount : '9+'}
+
+ >
+ )
+ );
+}
+
+PureAlert.propTypes = {
+ alertCount: PropTypes.number.isRequired,
+};
diff --git a/packages/webapp/src/components/Navigation/NavBar/ListOption/index.js b/packages/webapp/src/components/Navigation/NavBar/ListOption/index.js
deleted file mode 100644
index 72778996c4..0000000000
--- a/packages/webapp/src/components/Navigation/NavBar/ListOption/index.js
+++ /dev/null
@@ -1,64 +0,0 @@
-import React from 'react';
-import styles from './listOption.module.scss';
-
-export default function ListOption({
- iconText,
- clickFn,
- icon,
- customParagraphStyle = {},
- customIconStyle = {},
- isBeingIntroduced = false,
- isIntroductionActive = false,
-}) {
- if (isIntroductionActive) {
- let alterStyles;
- if (isBeingIntroduced) {
- alterStyles = {
- background: '#c7efd3',
- };
- } else {
- alterStyles = {
- background: 'white',
- };
- }
- customParagraphStyle = {
- ...customParagraphStyle,
- ...alterStyles,
- };
- customIconStyle = {
- ...customIconStyle,
- ...alterStyles,
- };
- }
-
- const paragraphStyle = Object.assign(
- {
- paddingBottom: '0.4rem',
- paddingTop: '0.5rem',
- fontFamily: '"Open Sans"," SansSerif", serif',
- fontSize: '0.88rem',
- marginBottom: '0px',
- cursor: 'pointer',
- display: 'flex',
- alignItems: 'center',
- },
- customParagraphStyle,
- );
- const iconStyle = Object.assign(
- {
- width: '44px',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- },
- customIconStyle,
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/components/Navigation/NavBar/ListOption/index.jsx b/packages/webapp/src/components/Navigation/NavBar/ListOption/index.jsx
new file mode 100644
index 0000000000..358c6c4575
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/NavBar/ListOption/index.jsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import styles from './listOption.module.scss';
+
+export default function ListOption({
+ iconText,
+ clickFn,
+ icon,
+ customParagraphStyle = {},
+ customIconStyle = {},
+ isBeingIntroduced = false,
+ isIntroductionActive = false,
+}) {
+ if (isIntroductionActive) {
+ let alterStyles;
+ if (isBeingIntroduced) {
+ alterStyles = {
+ background: '#c7efd3',
+ };
+ } else {
+ alterStyles = {
+ background: 'white',
+ };
+ }
+ customParagraphStyle = {
+ ...customParagraphStyle,
+ ...alterStyles,
+ };
+ customIconStyle = {
+ ...customIconStyle,
+ ...alterStyles,
+ };
+ }
+
+ const paragraphStyle = Object.assign(
+ {
+ paddingBottom: '0.4rem',
+ paddingTop: '0.5rem',
+ fontFamily: '"Open Sans"," SansSerif", serif',
+ fontSize: '0.88rem',
+ marginBottom: '0px',
+ cursor: 'pointer',
+ display: 'flex',
+ alignItems: 'center',
+ },
+ customParagraphStyle,
+ );
+ const iconStyle = Object.assign(
+ {
+ width: '44px',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ customIconStyle,
+ );
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/components/Navigation/NavBar/Navbar.test.js b/packages/webapp/src/components/Navigation/NavBar/Navbar.test.js
deleted file mode 100644
index 1043cbbc4c..0000000000
--- a/packages/webapp/src/components/Navigation/NavBar/Navbar.test.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import { render, fireEvent, screen, act } from '@testing-library/react';
-import PureNavBar from './index';
-import '@testing-library/jest-dom';
-
-describe('Navbar view', () => {
- beforeAll(() => {});
- it('should renders correctly with non required props', () => {
- render( );
- expect(screen.getAllByRole('button')).toBeDefined(); // Icons are buttons
- expect(screen.getAllByRole('button').length).toBe(3);
- });
-
- it('should open profile if click is performed on profile icon', () => {
- render( );
- screen.getByTestId('thirdStep').click();
- expect(screen.getByText(/Log out/i)).toBeVisible();
- expect(screen.getByText(/help/i)).toBeVisible();
- expect(screen.getByText(/switch farm/i)).toBeVisible();
- expect(screen.getByText(/my info/i)).toBeVisible();
- });
-
- it('should close profile if click is performed on icon', () => {
- render( );
- screen.getByTestId('thirdStep').click();
- expect(screen.getByText(/Log out/i)).toBeVisible();
- screen.getByTestId('thirdStep').click();
- expect(screen.getByText(/Log out/i)).not.toBeVisible();
- expect(screen.getByText(/help/i)).not.toBeVisible();
- expect(screen.getByText(/switch farm/i)).not.toBeVisible();
- expect(screen.getByText(/my info/i)).not.toBeVisible();
- });
-});
diff --git a/packages/webapp/src/components/Navigation/NavBar/NavbarSpotlightProvider.jsx b/packages/webapp/src/components/Navigation/NavBar/NavbarSpotlightProvider.jsx
new file mode 100644
index 0000000000..647d69dc08
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/NavBar/NavbarSpotlightProvider.jsx
@@ -0,0 +1,90 @@
+import { TourProviderWrapper } from '../../TourProviderWrapper/TourProviderWrapper';
+import { useTranslation } from 'react-i18next';
+
+export function NavbarSpotlightProvider({ children, open, onFinish }) {
+ const { t } = useTranslation();
+ return (
+
+ {children}
+
+ );
+}
+
+export function NavBarNotificationSpotlightProvider({ children, open, onFinish }) {
+ const { t } = useTranslation();
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/webapp/src/components/Navigation/NavBar/index.js b/packages/webapp/src/components/Navigation/NavBar/index.js
deleted file mode 100644
index 77d14761ce..0000000000
--- a/packages/webapp/src/components/Navigation/NavBar/index.js
+++ /dev/null
@@ -1,477 +0,0 @@
-import React, { useState } from 'react';
-import {Link} from 'react-router-dom';
-import ReactJoyride, { STATUS } from 'react-joyride';
-import { makeStyles, useTheme } from '@material-ui/core/styles';
-import useMediaQuery from '@material-ui/core/useMediaQuery';
-import PureProfileFloater from '../../ProfileFloater';
-import { ReactComponent as MyFarmIcon } from '../../../assets/images/my-farm.svg';
-import { ReactComponent as MyFarmIconSpan } from '../../../assets/images/my-farm-es.svg';
-import { ReactComponent as MyFarmIconPort } from '../../../assets/images/my-farm-pt.svg';
-import { ReactComponent as TaskIcon } from '../../../assets/images/task_icon.svg';
-// TODO: use profile picture stored in db
-import { ReactComponent as ProfilePicture } from '../../../assets/images/navbar/defaultpfp.svg';
-import PureMyFarmFloater from '../../MyFarmFloater';
-import PureNotificationFloater from '../../NotificationFloater';
-import { logout } from '../../../util/jwt';
-import { useTranslation } from 'react-i18next';
-import SmallerLogo from '../../../assets/images/smaller_logo.svg';
-import SmallLogo from '../../../assets/images/small_logo.svg';
-import AppBar from '@material-ui/core/AppBar';
-import Toolbar from '@material-ui/core/Toolbar';
-import IconButton from '@material-ui/core/IconButton';
-import { BiMenu } from 'react-icons/bi';
-import { colors } from '../../../assets/theme';
-import { ClickAwayListener, SwipeableDrawer } from '@material-ui/core';
-import SlideMenu from './slideMenu';
-import PropTypes from 'prop-types';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../../../containers/showedSpotlightSlice';
-import { setSpotlightToShown } from '../../../containers/Map/saga';
-import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
-import {
- isIntroducingCertificationsSelector,
- setIntroducingCertifications,
-} from '../../../containers/Navigation/navbarSlice';
-
-const useStyles = makeStyles((theme) => ({
- menuButton: {
- position: 'absolute',
- padding: 0,
- left: '24px',
- '&:hover': {
- backgroundColor: 'transparent',
- },
- },
- icons: {
- display: 'flex',
- position: 'absolute',
- right: '8px',
- },
- appBar: {
- background:
- 'linear-gradient(96.68deg,#78c99e -4.29%,#c7efd3 24.32%,#e3f8ec 35.52%,#e3f8ec 64.28%,#c7efd3 80.81%,#78c99e 125.09%)',
- boxShadow: 'none',
- minHeight: '54px',
- [theme.breakpoints.up('md')]: {
- minHeight: '72px',
- },
- },
- toolbar: {
- display: 'flex',
- justifyContent: 'flex-start',
- flexGrow: 1,
- alignItems: 'center',
- [theme.breakpoints.up('md')]: {
- justifyContent: 'center',
- },
- },
- notificationButton: {
- transform: 'translateY(1px)',
- },
- profileButton: {
- transform: 'translateY(-2px)',
- },
- iconButton: {
- margin: theme.spacing(1),
- padding: 0,
- },
- burgerMenu: {
- fontSize: '32px',
- color: colors.teal700,
- [theme.breakpoints.up('md')]: {
- fontSize: '40px',
- },
- },
- green: {
- color: colors.teal700,
- },
- p: {
- marginBottom: '12px',
- },
- black: {
- color: colors.grey900,
- },
- drawerRoot: {
- zIndex: '1302 !important',
- },
-}));
-
-export default function PureNavBar({
- showSpotLight,
- resetSpotlight,
- history,
- showFinances,
- defaultOpenFloater,
-}) {
- const classes = useStyles();
- const { t } = useTranslation([
- 'translation',
- 'crop',
- 'common',
- 'disease',
- 'task',
- 'expense',
- 'fertilizer',
- 'message',
- 'gender',
- 'role',
- 'crop_nutrients',
- 'harvest_uses',
- 'soil',
- 'certifications',
- 'crop_group',
- ]);
- const { introduce_map, navigation } = useSelector(showedSpotlightSelector);
- const isIntroducingFarmMap = !introduce_map && navigation;
- const isIntroducingCertifications = useSelector(isIntroducingCertificationsSelector);
- const dispatch = useDispatch();
- //Drawer
- const [isDrawerOpen, setIsDrawerOpen] = useState(false);
- const closeDrawer = () => setIsDrawerOpen(false);
- const burgerMenuOnClick = () => setIsDrawerOpen((prev) => !prev);
- const [manageOpen, setManageOpen] = useState(true);
- const toggleManage = () => {
- setManageOpen(!manageOpen);
- };
- const selectedLanguage = getLanguageFromLocalStorage();
-
- //Floater
- const [openFloater, setOpenFloater] = useState(defaultOpenFloater);
- const [FARM, NOTIFICATION, PROFILE] = ['farm', 'notification', 'profile'];
- const isFarmFloaterOpen = openFloater === FARM;
- const isNotificationFloaterOpen = openFloater === NOTIFICATION;
- const isProfileFloaterOpen = openFloater === PROFILE;
- const closeFloater = () => {
- setOpenFloater(null);
- dispatch(setIntroducingCertifications(false));
- };
- const farmButtonOnClick = () => setOpenFloater(isFarmFloaterOpen ? null : FARM);
- const taskIconClick = () => {
- history.push('/tasks');
- };
- const profileButtonOnClick = () => setOpenFloater(isProfileFloaterOpen ? null : PROFILE);
- const onClickAway = () => {
- setOpenFloater(null);
- };
-
- const farmInfoClick = () => {
- if (!introduce_map) return;
- history.push({
- pathname: '/Profile',
- state: 'farm',
- });
- closeFloater();
- };
- const farmMapClick = () => {
- if (!introduce_map) dispatch(setSpotlightToShown('introduce_map'));
- history.push('/map');
- closeFloater();
- };
- const peopleClick = () => {
- if (!introduce_map) return;
- history.push({
- pathname: '/Profile',
- state: 'people',
- });
- closeFloater();
- };
- const certificationClick = () => {
- if (!introduce_map) return;
- history.push('/certification');
- closeFloater();
- };
-
- //PureProfileFloater
- const helpClick = () => {
- history.push('/help');
- closeFloater();
- };
- const switchFarmClick = () => {
- history.push('/farm_selection');
- closeFloater();
- };
- const logOutClick = () => {
- logout();
- closeFloater();
- };
- const myInfoClick = () => {
- history.push('/Profile');
- closeFloater();
- };
- const openTutorialsClick = () => {
- const playlistIDs = {
- 'es': 'PLDRpVZ4VsXJhghxfEQuApFQTeCWUbGBN9',
- 'pt': 'PLDRpVZ4VsXJg0ke20m47MmJq6uAJAlAGF',
- 'en': 'PLDRpVZ4VsXJgVGrmmXJooNqceXvre8IDY'
- };
-
- const playList = playlistIDs[selectedLanguage] || playlistIDs['en'];
- const url = 'https://www.youtube.com/playlist?list=' + playList;
-
- const win = window.open(url, '_blank');
- win.focus();
- closeFloater();
- }
-
- // Pure Notification Floater
- const notificationTeaserClick = () => {
- closeFloater();
- };
-
- //Spotlight
- const resetSpotlightStatus = (data) => {
- const { action, status } = data;
- if ([STATUS.FINISHED, STATUS.SKIPPED].includes(status) || action === 'close') {
- resetSpotlight();
- }
- };
- const farmSpotlight = t('NAVIGATION.SPOTLIGHT.FARM');
- const notificationsSpotlight = t('NAVIGATION.SPOTLIGHT.NOTIFICATION');
- const myProfileSpotlight = t('NAVIGATION.SPOTLIGHT.PROFILE');
- const steps = [
- {
- target: '#firstStep',
- title: returnContent(t('NAVIGATION.SPOTLIGHT.FARM_TITLE'), true, classes),
- content: returnContent(farmSpotlight, false, classes),
- locale: {
- next: returnNextButton(t('common:NEXT'), classes),
- },
- showCloseButton: false,
- disableBeacon: true,
- placement: 'right-start',
- styles: {
- options: {
- width: 240,
- },
- },
- },
- {
- target: '#secondStep',
- title: returnContent(t('NAVIGATION.SPOTLIGHT.NOTIFICATION_TITLE'), true, classes),
- content: returnContent(notificationsSpotlight, false, classes),
- locale: {
- next: returnNextButton(t('common:NEXT'), classes),
- },
- showCloseButton: false,
- placement: 'right-start',
- styles: {
- options: {
- width: 260,
- },
- },
- },
- {
- target: '#thirdStep',
- title: returnContent(t('NAVIGATION.SPOTLIGHT.PROFILE_TITLE'), true, classes),
- content: returnContent(myProfileSpotlight, false, classes),
- locale: {
- last: returnNextButton(t('common:GOT_IT'), classes),
- },
- placement: 'right-start',
- showCloseButton: false,
- styles: {
- options: {
- width: 210,
- },
- tooltip: {
- transform: 'translateX(-12px)',
- },
- },
- floaterProps: {
- styles: {
- floater: {
- marginRight: '0',
- },
- },
- },
- },
- ];
- return (
-
-
-
-
-
- setIsDrawerOpen(false)}
- onOpen={() => setIsDrawerOpen(true)}
- >
-
-
-
-
-
-
-
- {selectedLanguage === 'pt' ? (
-
- ) : selectedLanguage === 'es' ? (
-
- ) : (
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {showSpotLight && (
- //Deprecated
-
- )}
-
-
- );
-}
-
-const returnContent = (spotlightType, title, classes) => {
- return spotlightType.split(',').map(function (item, key) {
- return title ? (
-
-
- {item}
-
-
- ) : (
-
-
- {item}
-
-
- );
- });
-};
-
-const returnNextButton = (str, classes) => {
- return {str} ;
-};
-
-const Logo = ({ history }) => {
- const theme = useTheme();
- const matches = useMediaQuery(theme.breakpoints.up('md'));
- return (
- history.push('/')}
- />
- );
-};
-
-PureNavBar.propTypes = {
- showSpotLight: PropTypes.bool,
- resetSpotlight: PropTypes.func,
- history: PropTypes.object,
- setDefaultDateRange: PropTypes.func,
- showFinances: PropTypes.bool,
- defaultOpenFloater: PropTypes.oneOf(['farm', 'notification', 'profile']),
-};
diff --git a/packages/webapp/src/components/Navigation/NavBar/index.jsx b/packages/webapp/src/components/Navigation/NavBar/index.jsx
new file mode 100644
index 0000000000..59591e8b4a
--- /dev/null
+++ b/packages/webapp/src/components/Navigation/NavBar/index.jsx
@@ -0,0 +1,361 @@
+import React, { useState } from 'react';
+import { makeStyles, useTheme } from '@material-ui/core/styles';
+import useMediaQuery from '@material-ui/core/useMediaQuery';
+import PureProfileFloater from '../Floater/ProfileFloater';
+import { ReactComponent as NotificationIcon } from '../../../assets/images/notif.svg';
+import { ReactComponent as MyFarmIcon } from '../../../assets/images/my-farm.svg';
+import { ReactComponent as MyFarmIconSpan } from '../../../assets/images/my-farm-es.svg';
+import { ReactComponent as MyFarmIconPort } from '../../../assets/images/my-farm-pt.svg';
+import { ReactComponent as MyFarmIconFren } from '../../../assets/images/my-farm-fr.svg';
+import { ReactComponent as TaskIcon } from '../../../assets/images/task_icon.svg';
+// TODO: use profile picture stored in db
+import { ReactComponent as ProfilePicture } from '../../../assets/images/navbar/defaultpfp.svg';
+import PureMyFarmFloater from '../Floater/MyFarmFloater';
+import { logout } from '../../../util/jwt';
+import { useTranslation } from 'react-i18next';
+import SmallerLogo from '../../../assets/images/smaller_logo.svg';
+import SmallLogo from '../../../assets/images/small_logo.svg';
+import AppBar from '@material-ui/core/AppBar';
+import Toolbar from '@material-ui/core/Toolbar';
+import IconButton from '@material-ui/core/IconButton';
+import { BiMenu } from 'react-icons/bi';
+import { colors } from '../../../assets/theme';
+import { ClickAwayListener, SwipeableDrawer } from '@material-ui/core';
+import SlideMenu from './slideMenu';
+import PropTypes from 'prop-types';
+import { useDispatch } from 'react-redux';
+import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
+import {
+ NavbarSpotlightProvider,
+ NavBarNotificationSpotlightProvider,
+} from './NavbarSpotlightProvider';
+import Alert from '../../../containers/Navigation/Alert';
+
+const useStyles = makeStyles((theme) => ({
+ menuButton: {
+ position: 'absolute',
+ padding: 0,
+ left: '24px',
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ },
+ icons: {
+ display: 'flex',
+ position: 'absolute',
+ right: '8px',
+ },
+ appBar: {
+ background:
+ 'linear-gradient(96.68deg,#78c99e -4.29%,#c7efd3 24.32%,#e3f8ec 35.52%,#e3f8ec 64.28%,#c7efd3 80.81%,#78c99e 125.09%)',
+ boxShadow: 'none',
+ minHeight: '54px',
+ [theme.breakpoints.up('md')]: {
+ minHeight: '72px',
+ },
+ },
+ toolbar: {
+ display: 'flex',
+ justifyContent: 'flex-start',
+ flexGrow: 1,
+ alignItems: 'center',
+ [theme.breakpoints.up('md')]: {
+ justifyContent: 'center',
+ },
+ },
+ notificationButton: {
+ transform: 'translateY(1px)',
+ },
+ profileButton: {},
+ iconButton: {
+ margin: theme.spacing(1),
+ padding: 0,
+ },
+ burgerMenu: {
+ fontSize: '32px',
+ color: colors.teal700,
+ [theme.breakpoints.up('md')]: {
+ fontSize: '40px',
+ },
+ },
+ green: {
+ color: colors.teal700,
+ },
+ p: {
+ marginBottom: '12px',
+ },
+ black: {
+ color: colors.grey900,
+ },
+ drawerRoot: {
+ zIndex: '1302 !important',
+ },
+}));
+
+export default function PureNavBar({
+ showSpotLight,
+ showNotification,
+ resetSpotlight,
+ history,
+ showFinances,
+ defaultOpenFloater,
+}) {
+ const classes = useStyles();
+ const { t } = useTranslation([
+ 'translation',
+ 'crop',
+ 'common',
+ 'disease',
+ 'task',
+ 'expense',
+ 'fertilizer',
+ 'message',
+ 'gender',
+ 'role',
+ 'crop_nutrients',
+ 'harvest_uses',
+ 'soil',
+ 'certifications',
+ 'crop_group',
+ ]);
+ const dispatch = useDispatch();
+ //Drawer
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
+ const closeDrawer = () => setIsDrawerOpen(false);
+ const burgerMenuOnClick = () => setIsDrawerOpen((prev) => !prev);
+ const [manageOpen, setManageOpen] = useState(true);
+ const toggleManage = () => {
+ setManageOpen(!manageOpen);
+ };
+ const selectedLanguage = getLanguageFromLocalStorage();
+
+ //Floater
+ const [openFloater, setOpenFloater] = useState(defaultOpenFloater);
+ const [FARM, NOTIFICATION, PROFILE] = ['farm', 'notification', 'profile'];
+ const isFarmFloaterOpen = openFloater === FARM;
+ const isNotificationFloaterOpen = openFloater === NOTIFICATION;
+ const isProfileFloaterOpen = openFloater === PROFILE;
+ const closeFloater = () => {
+ setOpenFloater(null);
+ };
+ const farmButtonOnClick = () => setOpenFloater(isFarmFloaterOpen ? null : FARM);
+ const notificationIconClick = () => {
+ closeFloater();
+ const url = '/notifications';
+ if (history.location.pathname === url) {
+ // TODO click should update contents; is there better way than full page refresh?
+ history.go(0);
+ } else {
+ history.push(url);
+ }
+ };
+ const taskIconClick = () => {
+ closeFloater();
+ history.push('/tasks');
+ };
+ const profileButtonOnClick = () => setOpenFloater(isProfileFloaterOpen ? null : PROFILE);
+ const onClickAway = () => {
+ setOpenFloater(null);
+ };
+
+ const farmInfoClick = () => {
+ history.push({
+ pathname: '/farm',
+ });
+ closeFloater();
+ };
+ const farmMapClick = () => {
+ history.push('/map');
+ closeFloater();
+ };
+ const peopleClick = () => {
+ history.push({
+ pathname: '/people',
+ });
+ closeFloater();
+ };
+ const certificationClick = () => {
+ history.push('/certification');
+ closeFloater();
+ };
+
+ //PureProfileFloater
+ const helpClick = () => {
+ history.push('/help');
+ closeFloater();
+ };
+ const switchFarmClick = () => {
+ history.push('/farm_selection');
+ closeFloater();
+ };
+ const logOutClick = () => {
+ logout();
+ closeFloater();
+ };
+ const myInfoClick = () => {
+ history.push('/profile');
+ closeFloater();
+ };
+ const openTutorialsClick = () => {
+ const playlistIDs = {
+ es: 'PLDRpVZ4VsXJhghxfEQuApFQTeCWUbGBN9',
+ pt: 'PLDRpVZ4VsXJg0ke20m47MmJq6uAJAlAGF',
+ en: 'PLDRpVZ4VsXJgVGrmmXJooNqceXvre8IDY',
+ };
+
+ const playList = playlistIDs[selectedLanguage] || playlistIDs['en'];
+ const url = 'https://www.youtube.com/playlist?list=' + playList;
+
+ const win = window.open(url, '_blank');
+ win.focus();
+ closeFloater();
+ };
+
+ // Pure Notification Floater
+ const notificationTeaserClick = () => {
+ closeFloater();
+ };
+
+ const getLanguageFarmIcon = (language) => {
+ switch (language) {
+ case 'pt':
+ return ;
+ case 'es':
+ return ;
+ case 'fr':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ return (
+
+
+
+
+
+ setIsDrawerOpen(false)}
+ onOpen={() => setIsDrawerOpen(true)}
+ >
+
+
+
+ {showNotification ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+ {getLanguageFarmIcon(selectedLanguage)}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const Logo = ({ history }) => {
+ const theme = useTheme();
+ const matches = useMediaQuery(theme.breakpoints.up('md'));
+ return (
+ history.push('/')}
+ />
+ );
+};
+
+PureNavBar.propTypes = {
+ showSpotLight: PropTypes.bool,
+ resetSpotlight: PropTypes.func,
+ history: PropTypes.object,
+ setDefaultDateRange: PropTypes.func,
+ showFinances: PropTypes.bool,
+ defaultOpenFloater: PropTypes.oneOf(['farm', 'notification', 'profile']),
+};
diff --git a/packages/webapp/src/components/Navigation/NavBar/slideMenu/index.js b/packages/webapp/src/components/Navigation/NavBar/slideMenu/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Navigation/NavBar/slideMenu/index.js
rename to packages/webapp/src/components/Navigation/NavBar/slideMenu/index.jsx
diff --git a/packages/webapp/src/components/Navigation/NoFarmNavBar/index.js b/packages/webapp/src/components/Navigation/NoFarmNavBar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Navigation/NoFarmNavBar/index.js
rename to packages/webapp/src/components/Navigation/NoFarmNavBar/index.jsx
diff --git a/packages/webapp/src/components/NotificationFloater/index.js b/packages/webapp/src/components/NotificationFloater/index.js
deleted file mode 100644
index 56de0ee60b..0000000000
--- a/packages/webapp/src/components/NotificationFloater/index.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import { ReactComponent as NotificationTeaserIcon } from '../../assets/images/notification/NotificationTeaser.svg';
-import { useTranslation } from 'react-i18next';
-import ListOption from '../Navigation/NavBar/ListOption';
-
-import Floater from 'react-floater';
-
-export function PureNotificationFloaterComponent({ notificationTeaser }) {
- const { t } = useTranslation();
- return (
-
- }
- />
-
- );
-}
-
-export default function PureNotificationFloater({
- children,
- openProfile,
- notificationTeaserClick,
-}) {
- return (
- }
- placement={'bottom-end'}
- open={openProfile}
- styles={{
- floater: { zIndex: 1500, display: openProfile ? 'initial' : 'none' },
- }}
- >
- {children}
-
- );
-}
diff --git a/packages/webapp/src/components/Notifications/index.jsx b/packages/webapp/src/components/Notifications/index.jsx
new file mode 100644
index 0000000000..496b6d34e7
--- /dev/null
+++ b/packages/webapp/src/components/Notifications/index.jsx
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import Layout from '../Layout';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../PageTitle/v2';
+import { colors } from '../../assets/theme';
+import Button from '../../components/Form/Button';
+import { Semibold, Text } from '../Typography';
+import { getNotificationCardDate } from '../../util/moment.js';
+import history from '../../history';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+
+function PureNotificationReadOnly({ onGoBack, notification }) {
+ const { t } = useTranslation();
+ const currentLang = getLanguageFromLocalStorage();
+ const tOptions = notification.variables.reduce((optionsSoFar, currentOption) => {
+ let options = { ...optionsSoFar };
+ options[currentOption.name] = currentOption.translate
+ ? t(currentOption.value)
+ : currentOption.value;
+ return options;
+ }, {});
+
+ const hideTakeMeThere =
+ !notification.ref ||
+ (!notification.ref?.url &&
+ (!notification.ref?.entity ||
+ !notification.ref?.entity?.type ||
+ !notification.ref?.entity?.id));
+
+ const onTakeMeThere = () => {
+ const route =
+ notification.ref.url ??
+ `/${notification.ref.entity.type}s/${notification.ref.entity.id}/read_only`;
+ history.push(route, notification.context);
+ };
+
+ return (
+
+
+
+ {getNotificationCardDate(notification.created_at)}
+
+
+
+ {notification.title.translation_key
+ ? t(notification.title.translation_key)
+ : notification.title[currentLang]}
+
+
+ {notification.body.translation_key
+ ? t(notification.body.translation_key, tOptions)
+ : notification.body[currentLang]}
+
+ {!hideTakeMeThere && (
+
+ {t('NOTIFICATION.TAKE_ME_THERE')}
+
+ )}
+
+ );
+}
+
+export default PureNotificationReadOnly;
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.js b/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.js
deleted file mode 100644
index 13e0f96b39..0000000000
--- a/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import React, { useCallback, useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import Input from '../../Form/Input';
-import { useForm } from 'react-hook-form';
-import PageTitle from '../../PageTitle/v2';
-import RadioGroup from '../../Form/RadioGroup';
-
-export function PureCertificationSelection({
- onSubmit,
- certifications,
- onGoBack,
- persistedFormData,
- useHookFormPersist,
- persistedPathNames,
- survey = {},
-}) {
- const { t } = useTranslation(['translation', 'common', 'certifications']);
- const defaultValues = { ...survey, ...persistedFormData };
- const getDefaultCertificationId = useCallback(() => {
- if (defaultValues.certification_id === 0 || defaultValues.certification_id) {
- return defaultValues.certification_id;
- } else if (defaultValues.requested_certification) {
- return 0;
- } else {
- return undefined;
- }
- }, [defaultValues.certification_id, defaultValues.requested_certification]);
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- defaultValues: {
- ...survey,
- ...persistedFormData,
- certification_id: getDefaultCertificationId(),
- },
- });
- useHookFormPersist?.(getValues, persistedPathNames);
- const CERTIFICATION_ID = 'certification_id';
- const certification_id = watch(CERTIFICATION_ID);
- const REQUESTED_CERTIFICATION = 'requested_certification';
- const radioOptions = useMemo(() => {
- const certificationRadioOptions = certifications.map((certification) => ({
- label: t(`certifications:${certification.certification_translation_key}`),
- value: certification.certification_id,
- }));
- return [
- ...certificationRadioOptions,
- {
- label: t('common:OTHER'),
- value: 0,
- toolTipContent:
- certification_id === 0 ? t('CERTIFICATION.CERTIFICATION_SELECTION.TOOLTIP') : undefined,
- },
- ];
- }, [certifications, certification_id]);
- const disabled = !isValid;
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.jsx b/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.jsx
new file mode 100644
index 0000000000..def78bbfb9
--- /dev/null
+++ b/packages/webapp/src/components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection.jsx
@@ -0,0 +1,99 @@
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import React, { useCallback, useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import Input from '../../Form/Input';
+import { useForm } from 'react-hook-form';
+import PageTitle from '../../PageTitle/v2';
+import RadioGroup from '../../Form/RadioGroup';
+
+export function PureCertificationSelection({
+ onSubmit,
+ certifications,
+ onGoBack,
+ persistedFormData,
+ useHookFormPersist,
+ persistedPathNames,
+ survey = {},
+}) {
+ const { t } = useTranslation(['translation', 'common', 'certifications']);
+ const defaultValues = { ...survey, ...persistedFormData };
+ const getDefaultCertificationId = useCallback(() => {
+ if (defaultValues.certification_id === 0 || defaultValues.certification_id) {
+ return defaultValues.certification_id;
+ } else if (defaultValues.requested_certification) {
+ return 0;
+ } else {
+ return undefined;
+ }
+ }, [defaultValues.certification_id, defaultValues.requested_certification]);
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: {
+ ...survey,
+ ...persistedFormData,
+ certification_id: getDefaultCertificationId(),
+ },
+ });
+ useHookFormPersist?.(getValues, persistedPathNames);
+ const CERTIFICATION_ID = 'certification_id';
+ const certification_id = watch(CERTIFICATION_ID);
+ const REQUESTED_CERTIFICATION = 'requested_certification';
+ const radioOptions = useMemo(() => {
+ const certificationRadioOptions = certifications.map((certification) => ({
+ label: t(`certifications:${certification.certification_translation_key}`),
+ value: certification.certification_id,
+ }));
+ return [
+ ...certificationRadioOptions,
+ {
+ label: t('common:OTHER'),
+ value: 0,
+ toolTipContent:
+ certification_id === 0 ? t('CERTIFICATION.CERTIFICATION_SELECTION.TOOLTIP') : undefined,
+ },
+ ];
+ }, [certifications, certification_id]);
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem/index.js b/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem/index.jsx
similarity index 100%
rename from packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem/index.js
rename to packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/CertifierSelectionMenu/CertiferSelectionMenuItem/index.jsx
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.js b/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.js
deleted file mode 100644
index 5c80aaa185..0000000000
--- a/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import Layout from '../../Layout';
-import Button from '../../Form/Button';
-import React, { useMemo, useState } from 'react';
-import PropTypes from 'prop-types';
-import { AddLink, Semibold, Text } from '../../Typography';
-import CertifierSelectionMenuItem from './CertifierSelectionMenu/CertiferSelectionMenuItem';
-import Input from '../../Form/Input';
-import { useTranslation } from 'react-i18next';
-import Infoi from '../../Tooltip/Infoi';
-import PageTitle from '../../PageTitle/v2';
-
-export function PureCertifierSelectionScreen({
- certifiers,
- onBack,
- onSubmit,
- certificationName,
- onRequestCertifier,
- onSelectCertifier,
- certifier_id,
-}) {
- const { t } = useTranslation(['translation', 'common', 'certifications']);
- const [filter, setFilter] = useState();
- const disabled = !certifier_id;
- const isSearchable = certifiers.length >= 2;
-
- const onFilterChange = (e) => {
- setFilter(e.target.value);
- };
-
- const filteredCertifiers = useMemo(() => {
- const results = filter
- ? certifiers.filter(
- (certifier) =>
- certifier.certifier_name.toLowerCase().includes(filter?.toLowerCase()) ||
- certifier.certifier_acronym.toLowerCase().includes(filter?.toLowerCase()),
- )
- : certifiers;
- return results.sort((firstEl, secondEl) => firstEl.certifier_name.localeCompare(secondEl.certifier_name));
- }, [filter, certifiers]);
-
- return (
-
-
- {t('common:PROCEED')}
-
- >
- }
- >
-
-
- {`${t('CERTIFICATION.CERTIFICATION_SELECTION.SUBTITLE_ONE')} ${certificationName} ${t(
- 'CERTIFICATION.CERTIFICATION_SELECTION.SUBTITLE_TWO',
- )}`}
-
-
- {isSearchable && (
-
- )}
- {filteredCertifiers.map((certifier) => {
- return (
- onSelectCertifier(certifier.certifier_id)}
- />
- );
- })}
-
-
- {t('CERTIFICATION.CERTIFIER_SELECTION.NOT_FOUND')}
- {' '}
-
-
-
- {t('CERTIFICATION.CERTIFIER_SELECTION.REQUEST_CERTIFIER')}
-
-
- );
-}
-
-PureCertifierSelectionScreen.prototype = {
- certifiers: PropTypes.arrayOf(
- PropTypes.exact({
- certifierTranslation: PropTypes.string,
- certifier_id: PropTypes.string,
- }),
- ),
- onBack: PropTypes.func,
- onSubmit: PropTypes.func,
- certificationName: PropTypes.string,
- onRequestCertifier: PropTypes.func,
- onSelectCertifier: PropTypes.func,
- certifier_id: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.jsx b/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.jsx
new file mode 100644
index 0000000000..f2f7026564
--- /dev/null
+++ b/packages/webapp/src/components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen.jsx
@@ -0,0 +1,114 @@
+import Layout from '../../Layout';
+import Button from '../../Form/Button';
+import React, { useMemo, useState } from 'react';
+import PropTypes from 'prop-types';
+import { AddLink, Semibold, Text } from '../../Typography';
+import CertifierSelectionMenuItem from './CertifierSelectionMenu/CertiferSelectionMenuItem';
+import Input from '../../Form/Input';
+import { useTranslation } from 'react-i18next';
+import Infoi from '../../Tooltip/Infoi';
+import PageTitle from '../../PageTitle/v2';
+
+export function PureCertifierSelectionScreen({
+ certifiers,
+ onBack,
+ onSubmit,
+ certificationName,
+ onRequestCertifier,
+ onSelectCertifier,
+ certifier_id,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'certifications']);
+ const [filter, setFilter] = useState();
+ const disabled = !certifier_id;
+ const isSearchable = certifiers.length >= 2;
+
+ const onFilterChange = (e) => {
+ setFilter(e.target.value);
+ };
+
+ const filteredCertifiers = useMemo(() => {
+ const results = filter
+ ? certifiers.filter(
+ (certifier) =>
+ certifier.certifier_name.toLowerCase().includes(filter?.toLowerCase()) ||
+ certifier.certifier_acronym.toLowerCase().includes(filter?.toLowerCase()),
+ )
+ : certifiers;
+ return results.sort((firstEl, secondEl) => firstEl.certifier_name.localeCompare(secondEl.certifier_name));
+ }, [filter, certifiers]);
+
+ return (
+
+
+ {t('common:PROCEED')}
+
+ >
+ }
+ >
+
+
+ {`${t('CERTIFICATION.CERTIFICATION_SELECTION.SUBTITLE_ONE')} ${certificationName} ${t(
+ 'CERTIFICATION.CERTIFICATION_SELECTION.SUBTITLE_TWO',
+ )}`}
+
+
+ {isSearchable && (
+
+ )}
+ {filteredCertifiers.map((certifier) => {
+ return (
+ onSelectCertifier(certifier.certifier_id)}
+ />
+ );
+ })}
+
+
+ {t('CERTIFICATION.CERTIFIER_SELECTION.NOT_FOUND')}
+ {' '}
+
+
+
+ {t('CERTIFICATION.CERTIFIER_SELECTION.REQUEST_CERTIFIER')}
+
+
+ );
+}
+
+PureCertifierSelectionScreen.prototype = {
+ certifiers: PropTypes.arrayOf(
+ PropTypes.exact({
+ certifierTranslation: PropTypes.string,
+ certifier_id: PropTypes.string,
+ }),
+ ),
+ onBack: PropTypes.func,
+ onSubmit: PropTypes.func,
+ certificationName: PropTypes.string,
+ onRequestCertifier: PropTypes.func,
+ onSelectCertifier: PropTypes.func,
+ certifier_id: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.js b/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.js
deleted file mode 100644
index 6c8e6cbfc0..0000000000
--- a/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import Form from '../../Form';
-import Button from '../../Form/Button';
-import { Label, Main } from '../../Typography';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PureWarningBox from '../../WarningBox';
-import { useForm } from 'react-hook-form';
-import RadioGroup from '../../Form/RadioGroup';
-import PageTitle from '../../PageTitle/v2';
-
-export function PureInterestedOrganic({
- onSubmit,
- onGoBack,
- survey = {},
- persistedFormData,
- useHookFormPersist,
- persistedPathNames,
-}) {
- const { t } = useTranslation(['translation', 'common']);
- const {
- handleSubmit,
- control,
- getValues,
- formState: { isValid },
- } = useForm({ mode: 'onChange', defaultValues: { ...survey, ...persistedFormData } });
- useHookFormPersist?.(getValues, persistedPathNames);
- const INTERESTED = 'interested';
- const disabled = !isValid;
- const title = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.TITLE');
- const paragraph = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.PARAGRAPH');
- const content = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.WHY_ANSWER');
- return (
-
- );
-}
-
-PureInterestedOrganic.prototype = {
- onSubmit: PropTypes.func,
- onGoBack: PropTypes.func,
- survey: PropTypes.shape({
- certification_id: PropTypes.number,
- certifier_id: PropTypes.number,
- farm_id: PropTypes.string,
- interested: PropTypes.bool,
- requested_certification: PropTypes.string,
- requested_certifier: PropTypes.string,
- survey_id: PropTypes.number,
- }),
- persistedFormData: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- persistedPathNames: PropTypes.arrayOf(PropTypes.string),
-};
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.jsx b/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.jsx
new file mode 100644
index 0000000000..68c277b86a
--- /dev/null
+++ b/packages/webapp/src/components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic.jsx
@@ -0,0 +1,67 @@
+import Form from '../../Form';
+import Button from '../../Form/Button';
+import { Main } from '../../Typography';
+import PropTypes from 'prop-types';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { useForm } from 'react-hook-form';
+import RadioGroup from '../../Form/RadioGroup';
+import PageTitle from '../../PageTitle/v2';
+
+export function PureInterestedOrganic({
+ onSubmit,
+ onGoBack,
+ survey = {},
+ persistedFormData,
+ useHookFormPersist,
+ persistedPathNames,
+}) {
+ const { t } = useTranslation(['translation', 'common']);
+ const {
+ handleSubmit,
+ control,
+ getValues,
+ formState: { isValid },
+ } = useForm({ mode: 'onChange', defaultValues: { ...survey, ...persistedFormData } });
+ useHookFormPersist?.(getValues, persistedPathNames);
+ const INTERESTED = 'interested';
+ const disabled = !isValid;
+ const title = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.TITLE');
+ const paragraph = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.PARAGRAPH');
+ const content = t('CERTIFICATION.INTERESTED_IN_CERTIFICATION.WHY_ANSWER');
+ return (
+
+ );
+}
+
+PureInterestedOrganic.prototype = {
+ onSubmit: PropTypes.func,
+ onGoBack: PropTypes.func,
+ survey: PropTypes.shape({
+ certification_id: PropTypes.number,
+ certifier_id: PropTypes.number,
+ farm_id: PropTypes.string,
+ interested: PropTypes.bool,
+ requested_certification: PropTypes.string,
+ requested_certifier: PropTypes.string,
+ survey_id: PropTypes.number,
+ }),
+ persistedFormData: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ persistedPathNames: PropTypes.arrayOf(PropTypes.string),
+};
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier.js b/packages/webapp/src/components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier.jsx
similarity index 100%
rename from packages/webapp/src/components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier.js
rename to packages/webapp/src/components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier.jsx
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.js b/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.js
deleted file mode 100644
index 6d026cf339..0000000000
--- a/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import Button from '../../Form/Button';
-import React from 'react';
-import { Main, Semibold, Text } from '../../Typography';
-import { useTranslation } from 'react-i18next';
-import Layout from '../../Layout';
-import Farmland from '../../../assets/images/certification/Farmland.svg';
-import { colors } from '../../../assets/theme';
-import PageTitle from '../../PageTitle/v2';
-
-export function PureSetCertificationSummary({
- onSubmit,
- certificationName,
- onGoBack,
- certifierName,
- isRequestedCertifier,
-}) {
- const { t } = useTranslation(['translation', 'common', 'certifications']);
- return (
-
-
- {t('common:CONTINUE')}
-
- >
- }
- >
-
-
- {t('CERTIFICATION.SUMMARY.TITLE')}
-
- {`${certificationName} ${t('CERTIFICATION.SUMMARY.CERTIFICATION')} ${t(
- 'common:FROM',
- )} ${certifierName} `}
-
-
-
-
-
-
- {isRequestedCertifier
- ? t('CERTIFICATION.SUMMARY.BAD_NEWS')
- : t('CERTIFICATION.SUMMARY.GOOD_NEWS')}
-
-
- {isRequestedCertifier
- ? t('CERTIFICATION.SUMMARY.BAD_NEWS_INFO')
- : t('CERTIFICATION.SUMMARY.INFORMATION')}
-
-
- );
-}
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.jsx b/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.jsx
new file mode 100644
index 0000000000..1e70436634
--- /dev/null
+++ b/packages/webapp/src/components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary.jsx
@@ -0,0 +1,57 @@
+import Button from '../../Form/Button';
+import React from 'react';
+import { Main, Semibold, Text } from '../../Typography';
+import { useTranslation } from 'react-i18next';
+import Layout from '../../Layout';
+import Farmland from '../../../assets/images/certification/Farmland.svg';
+import { colors } from '../../../assets/theme';
+import PageTitle from '../../PageTitle/v2';
+
+export function PureSetCertificationSummary({
+ onSubmit,
+ certificationName,
+ onGoBack,
+ certifierName,
+ isRequestedCertifier,
+}) {
+ const { t } = useTranslation(['translation', 'common', 'certifications']);
+ return (
+
+
+ {t('common:CONTINUE')}
+
+ >
+ }
+ >
+
+
+ {t('CERTIFICATION.SUMMARY.TITLE')}
+
+ {`${certificationName} ${t('CERTIFICATION.SUMMARY.CERTIFICATION')} ${t(
+ 'common:FROM',
+ )} ${certifierName} `}
+
+
+
+
+
+
+ {isRequestedCertifier
+ ? t('CERTIFICATION.SUMMARY.BAD_NEWS')
+ : t('CERTIFICATION.SUMMARY.GOOD_NEWS')}
+
+
+ {isRequestedCertifier
+ ? t('CERTIFICATION.SUMMARY.BAD_NEWS_INFO')
+ : t('CERTIFICATION.SUMMARY.INFORMATION')}
+
+
+ );
+}
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification/index.js b/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification/index.jsx
similarity index 100%
rename from packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification/index.js
rename to packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification/index.jsx
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification/index.js b/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification/index.jsx
similarity index 100%
rename from packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification/index.js
rename to packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification/index.jsx
diff --git a/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification/index.js b/packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification/index.jsx
similarity index 100%
rename from packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification/index.js
rename to packages/webapp/src/components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification/index.jsx
diff --git a/packages/webapp/src/components/Outro/index.js b/packages/webapp/src/components/Outro/index.js
deleted file mode 100644
index 15055d3b64..0000000000
--- a/packages/webapp/src/components/Outro/index.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import Layout from '../Layout';
-import Button from '../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../Typography';
-import { ReactComponent } from '../../assets/images/outro/outro.svg';
-import PageTitle from '../PageTitle/v2';
-
-export default function PureOutroSplash({ onContinue, onGoBack, toShowSpotlight }) {
- const { t } = useTranslation(['translation', 'common']);
- return (
-
- {t('common:FINISH')}
-
- }
- >
-
-
-
-
-
-
- {toShowSpotlight ? t('OUTRO.IMPORTANT_THINGS') : t('OUTRO.ALL_DONE')}
-
-
-
- );
-}
-
-PureOutroSplash.prototype = {
- onClick: PropTypes.func,
- text: PropTypes.string,
- showSpotLight: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Outro/index.jsx b/packages/webapp/src/components/Outro/index.jsx
new file mode 100644
index 0000000000..5fc9b7381b
--- /dev/null
+++ b/packages/webapp/src/components/Outro/index.jsx
@@ -0,0 +1,53 @@
+import Layout from '../Layout';
+import Button from '../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../Typography';
+import { ReactComponent } from '../../assets/images/outro/outro.svg';
+import PageTitle from '../PageTitle/v2';
+
+export default function PureOutroSplash({ onContinue, onGoBack, toShowSpotlight }) {
+ const { t } = useTranslation(['translation', 'common']);
+ return (
+
+ {t('common:FINISH')}
+
+ }
+ >
+
+
+
+
+
+
+ {toShowSpotlight ? t('OUTRO.IMPORTANT_THINGS') : t('OUTRO.ALL_DONE')}
+
+
+
+ );
+}
+
+PureOutroSplash.prototype = {
+ onClick: PropTypes.func,
+ text: PropTypes.string,
+ showSpotLight: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/PageBreak/index.js b/packages/webapp/src/components/PageBreak/index.jsx
similarity index 100%
rename from packages/webapp/src/components/PageBreak/index.js
rename to packages/webapp/src/components/PageBreak/index.jsx
diff --git a/packages/webapp/src/components/PageTitle/CancelButton.js b/packages/webapp/src/components/PageTitle/CancelButton.jsx
similarity index 100%
rename from packages/webapp/src/components/PageTitle/CancelButton.js
rename to packages/webapp/src/components/PageTitle/CancelButton.jsx
diff --git a/packages/webapp/src/components/PageTitle/MultiStepPageTitle/index.js b/packages/webapp/src/components/PageTitle/MultiStepPageTitle/index.jsx
similarity index 100%
rename from packages/webapp/src/components/PageTitle/MultiStepPageTitle/index.js
rename to packages/webapp/src/components/PageTitle/MultiStepPageTitle/index.jsx
diff --git a/packages/webapp/src/components/PageTitle/index.js b/packages/webapp/src/components/PageTitle/index.jsx
similarity index 100%
rename from packages/webapp/src/components/PageTitle/index.js
rename to packages/webapp/src/components/PageTitle/index.jsx
diff --git a/packages/webapp/src/components/PageTitle/v2/index.js b/packages/webapp/src/components/PageTitle/v2/index.js
deleted file mode 100644
index 8696a00661..0000000000
--- a/packages/webapp/src/components/PageTitle/v2/index.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { EditLink, Title } from '../../Typography';
-import React from 'react';
-import styles from './styles.module.scss';
-import { BsChevronLeft } from 'react-icons/bs';
-import PropTypes from 'prop-types';
-import { CancelButton } from '../CancelButton';
-
-function PageTitle({
- title,
- onGoBack,
- onCancel,
- onEdit,
- style,
- cancelModalTitle,
- editLink,
- label,
-}) {
- return (
-
-
- {onGoBack && (
-
-
-
- )}
-
{title}
-
- {!!onEdit && (
-
- {' '}
- {editLink}{' '}
-
- )}
- {!!onCancel &&
}
- {label}
-
- );
-}
-
-export default PageTitle;
-PageTitle.prototype = {
- title: PropTypes.string,
- onGoBack: PropTypes.func,
- onCancel: PropTypes.func,
- style: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/PageTitle/v2/index.jsx b/packages/webapp/src/components/PageTitle/v2/index.jsx
new file mode 100644
index 0000000000..5242c4f183
--- /dev/null
+++ b/packages/webapp/src/components/PageTitle/v2/index.jsx
@@ -0,0 +1,33 @@
+import { Title } from '../../Typography';
+import React from 'react';
+import styles from './styles.module.scss';
+import { BsChevronLeft } from 'react-icons/bs';
+import PropTypes from 'prop-types';
+import { CancelButton } from '../CancelButton';
+
+function PageTitle({ title, onGoBack, onCancel, style, cancelModalTitle, label }) {
+ return (
+
+
+ {onGoBack && (
+
+
+
+ )}
+
+ {title.length > 77 ? `${title.substring(0, 77).trim()}...` : title}
+
+
+ {!!onCancel &&
}
+ {label}
+
+ );
+}
+
+export default PageTitle;
+PageTitle.prototype = {
+ title: PropTypes.string,
+ onGoBack: PropTypes.func,
+ onCancel: PropTypes.func,
+ style: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/PageTitleFragment/index.js b/packages/webapp/src/components/PageTitleFragment/index.jsx
similarity index 100%
rename from packages/webapp/src/components/PageTitleFragment/index.js
rename to packages/webapp/src/components/PageTitleFragment/index.jsx
diff --git a/packages/webapp/src/components/PasswordResetAccount/index.js b/packages/webapp/src/components/PasswordResetAccount/index.js
deleted file mode 100644
index cf671b5f06..0000000000
--- a/packages/webapp/src/components/PasswordResetAccount/index.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import Input from '../Form/Input';
-import React from 'react';
-import { Title } from '../Typography';
-import PropTypes from 'prop-types';
-import { useForm } from 'react-hook-form';
-import { validatePasswordWithErrors } from '../Signup/utils';
-import { PasswordError } from '../Form/Errors';
-import { useTranslation } from 'react-i18next';
-
-export default function PureResetPasswordAccount({ email, update }) {
- const { register, handleSubmit, watch } = useForm();
- const PASSWORD = 'password';
- const password = watch(PASSWORD, undefined);
- const { t } = useTranslation();
- const title = t('PASSWORD_RESET.NEW_ACCOUNT_TITLE');
- const {
- isValid,
- hasNoSymbol,
- hasNoDigit,
- hasNoUpperCase,
- isTooShort,
- } = validatePasswordWithErrors(password);
- const inputRegister = register(PASSWORD, { validate: () => isValid });
-
- const disabled = !isValid;
-
- const onSubmit = (data) => {
- if (isValid) {
- update(data);
- }
- };
- const onError = (data) => {};
-
- return (
-
- );
-}
-
-PureResetPasswordAccount.prototype = {
- onLogin: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/PasswordResetAccount/index.jsx b/packages/webapp/src/components/PasswordResetAccount/index.jsx
new file mode 100644
index 0000000000..a9bc52d732
--- /dev/null
+++ b/packages/webapp/src/components/PasswordResetAccount/index.jsx
@@ -0,0 +1,68 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import Input from '../Form/Input';
+import React from 'react';
+import { Title } from '../Typography';
+import PropTypes from 'prop-types';
+import { useForm } from 'react-hook-form';
+import { validatePasswordWithErrors } from '../Signup/utils';
+import { PasswordError } from '../Form/Errors';
+import { useTranslation } from 'react-i18next';
+
+export default function PureResetPasswordAccount({ email, update }) {
+ const { register, handleSubmit, watch } = useForm();
+ const PASSWORD = 'password';
+ const password = watch(PASSWORD, undefined);
+ const { t } = useTranslation();
+ const title = t('PASSWORD_RESET.NEW_ACCOUNT_TITLE');
+ const { isValid, hasNoSymbol, hasNoDigit, hasNoUpperCase, isTooShort } =
+ validatePasswordWithErrors(password);
+ const inputRegister = register(PASSWORD, { validate: () => isValid });
+
+ const disabled = !isValid;
+
+ const onSubmit = (data) => {
+ if (isValid) {
+ update(data);
+ }
+ };
+ const onError = (data) => {};
+
+ return (
+
+ );
+}
+
+PureResetPasswordAccount.prototype = {
+ onLogin: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.js b/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.js
deleted file mode 100644
index dd0bfd118d..0000000000
--- a/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { FiFilter } from 'react-icons/all';
-import Input from '../../Form/Input';
-import { makeStyles } from '@material-ui/core/styles';
-import { colors } from '../../../assets/theme';
-import Pill from '../../Filter/Pill';
-import PropTypes from 'prop-types';
-
-const useStyles = makeStyles({
- container: {
- display: 'flex',
- gap: '16px',
- position: 'relative',
- alignItems: 'center',
- paddingBottom: '16px',
- },
- circle: {
- position: 'absolute',
- right: 0,
- width: '4px',
- height: '4px',
- borderRadius: '2px',
- backgroundColor: colors.teal700,
- transform: 'translate(-9px, -14px)',
- },
- filter: {
- fontSize: '24px',
- color: colors.grey600,
- cursor: 'pointer',
- },
- pillContainer: {
- paddingBottom: '16px',
- flexWrap: 'wrap',
- display: 'flex',
- gap: '16px',
- },
-});
-
-export default function PureSearchbarAndFilter({ onFilterOpen, value, onChange, isFilterActive }) {
- const classes = useStyles();
- return (
- <>
-
-
- {isFilterActive &&
}
-
-
- >
- );
-}
-
-PureSearchbarAndFilter.propTypes = {
- onFilterOpen: PropTypes.func,
- value: PropTypes.string,
- onChange: PropTypes.func,
- isFilterActive: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.jsx b/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.jsx
new file mode 100644
index 0000000000..726244dde7
--- /dev/null
+++ b/packages/webapp/src/components/PopupFilter/PureSearchbarAndFilter/index.jsx
@@ -0,0 +1,71 @@
+import { FiFilter } from 'react-icons/all';
+import Input from '../../Form/Input';
+import { makeStyles } from '@material-ui/core/styles';
+import { colors } from '../../../assets/theme';
+import PropTypes from 'prop-types';
+
+const useStyles = makeStyles({
+ container: {
+ display: 'flex',
+ gap: '16px',
+ position: 'relative',
+ alignItems: 'center',
+ paddingBottom: '16px',
+ },
+ circle: {
+ position: 'absolute',
+ right: 0,
+ width: '4px',
+ height: '4px',
+ borderRadius: '2px',
+ backgroundColor: colors.teal700,
+ transform: 'translate(-9px, -14px)',
+ },
+ filter: {
+ fontSize: '24px',
+ color: colors.grey600,
+ cursor: 'pointer',
+ },
+ pillContainer: {
+ paddingBottom: '16px',
+ flexWrap: 'wrap',
+ display: 'flex',
+ gap: '16px',
+ },
+});
+
+export default function PureSearchbarAndFilter({
+ onFilterOpen,
+ value,
+ onChange,
+ isFilterActive,
+ disableFilter = false,
+}) {
+ const classes = useStyles();
+ return (
+ <>
+
+
+ {!disableFilter && (
+ <>
+ {isFilterActive &&
}
+
+ >
+ )}
+
+ >
+ );
+}
+
+PureSearchbarAndFilter.propTypes = {
+ onFilterOpen: PropTypes.func,
+ value: PropTypes.string,
+ onChange: PropTypes.func,
+ isFilterActive: PropTypes.bool,
+ disableFilter: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/index.jsx b/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/index.jsx
new file mode 100644
index 0000000000..c16cc5f1df
--- /dev/null
+++ b/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/index.jsx
@@ -0,0 +1,131 @@
+import { FiFilter } from 'react-icons/all';
+import { colors } from '../../../assets/theme';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { useState } from 'react';
+import styles from './styles.module.scss';
+import { BsChevronDown } from 'react-icons/bs';
+import { Main, Semibold } from '../../Typography';
+import Radio from '../../Form/Radio';
+import { ReactComponent as CalendarDown } from '../../../assets/images/taskFilter/CalendarDown.svg';
+import { ReactComponent as CalendarUp } from '../../../assets/images/taskFilter/CalendarUp.svg';
+import clsx from 'clsx';
+import PageBreak from '../../PageBreak';
+import { ClickAwayListener } from '@material-ui/core';
+
+export default function PureTaskDropdownFilter({
+ isDropDownOpen,
+ isAscending,
+ onDateOrderChange,
+ assigneeValue,
+ onAssigneeChange,
+ isFilterActive,
+ onFilterOpen,
+}) {
+ const { t } = useTranslation();
+ const [isDropdownOpen, setDropdownOpen] = useState(isDropDownOpen);
+ const onDropdownClick = () => setDropdownOpen((isDropdownOpen) => !isDropdownOpen);
+ const assigneeTranslationMap = {
+ myTask: t('TASK.FILTER.MY_TASK'),
+ unassigned: t('TASK.FILTER.UNASSIGNED'),
+ all: t('common:ALL'),
+ };
+ return (
+ setDropdownOpen(false)}>
+
+
+
+ {assigneeTranslationMap[assigneeValue] && (
+ <>
+ {t('TASK.FILTER.VIEW')}:
+
+ {assigneeTranslationMap[assigneeValue]}
+
+ >
+ )}
+ {isAscending ? : }
+
+
+
+ {isDropdownOpen && (
+
+
+
{t('TASK.FILTER.VIEW')}:
+
+
+
+
+
{t('TASK.FILTER.SORT_BY')}:
+
+
+ {t('common:DATE')}: {t('TASK.FILTER.ASCENDING')}
+ >
+ }
+ name={'date'}
+ value={'ascending'}
+ onChange={onDateOrderChange}
+ />
+
+
+
+
+ {t('common:DATE')}: {t('TASK.FILTER.DESCENDING')}
+ >
+ }
+ name={'date'}
+ value={'descending'}
+ onChange={onDateOrderChange}
+ />
+
+
+
+
+ )}
+
+ {isFilterActive &&
}
+
+
+
+ );
+}
+
+PureTaskDropdownFilter.propTypes = {
+ onFilterOpen: PropTypes.func,
+ value: PropTypes.string,
+ onChange: PropTypes.func,
+ isFilterActive: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/styles.module.scss b/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/styles.module.scss
new file mode 100644
index 0000000000..352e8ff150
--- /dev/null
+++ b/packages/webapp/src/components/PopupFilter/PureTaskDropdownFilter/styles.module.scss
@@ -0,0 +1,97 @@
+@import '../../../assets/mixin';
+
+.container {
+ display: flex;
+ gap: 16px;
+ position: relative;
+ align-items: center;
+ padding-bottom: 16px;
+}
+
+
+
+.circle {
+ position: absolute;
+ right: 0;
+ width: 4px;
+ height: 4px;
+ border-radius: 2px;
+ background-color: var(--teal700);
+ transform: translate(-7px, -11px);
+}
+.filter{
+ font-size: 18px;
+ color: var(--grey600);
+ cursor: pointer;
+}
+.pillContainer{
+ padding-bottom: 16px;
+ flex-wrap: wrap;
+ display: flex;
+ gap: 16px;
+}
+.dropdownContainer{
+ flex-direction: row;
+ flex-grow: 1;
+ display: flex;
+ position: relative;
+ z-index: 1;
+}
+.dropdown{
+ z-index: 2;
+ flex-direction: row;
+ flex-grow: 1;
+ display: flex;
+ column-gap: 8px;
+ position: relative;
+ border: 1px solid var(--grey400);
+ border-radius: 4px;
+ height: 32px;
+ line-height: 24px;
+ align-items: center;
+ cursor: pointer;
+ user-select: none;
+ padding: 0 8px;
+
+}
+
+.dropdownMenu{
+ padding: 12px;
+ border: 1px solid var(--grey400);
+ border-radius: 0 0 4px 4px;
+
+ display: flex;
+ flex-grow: 1;
+ flex-direction: column;
+ width: 100%;
+ top: 31px;
+ background-color: white;
+}
+.dropdownMenuContainer{
+ padding-top: 31px;
+ position: absolute;
+ width: 100%;
+ @include midShadow();
+}
+.chevron{
+ color: var(--grey600);
+ position: absolute;
+ right: 12px;
+ font-size: 16px;
+}
+.chevronActive{
+ transform: scaleY(-1);
+}
+.active{
+ border-color: var(--inputActive);
+}
+.dropDownActive{
+ border-radius: 4px 4px 0 0;
+}
+.dateRadioContainer{
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+}
+
diff --git a/packages/webapp/src/components/Profile/Account/index.js b/packages/webapp/src/components/Profile/Account/index.js
deleted file mode 100644
index a8d5aeec49..0000000000
--- a/packages/webapp/src/components/Profile/Account/index.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import Input, { integerOnKeyDown } from '../../Form/Input';
-import { Controller, useForm } from 'react-hook-form';
-import { userFarmEnum } from '../../../containers/constants';
-import ReactSelect from '../../Form/ReactSelect';
-import { useTranslation } from 'react-i18next';
-import React, { useMemo } from 'react';
-import Button from '../../Form/Button';
-import PropTypes from 'prop-types';
-import ProfileLayout from '../ProfileLayout';
-import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
-
-export default function PureAccount({ userFarm, onSubmit }) {
- const getDefaultValues = () => {
- const defaultValues = {};
- defaultValues[userFarmEnum.first_name] = userFarm.first_name;
- defaultValues[userFarmEnum.last_name] = userFarm.last_name;
- defaultValues[userFarmEnum.email] = userFarm.email;
- defaultValues[userFarmEnum.phone_number] = userFarm.phone_number;
- defaultValues[userFarmEnum.user_address] = userFarm.user_address;
- return defaultValues;
- };
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- control,
- formState: { isValid, isDirty },
- } = useForm({
- mode: 'onChange',
- defaultValues: getDefaultValues(),
- });
- const disabled = !isDirty || !isValid;
-
- const options = [
- { label: t('PROFILE.ACCOUNT.ENGLISH'), value: 'en' },
- { label: t('PROFILE.ACCOUNT.SPANISH'), value: 'es' },
- { label: t('PROFILE.ACCOUNT.PORTUGUESE'), value: 'pt' },
- { label: t('PROFILE.ACCOUNT.FRENCH'), value: 'fr' },
- ];
- const language_preference = getLanguageFromLocalStorage();
- const defaultLanguageOption = useMemo(() => {
- for (const option of options) {
- if (language_preference.includes(option.value)) return option;
- }
- }, [language_preference]);
- return (
-
- {t('common:SAVE')}
-
- }
- >
-
-
-
-
-
-
- (
-
- )}
- />
-
- );
-}
-PureAccount.propTypes = {
- userFarm: PropTypes.shape({
- first_name: PropTypes.string,
- last_name: PropTypes.string,
- email: PropTypes.string,
- phone_number: PropTypes.string,
- user_address: PropTypes.string,
- }).isRequired,
- onSubmit: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Profile/Account/index.jsx b/packages/webapp/src/components/Profile/Account/index.jsx
new file mode 100644
index 0000000000..e0dc967c1f
--- /dev/null
+++ b/packages/webapp/src/components/Profile/Account/index.jsx
@@ -0,0 +1,109 @@
+import Input, { integerOnKeyDown } from '../../Form/Input';
+import { Controller, useForm } from 'react-hook-form';
+import { userFarmEnum } from '../../../containers/constants';
+import ReactSelect from '../../Form/ReactSelect';
+import { useTranslation } from 'react-i18next';
+import React, { useEffect, useRef } from 'react';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+import ProfileLayout from '../ProfileLayout';
+
+const useLanguageOptions = (language_preference) => {
+ const { t } = useTranslation();
+ const languageOptionMap = {
+ en: { label: t('PROFILE.ACCOUNT.ENGLISH'), value: 'en' },
+ es: { label: t('PROFILE.ACCOUNT.SPANISH'), value: 'es' },
+ pt: { label: t('PROFILE.ACCOUNT.PORTUGUESE'), value: 'pt' },
+ fr: { label: t('PROFILE.ACCOUNT.FRENCH'), value: 'fr' },
+ };
+ const languageOptions = Object.values(languageOptionMap);
+ const languagePreferenceOptionRef = useRef();
+ languagePreferenceOptionRef.current = languageOptionMap[language_preference];
+ return { languageOptionMap, languageOptions, languagePreferenceOptionRef };
+};
+
+export default function PureAccount({ userFarm, onSubmit, history, isAdmin }) {
+ const { languageOptions, languagePreferenceOptionRef } = useLanguageOptions(
+ userFarm.language_preference,
+ );
+ const { t } = useTranslation();
+ const {
+ register,
+ handleSubmit,
+ control,
+ setValue,
+ formState: { isValid, isDirty },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: userFarm,
+ shouldUnregister: true,
+ });
+ useEffect(() => {
+ setValue(userFarmEnum.language_preference, null, { shouldValidate: false, shouldDirty: false });
+ setTimeout(() => {
+ setValue(userFarmEnum.language_preference, languagePreferenceOptionRef.current, {
+ shouldValidate: false,
+ shouldDirty: false,
+ });
+ }, 100);
+ }, [userFarm.language_preference]);
+ const disabled = !isDirty || !isValid;
+ return (
+
+ {t('common:SAVE')}
+
+ }
+ >
+
+
+
+
+ (
+
+ )}
+ />
+
+
+ );
+}
+PureAccount.propTypes = {
+ userFarm: PropTypes.shape({
+ first_name: PropTypes.string,
+ last_name: PropTypes.string,
+ email: PropTypes.string,
+ phone_number: PropTypes.string,
+ user_address: PropTypes.string,
+ }).isRequired,
+ onSubmit: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Profile/EditUser/index.jsx b/packages/webapp/src/components/Profile/EditUser/index.jsx
new file mode 100644
index 0000000000..5b3ce0d0a7
--- /dev/null
+++ b/packages/webapp/src/components/Profile/EditUser/index.jsx
@@ -0,0 +1,135 @@
+import Input, { getInputErrors } from '../../Form/Input';
+import { Controller, useForm } from 'react-hook-form';
+import ReactSelect from '../../Form/ReactSelect';
+import { useTranslation } from 'react-i18next';
+import React, { useState } from 'react';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+import Form from '../../Form';
+import PageTitle from '../../PageTitle/v2';
+import RevokeUserAccessModal from '../../Modals/RevokeUserAccessModal';
+import Checkbox from '../../Form/Checkbox';
+
+export default function PureEditUser({ userFarm, onUpdate, history, isAdmin, onActivate, onRevoke, onInvite }) {
+ const { t } = useTranslation();
+ const ROLE = 'role_id';
+ const WAGE = 'wage.amount';
+ const EMAIL = 'email';
+ const dropDownMap = {
+ 1: t('role:OWNER'),
+ 2: t('role:MANAGER'),
+ 3: t('role:WORKER'),
+ 5: t('role:EXTENSION_OFFICER'),
+ };
+ const roleOptions = Object.keys(dropDownMap).map(role_id => ({ value: role_id, label: dropDownMap[role_id] }));
+ const roleOption = { value: userFarm.role_id, label: dropDownMap[userFarm.role_id] };
+
+ const {
+ register,
+ handleSubmit,
+ control,
+ setValue,
+ watch,
+ clearErrors,
+ formState: { isValid, isDirty, errors },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: { ...userFarm, role_id: roleOption },
+ shouldUnregister: true,
+ });
+
+
+ const [showRevokeUserAccessModal, setShowRevokeUserAccessModal] = useState();
+ const isPseudoUser = userFarm.role_id === 4;
+ const [shouldInvitePseudoUser, setShouldInvitePseudoUser] = useState(false);
+ const onInviteUserCheckboxClick = () => {
+ setValue(EMAIL, shouldInvitePseudoUser ? userFarm.email : '');
+ setShouldInvitePseudoUser(shouldInvitePseudoUser => !shouldInvitePseudoUser);
+ clearErrors(EMAIL);
+ };
+ const email = watch(EMAIL);
+ const role = watch(ROLE);
+ const wage = watch(WAGE);
+ const disabled = !isValid || (shouldInvitePseudoUser && (!email || !role?.label)) || (!shouldInvitePseudoUser && !isPseudoUser && Number(role?.value) === userFarm.role_id && (wage || 0) === Number(userFarm.wage?.amount))
+ || (!shouldInvitePseudoUser && isPseudoUser && (wage || 0) === Number(userFarm.wage?.amount));
+
+ return (
+
+ );
+}
+PureEditUser.propTypes = {
+ userFarm: PropTypes.object,
+
+ onSubmit: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Profile/EditUser/styles.module.scss b/packages/webapp/src/components/Profile/EditUser/styles.module.scss
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/webapp/src/components/Profile/Farm/index.js b/packages/webapp/src/components/Profile/Farm/index.js
deleted file mode 100644
index c7ef4b19ea..0000000000
--- a/packages/webapp/src/components/Profile/Farm/index.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import Input, { integerOnKeyDown } from '../../Form/Input';
-import { Controller, useForm } from 'react-hook-form';
-import { userFarmEnum } from '../../../containers/constants';
-import ReactSelect from '../../Form/ReactSelect';
-import { useTranslation } from 'react-i18next';
-import React from 'react';
-import Button from '../../Form/Button';
-import PropTypes from 'prop-types';
-import ProfileLayout from '../ProfileLayout';
-import useDefaultOption from '../../Form/useDefaultOption';
-
-export default function PureFarm({ userFarm, onSubmit }) {
- const MEASUREMENT = 'measurement';
- const CURRENCY = 'currency';
- const getDefaultValues = () => {
- const defaultValues = {};
- defaultValues[userFarmEnum.farm_name] = userFarm.farm_name;
- defaultValues[userFarmEnum.farm_phone_number] = userFarm.farm_phone_number;
- defaultValues[userFarmEnum.address] = userFarm.address;
- defaultValues[CURRENCY] = userFarm.units.currency;
- return defaultValues;
- };
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- control,
- formState: { isValid, isDirty },
- } = useForm({
- mode: 'onChange',
- defaultValues: getDefaultValues(),
- });
-
- const disabled = !isDirty || !isValid;
-
- const options = [
- { label: t('PROFILE.FARM.METRIC'), value: 'metric' },
- { label: t('PROFILE.FARM.IMPERIAL'), value: 'imperial' },
- ];
- const defaultMeasurementOption = useDefaultOption(options, userFarm.units.measurement);
- return (
-
- {t('common:SAVE')}
-
- }
- >
-
-
-
- (
-
- )}
- />
-
-
- );
-}
-PureFarm.propTypes = {
- userFarm: PropTypes.shape({
- farm_name: PropTypes.string,
- farm_phone_number: PropTypes.string,
- address: PropTypes.string,
- units: PropTypes.shape({
- measurement: PropTypes.string,
- currency: PropTypes.string,
- }),
- }).isRequired,
- onSubmit: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Profile/Farm/index.jsx b/packages/webapp/src/components/Profile/Farm/index.jsx
new file mode 100644
index 0000000000..0977e2877e
--- /dev/null
+++ b/packages/webapp/src/components/Profile/Farm/index.jsx
@@ -0,0 +1,89 @@
+import Input, { integerOnKeyDown } from '../../Form/Input';
+import { Controller, useForm } from 'react-hook-form';
+import { userFarmEnum } from '../../../containers/constants';
+import ReactSelect from '../../Form/ReactSelect';
+import { useTranslation } from 'react-i18next';
+import React from 'react';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+import ProfileLayout from '../ProfileLayout';
+
+export default function PureFarm({ userFarm, onSubmit, history, isAdmin }) {
+ const MEASUREMENT = 'units.measurement';
+ const { t } = useTranslation();
+
+ const measurementOptionMap = {
+ metric: { label: t('PROFILE.FARM.METRIC'), value: 'metric' },
+ imperial: { label: t('PROFILE.FARM.IMPERIAL'), value: 'imperial' },
+ };
+ const options = Object.values(measurementOptionMap);
+ const defaultMeasurementOption = measurementOptionMap[userFarm.units.measurement];
+ const {
+ register,
+ handleSubmit,
+ control,
+ formState: { isValid, isDirty },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: { ...userFarm, units: { measurement: defaultMeasurementOption } },
+ shouldUnregister: true,
+ });
+ const disabled = !isDirty || !isValid;
+
+ return (
+
+ {t('common:SAVE')}
+
+ }
+ >
+
+
+
+ (
+
+ )}
+ />
+
+
+ );
+}
+PureFarm.propTypes = {
+ userFarm: PropTypes.shape({
+ farm_name: PropTypes.string,
+ farm_phone_number: PropTypes.string,
+ address: PropTypes.string,
+ units: PropTypes.shape({
+ measurement: PropTypes.string,
+ currency: PropTypes.string,
+ }),
+ }).isRequired,
+ onSubmit: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Profile/People/index.js b/packages/webapp/src/components/Profile/People/index.js
deleted file mode 100644
index 6c0e2604e6..0000000000
--- a/packages/webapp/src/components/Profile/People/index.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import Input from '../../Form/Input';
-import { useTranslation } from 'react-i18next';
-import React, { useState } from 'react';
-import Button from '../../Form/Button';
-import PropTypes from 'prop-types';
-import { Tab, Tabs } from '@material-ui/core';
-import Table from '../../Table';
-import styles from './styles.module.scss';
-
-export default function PurePeople({ users, history, isAdmin }) {
- const { t } = useTranslation();
- const [searchString, setSearchString] = useState('');
- const onChange = (e) => {
- setSearchString(e.target.value);
- };
- const summaryColumns = [
- {
- id: 'name',
- Header: t(`PROFILE.TABLE.HEADER_NAME`),
- accessor: 'name',
- minWidth: 70,
- },
- {
- id: 'email',
- Header: t(`PROFILE.TABLE.HEADER_EMAIL`),
- accessor: 'email',
- minWidth: 95,
- style: { whiteSpace: 'unset' },
- },
- {
- id: 'role',
- Header: t(`PROFILE.TABLE.HEADER_ROLE`),
- accessor: 'role',
- minWidth: 55,
- },
- {
- id: 'status',
- Header: t(`PROFILE.TABLE.HEADER_STATUS`),
- accessor: 'status',
- minWidth: 55,
- },
- ];
-
- const getFilteredUsers = () => {
- const ROLE_TRANSLATIONS = {
- Owner: t('role:OWNER'),
- 'Extension Officer': t('role:EXTENSION_OFFICER'),
- Manager: t('role:MANAGER'),
- Worker: t('role:WORKER'),
- 'Worker Without Account': t('role:WORKER_WITHOUT_ACCOUNT'),
- };
- const STATUS_TRANSLATIONS = {
- Active: t('STATUS.ACTIVE'),
- Inactive: t('STATUS.INACTIVE'),
- Invited: t('STATUS.INVITED'),
- };
-
- const getName = (user) => {
- const firstName = user.first_name.toLowerCase();
- const lastName = user.last_name.toLowerCase();
- return firstName.concat(' ', lastName);
- };
-
- const filteredUsers = users.filter((user) => {
- return getName(user).includes(searchString.trim().toLowerCase());
- });
- return filteredUsers.map((user) => ({
- name: getName(user),
- user_id: user.user_id,
- role: ROLE_TRANSLATIONS[user.role],
- email: user.email,
- status: STATUS_TRANSLATIONS[user.status],
- originalStatus: user.status,
- }));
- };
- const onRowEdit = (state, rowInfo, column, instance) => {
- const isClickable = rowInfo && isAdmin && column.id === 'name';
- const clickableStyle = {
- whiteSpace: 'unset',
- cursor: 'pointer',
- textDecoration: 'underline',
- color: '#0645AD',
- };
- const normalTextStyle = { whiteSpace: 'unset' };
- return {
- onClick: (e) => {
- if (isClickable) {
- history.push(`/update_user_permission/user/${rowInfo.original.user_id}`);
- }
- },
- style: isClickable ? clickableStyle : normalTextStyle,
- };
- };
- return (
-
-
-
-
-
-
-
-
-
history.push('/invite_user')} fullLength>
- {t('PROFILE.PEOPLE.INVITE_USER')}
-
-
- );
-}
-PurePeople.propTypes = {
- users: PropTypes.arrayOf(PropTypes.object).isRequired,
- history: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Profile/People/index.jsx b/packages/webapp/src/components/Profile/People/index.jsx
new file mode 100644
index 0000000000..ac760ff4e8
--- /dev/null
+++ b/packages/webapp/src/components/Profile/People/index.jsx
@@ -0,0 +1,140 @@
+import Input from '../../Form/Input';
+import { useTranslation } from 'react-i18next';
+import React, { useState } from 'react';
+import Button from '../../Form/Button';
+import PropTypes from 'prop-types';
+import Table from '../../Table';
+import ProfileLayout from '../ProfileLayout';
+
+export default function PurePeople({ users, history, isAdmin }) {
+ const { t } = useTranslation();
+ const [searchString, setSearchString] = useState('');
+ const onChange = (e) => {
+ setSearchString(e.target.value);
+ };
+ const summaryColumns = [
+ {
+ id: 'name',
+ Header: t(`PROFILE.TABLE.HEADER_NAME`),
+ accessor: 'name',
+ minWidth: 70,
+ },
+ {
+ id: 'email',
+ Header: t(`PROFILE.TABLE.HEADER_EMAIL`),
+ accessor: 'email',
+ minWidth: 95,
+ style: { whiteSpace: 'unset' },
+ },
+ {
+ id: 'role',
+ Header: t(`PROFILE.TABLE.HEADER_ROLE`),
+ accessor: 'role',
+ minWidth: 55,
+ },
+ {
+ id: 'status',
+ Header: t(`PROFILE.TABLE.HEADER_STATUS`),
+ accessor: 'status',
+ minWidth: 55,
+ },
+ ];
+
+ const getFilteredUsers = () => {
+ const dropDownMap = {
+ 1: t('role:OWNER'),
+ 2: t('role:MANAGER'),
+ 3: t('role:WORKER'),
+ 4: t('role:WORKER_WITHOUT_ACCOUNT'),
+ 5: t('role:EXTENSION_OFFICER'),
+ };
+ const STATUS_TRANSLATIONS = {
+ Active: t('STATUS.ACTIVE'),
+ Inactive: t('STATUS.INACTIVE'),
+ Invited: t('STATUS.INVITED'),
+ };
+
+ const getName = (user) => {
+ const firstName = user.first_name;
+ const lastName = user.last_name;
+ return firstName.concat(' ', lastName);
+ };
+
+ const filteredUsers = users.filter((user) => {
+ return getName(user)
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .toLowerCase()
+ .replace(/\W/g, '')
+ .trim()
+ .includes(
+ searchString
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .toLowerCase()
+ .replace(/\W/g, '')
+ .trim(),
+ );
+ });
+ return filteredUsers.map((user) => ({
+ name: getName(user),
+ user_id: user.user_id,
+ role: dropDownMap[user.role_id],
+ email: user.email,
+ status: STATUS_TRANSLATIONS[user.status],
+ originalStatus: user.status,
+ }));
+ };
+ const onRowEdit = (state, rowInfo, column, instance) => {
+ const isClickable = rowInfo && isAdmin && column.id === 'name';
+ const clickableStyle = {
+ whiteSpace: 'unset',
+ cursor: 'pointer',
+ textDecoration: 'underline',
+ color: '#0645AD',
+ };
+ const normalTextStyle = { whiteSpace: 'unset' };
+ return {
+ onClick: (e) => {
+ if (isClickable) {
+ history.push(`/user/${rowInfo.original.user_id}`);
+ }
+ },
+ style: isClickable ? clickableStyle : normalTextStyle,
+ };
+ };
+ return (
+ history.push('/invite_user')}
+ history={history}
+ buttonGroup={
+ isAdmin && (
+
+ {t('PROFILE.PEOPLE.INVITE_USER')}
+
+ )
+ }
+ >
+
+
+
+ );
+}
+PurePeople.propTypes = {
+ users: PropTypes.arrayOf(PropTypes.object).isRequired,
+ history: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Profile/ProfileLayout/index.js b/packages/webapp/src/components/Profile/ProfileLayout/index.js
deleted file mode 100644
index 5caadae083..0000000000
--- a/packages/webapp/src/components/Profile/ProfileLayout/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-
-import styles from './styles.module.scss';
-import Footer from '../../Footer';
-import PropTypes from 'prop-types';
-import { Tab, Tabs } from '@material-ui/core';
-
-export default function ProfileLayout({ children, buttonGroup, onSubmit }) {
- return (
-
- );
-}
-ProfileLayout.propTypes = {
- buttonGroup: PropTypes.node,
- children: PropTypes.node,
- onSubmit: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Profile/ProfileLayout/index.jsx b/packages/webapp/src/components/Profile/ProfileLayout/index.jsx
new file mode 100644
index 0000000000..eef0ac5d0d
--- /dev/null
+++ b/packages/webapp/src/components/Profile/ProfileLayout/index.jsx
@@ -0,0 +1,39 @@
+import React from 'react';
+
+import styles from './styles.module.scss';
+import Footer from '../../Footer';
+import PropTypes from 'prop-types';
+import RouterTab from '../../RouterTab';
+import { useTranslation } from 'react-i18next';
+
+export default function ProfileLayout({ children, buttonGroup, onSubmit, history }) {
+ const { t } = useTranslation();
+ return (
+
+ );
+}
+ProfileLayout.propTypes = {
+ buttonGroup: PropTypes.node,
+ children: PropTypes.node,
+ onSubmit: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/ProfileFloater/ProfileFloater.test.js b/packages/webapp/src/components/ProfileFloater/ProfileFloater.test.js
deleted file mode 100644
index 77c61ce11a..0000000000
--- a/packages/webapp/src/components/ProfileFloater/ProfileFloater.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import { render, fireEvent, screen, act } from '@testing-library/react';
-import PureProfileFloater from './index';
-
-describe('Profile Loader View', () => {
- it('rendÎers correctly with given props', () => {
- const fakeFunc = jest.fn();
- render(
- ,
- );
- expect(screen.queryByText(/log out/i)).toBeDefined();
- });
-
- it('calls all passed functions on click', () => {
- const fakeFunc = jest.fn();
- render(
- ,
- );
- act(() => {
- fireEvent.click(screen.getByText(/log out/i));
- fireEvent.click(screen.getByText(/my info/i));
- fireEvent.click(screen.getByText(/switch farm/i));
- fireEvent.click(screen.getByText(/help/i));
- });
- expect(fakeFunc).toHaveBeenCalledTimes(4);
- });
-});
diff --git a/packages/webapp/src/components/ProfileFloater/index.js b/packages/webapp/src/components/ProfileFloater/index.js
deleted file mode 100644
index 38ded42bd4..0000000000
--- a/packages/webapp/src/components/ProfileFloater/index.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import React from 'react';
-import { ReactComponent as LogoutIcon } from '../../assets/images/navbar/logout.svg';
-import { ReactComponent as MyInfoIcon } from '../../assets/images/navbar/my-info.svg';
-import { ReactComponent as HelpIcon } from '../../assets/images/navbar/help-profile.svg';
-import { ReactComponent as VideoIcon } from '../../assets/images/video_icon.svg';
-import { ReactComponent as SwitchFarmIcon } from '../../assets/images/navbar/switch-farm.svg';
-import ListOption from '../Navigation/NavBar/ListOption';
-import { useTranslation } from 'react-i18next';
-import Floater from 'react-floater';
-import PropTypes from 'prop-types';
-
-export function PureProfileFloaterComponent({ onInfo, onSwitchFarm, onHelp,
- onTutorials, onLogout }) {
-
- const { t } = useTranslation();
- return (
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- />
-
- }
- customParagraphStyle={{ paddingBottom: '0.5rem', paddingTop: '0.4rem' }}
- />
-
- );
-}
-
-export default function PureProfileFloater({
- children,
- openProfile,
- helpClick,
- myInfoClick,
- logOutClick,
- switchFarmClick,
- tutorialsClick,
-}) {
- return (
-
- }
- placement={'bottom-end'}
- open={openProfile}
- styles={{
- floater: { zIndex: 1500, display: openProfile ? 'initial' : 'none' },
- }}
- >
- {children}
-
- );
-}
-
-PureProfileFloaterComponent.prototype = {
- onInfo: PropTypes.func,
- onSwitchFarm: PropTypes.func,
- onHelp: PropTypes.func,
- onLogout: PropTypes.func,
-};
-
-PureProfileFloater.prototype = {
- myInfoClick: PropTypes.func,
- switchFarmClick: PropTypes.func,
- helpClick: PropTypes.func,
- logOutClick: PropTypes.func,
- children: PropTypes.node,
- openProfile: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/ProgressBar/index.js b/packages/webapp/src/components/ProgressBar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/ProgressBar/index.js
rename to packages/webapp/src/components/ProgressBar/index.jsx
diff --git a/packages/webapp/src/components/PureSnackbar/index.js b/packages/webapp/src/components/PureSnackbar/index.jsx
similarity index 100%
rename from packages/webapp/src/components/PureSnackbar/index.js
rename to packages/webapp/src/components/PureSnackbar/index.jsx
diff --git a/packages/webapp/src/components/Rating/index.js b/packages/webapp/src/components/Rating/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Rating/index.js
rename to packages/webapp/src/components/Rating/index.jsx
diff --git a/packages/webapp/src/components/RoleSelection/index.js b/packages/webapp/src/components/RoleSelection/index.js
deleted file mode 100644
index 78d36437b2..0000000000
--- a/packages/webapp/src/components/RoleSelection/index.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import Form from '../Form';
-import Button from '../Form/Button';
-import Radio from '../Form/Radio';
-import React, { useEffect } from 'react';
-import { Label, Title } from '../Typography';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../PageTitle/v2';
-import { useForm } from 'react-hook-form';
-import RadioGroup from '../Form/RadioGroup';
-
-export default function PureRoleSelection({
- onSubmit,
- title,
- inputs,
- inputClasses = {},
- redirectConsent,
- onGoBack,
- defaultRole,
- defaultOwnerOperated,
-}) {
- const { t } = useTranslation(['translation', 'common']);
- const {
- register,
- handleSubmit,
- setValue,
- control,
- watch,
- formState: { isValid },
- } = useForm();
- const ROLE = 'role';
- const OWNER_OPERATED = 'owner_operated';
- const role = watch(ROLE);
-
- useEffect(() => {
- setValue(ROLE, defaultRole);
- setValue(OWNER_OPERATED, defaultOwnerOperated?.toString());
- }, []);
-
- const disabled = !role;
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/RoleSelection/index.jsx b/packages/webapp/src/components/RoleSelection/index.jsx
new file mode 100644
index 0000000000..e8ef7174c8
--- /dev/null
+++ b/packages/webapp/src/components/RoleSelection/index.jsx
@@ -0,0 +1,80 @@
+import Form from '../Form';
+import Button from '../Form/Button';
+import React from 'react';
+import { Label, Title } from '../Typography';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../PageTitle/v2';
+import { useForm } from 'react-hook-form';
+import RadioGroup from '../Form/RadioGroup';
+
+export default function PureRoleSelection({
+ onSubmit,
+ title,
+ inputs,
+ inputClasses = {},
+ redirectConsent,
+ onGoBack,
+ defaultRole,
+ defaultOwnerOperated,
+}) {
+ const { t } = useTranslation(['translation', 'common']);
+ const ROLE = 'role';
+ const OWNER_OPERATED = 'owner_operated';
+ const {
+ register,
+ handleSubmit,
+ setValue,
+ control,
+ watch,
+ formState: { isValid },
+ } = useForm({
+ defaultValues: {
+ [ROLE]: defaultRole,
+ [OWNER_OPERATED]: defaultOwnerOperated,
+ },
+ });
+
+ const role = watch(ROLE);
+
+ const disabled = !role;
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/RouterTab/StateTab/index.js b/packages/webapp/src/components/RouterTab/StateTab/index.jsx
similarity index 100%
rename from packages/webapp/src/components/RouterTab/StateTab/index.js
rename to packages/webapp/src/components/RouterTab/StateTab/index.jsx
diff --git a/packages/webapp/src/components/RouterTab/index.js b/packages/webapp/src/components/RouterTab/index.js
deleted file mode 100644
index 74fd800710..0000000000
--- a/packages/webapp/src/components/RouterTab/index.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import PropTypes from 'prop-types';
-import { Semibold } from '../Typography';
-import styles from './styles.module.scss';
-import clsx from 'clsx';
-
-export default function RouterTab({ tabs, history, classes }) {
- const isSelected = (path) => history.location.pathname.includes(path);
- return (
-
- {tabs.map((tab, index) => (
- !isSelected(tab.path) && history.push(tab.path)}
- id={tab.label + index}
- >
- {tab.label}
-
- ))}
-
- );
-}
-
-RouterTab.prototype = {
- tabs: PropTypes.shape({ label: PropTypes.string, path: PropTypes.string }),
- history: PropTypes.object,
- classes: PropTypes.object,
- currentPath: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/RouterTab/index.jsx b/packages/webapp/src/components/RouterTab/index.jsx
new file mode 100644
index 0000000000..7f1faed55f
--- /dev/null
+++ b/packages/webapp/src/components/RouterTab/index.jsx
@@ -0,0 +1,29 @@
+import PropTypes from 'prop-types';
+import { Semibold } from '../Typography';
+import styles from './styles.module.scss';
+import clsx from 'clsx';
+
+export default function RouterTab({ tabs, history, classes }) {
+ const isSelected = (path) => history.location.pathname?.toLowerCase().includes(path);
+ return (
+
+ {tabs.map((tab, index) => (
+ !isSelected(tab.path) && history.replace(tab.path, tab.state)}
+ id={tab.label + index}
+ >
+ {tab.label}
+
+ ))}
+
+ );
+}
+
+RouterTab.prototype = {
+ tabs: PropTypes.shape({ label: PropTypes.string, path: PropTypes.string }),
+ history: PropTypes.object,
+ classes: PropTypes.object,
+ currentPath: PropTypes.string,
+};
diff --git a/packages/webapp/src/components/Signup/EnterPasswordPage/index.js b/packages/webapp/src/components/Signup/EnterPasswordPage/index.js
deleted file mode 100644
index 2bd66dae2b..0000000000
--- a/packages/webapp/src/components/Signup/EnterPasswordPage/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import Form from '../../Form';
-import styles from './styles.module.scss';
-import Button from '../../Form/Button';
-import Input from '../../Form/Input';
-import React, { useEffect, useState } from 'react';
-import { Text, Title, Underlined } from '../../Typography';
-import PropTypes from 'prop-types';
-import { useForm } from 'react-hook-form';
-import { validatePasswordWithErrors } from '../utils';
-import { PasswordError } from '../../Form/Errors';
-import { useTranslation } from 'react-i18next';
-import { NewReleaseCard } from '../../Card/NewReleaseCard/NewReleaseCard';
-
-export default function PureEnterPasswordPage({
- title,
- onLogin,
- onGoBack,
- forgotPassword,
- isVisible,
- isChrome = true,
-}) {
- const {
- register,
- handleSubmit,
- setError,
- watch,
-
- formState: { errors },
- } = useForm();
- const PASSWORD = 'password';
- const password = watch(PASSWORD);
- const {
- isValid,
- hasNoSymbol,
- hasNoDigit,
- hasNoUpperCase,
- isTooShort,
- } = validatePasswordWithErrors(password);
- const inputRegister = register(PASSWORD, { required: true });
- const [showErrors, setShowErrors] = useState(false);
- const { t } = useTranslation(['translation', 'common']);
- const showPasswordIncorrectError = () => {
- setError(PASSWORD, {
- type: 'manual',
- message: t('SIGNUP.PASSWORD_ERROR'),
- });
- setShowErrors(true);
- };
- const onSubmit = (data) => {
- onLogin(data.password, showPasswordIncorrectError);
- };
- const onError = (data) => {
- setShowErrors(true);
- };
- const wrongBrowserTop = t('SIGNUP.WRONG_BROWSER');
- const wrongBrowserBottom = t('SIGNUP.WRONG_BROWSER_BOTTOM');
-
- useEffect(() => {
- if (isVisible) {
- document.getElementById('password_input_to_focus')?.focus();
- }
- }, [isVisible]);
-
- return (
-
- );
-}
-
-PureEnterPasswordPage.prototype = {
- title: PropTypes.string,
- onLogin: PropTypes.func,
- onGoBack: PropTypes.func,
- forgotPassword: PropTypes.func,
- isChrome: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Signup/EnterPasswordPage/index.jsx b/packages/webapp/src/components/Signup/EnterPasswordPage/index.jsx
new file mode 100644
index 0000000000..267ad3b28d
--- /dev/null
+++ b/packages/webapp/src/components/Signup/EnterPasswordPage/index.jsx
@@ -0,0 +1,117 @@
+import Form from '../../Form';
+import styles from './styles.module.scss';
+import Button from '../../Form/Button';
+import Input from '../../Form/Input';
+import React, { useEffect, useState } from 'react';
+import { Text, Title, Underlined } from '../../Typography';
+import PropTypes from 'prop-types';
+import { useForm } from 'react-hook-form';
+import { validatePasswordWithErrors } from '../utils';
+import { PasswordError } from '../../Form/Errors';
+import { useTranslation } from 'react-i18next';
+import { NewReleaseCard } from '../../Card/NewReleaseCard/NewReleaseCard';
+
+export default function PureEnterPasswordPage({
+ title,
+ onLogin,
+ onGoBack,
+ forgotPassword,
+ isVisible,
+ isChrome = true,
+}) {
+ const {
+ register,
+ handleSubmit,
+ setError,
+ watch,
+
+ formState: { errors },
+ } = useForm();
+ const PASSWORD = 'password';
+ const password = watch(PASSWORD);
+ const { isValid, hasNoSymbol, hasNoDigit, hasNoUpperCase, isTooShort } =
+ validatePasswordWithErrors(password);
+ const inputRegister = register(PASSWORD, { required: true });
+ const [showErrors, setShowErrors] = useState(false);
+ const { t } = useTranslation(['translation', 'common', 'message']);
+ const showPasswordIncorrectError = () => {
+ setError(PASSWORD, {
+ type: 'manual',
+ message: t('SIGNUP.PASSWORD_ERROR'),
+ });
+ setShowErrors(true);
+ };
+ const onSubmit = (data) => {
+ onLogin(data.password, showPasswordIncorrectError);
+ };
+ const onError = (data) => {
+ setShowErrors(true);
+ };
+ const wrongBrowserTop = t('SIGNUP.WRONG_BROWSER');
+ const wrongBrowserBottom = t('SIGNUP.WRONG_BROWSER_BOTTOM');
+
+ useEffect(() => {
+ if (isVisible) {
+ document.getElementById('password_input_to_focus')?.focus();
+ }
+ }, [isVisible]);
+
+ return (
+
+ );
+}
+
+PureEnterPasswordPage.prototype = {
+ title: PropTypes.string,
+ onLogin: PropTypes.func,
+ onGoBack: PropTypes.func,
+ forgotPassword: PropTypes.func,
+ isChrome: PropTypes.bool,
+};
diff --git a/packages/webapp/src/components/Spinner/index.js b/packages/webapp/src/components/Spinner/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Spinner/index.js
rename to packages/webapp/src/components/Spinner/index.jsx
diff --git a/packages/webapp/src/components/Square/index.js b/packages/webapp/src/components/Square/index.js
deleted file mode 100644
index 8aef52f65e..0000000000
--- a/packages/webapp/src/components/Square/index.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import { makeStyles } from '@material-ui/core/styles';
-import { colors } from '../../assets/theme';
-import { FaExclamation } from 'react-icons/all';
-import PropTypes from 'prop-types';
-import clsx from 'clsx';
-
-const useStyles = makeStyles({
- container: {
- display: 'inline-flex',
- justifyContent: 'center',
- alignItems: 'center',
- padding: '4px',
- minWidth: '16px',
- height: '16px',
- fontFamily: '"Open Sans"," SansSerif", serif',
- color: 'white',
- fontWeight: 700,
- borderRadius: '4px',
- },
- counter: {
- backgroundColor: colors.teal700,
- },
- active: {
- backgroundColor: colors.brightGreen700,
- },
- planned: {
- backgroundColor: colors.brown700,
- },
- past: {
- backgroundColor: colors.teal900,
- },
- needsPlan: {
- backgroundColor: colors.red700,
- },
- valid: {
- backgroundColor: colors.brightGreen700,
- },
- archived: {
- backgroundColor: colors.teal900,
- },
- cropTile: {
- minWidth: '24px',
- height: '24px',
- borderRadius: 0,
- },
-});
-
-export default function Square({ color = 'active', children, isCropTile, ...props }) {
- const classes = useStyles();
- return (
-
- {color === 'needsPlan' ? : children}
-
- );
-}
-
-Square.propTypes = {
- color: PropTypes.oneOf([
- 'active',
- 'planned',
- 'past',
- 'needsPlan',
- 'valid',
- 'archived',
- 'counter',
- ]),
- isCropTile: PropTypes.bool,
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
-};
diff --git a/packages/webapp/src/components/Square/index.jsx b/packages/webapp/src/components/Square/index.jsx
new file mode 100644
index 0000000000..780c13761f
--- /dev/null
+++ b/packages/webapp/src/components/Square/index.jsx
@@ -0,0 +1,74 @@
+import { makeStyles } from '@material-ui/core/styles';
+import { colors } from '../../assets/theme';
+import { FaExclamation } from 'react-icons/all';
+import PropTypes from 'prop-types';
+import clsx from 'clsx';
+
+const useStyles = makeStyles({
+ container: {
+ display: 'inline-flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: '4px',
+ minWidth: '16px',
+ height: '16px',
+ fontFamily: '"Open Sans"," SansSerif", serif',
+ color: 'white',
+ fontWeight: 700,
+ borderRadius: '4px',
+ },
+ counter: {
+ backgroundColor: colors.teal700,
+ },
+ active: {
+ backgroundColor: colors.brightGreen700,
+ },
+ planned: {
+ backgroundColor: colors.brown700,
+ },
+ past: {
+ backgroundColor: colors.teal900,
+ },
+ needsPlan: {
+ backgroundColor: colors.red700,
+ },
+ valid: {
+ backgroundColor: colors.brightGreen700,
+ },
+ archived: {
+ backgroundColor: colors.teal900,
+ },
+ cropTile: {
+ minWidth: '24px',
+ height: '24px',
+ borderRadius: 0,
+ },
+});
+
+export default function Square({ color = 'active', children, isCropTile, ...props }) {
+ const classes = useStyles();
+ return (
+
+ {/* commenting for the future use */}
+ {/* {color === 'needsPlan' ? : children} */}
+ {children}
+
+ );
+}
+
+Square.propTypes = {
+ color: PropTypes.oneOf([
+ 'active',
+ 'planned',
+ 'past',
+ 'needsPlan',
+ 'valid',
+ 'archived',
+ 'counter',
+ ]),
+ isCropTile: PropTypes.bool,
+ children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
+};
diff --git a/packages/webapp/src/components/Svg/index.js b/packages/webapp/src/components/Svg/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Svg/index.js
rename to packages/webapp/src/components/Svg/index.jsx
diff --git a/packages/webapp/src/components/Table/index.js b/packages/webapp/src/components/Table/index.js
deleted file mode 100644
index c0d37f2027..0000000000
--- a/packages/webapp/src/components/Table/index.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import ReactTable from 'react-table';
-import React from 'react';
-import { Text } from '../Typography';
-import { useTranslation } from 'react-i18next';
-
-// refer to Log/index.js for example on how to format columns and data props, or read react-table documentation
-function Table({
- columns,
- data,
- showPagination,
- pageSizeOptions,
- defaultPageSize,
- className,
- getTdProps,
- sortByID,
- minRows = 5,
-}) {
- const { t } = useTranslation();
- const defaultSorted = sortByID
- ? [
- {
- id: sortByID,
- desc: true,
- },
- ]
- : [{ id: columns?.[0]?.id, desc: true }];
- const pageSize = showPagination
- ? Math.min(Math.max(data?.length || minRows || 5, minRows), defaultPageSize)
- : undefined;
- return (
- defaultPageSize}
- pageSizeOptions={pageSizeOptions}
- defaultPageSize={pageSize}
- minRows={showPagination ? undefined : minRows} // Messes up pagination
- getTdProps={getTdProps}
- defaultSorted={defaultSorted}
- noDataText={t('TABLE.NO_DATA_TEXT')}
- previousText={t('TABLE.PREVIOUS_TEXT')}
- nextText={t('TABLE.NEXT_TEXT')}
- loadingText={t('TABLE.LOADING_TEXT')}
- pageText={t('TABLE.PAGE_TEXT')}
- ofText={t('TABLE.OF_TEXT')}
- rowsText={t('TABLE.ROWS_TEXT')}
- />
- );
-}
-
-export default Table;
diff --git a/packages/webapp/src/components/Table/index.jsx b/packages/webapp/src/components/Table/index.jsx
new file mode 100644
index 0000000000..b637bb4ae0
--- /dev/null
+++ b/packages/webapp/src/components/Table/index.jsx
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (index.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import ReactTable from 'react-table';
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+
+// refer to Log/index.js for example on how to format columns and data props, or read react-table documentation
+function Table({
+ columns,
+ data,
+ showPagination,
+ pageSizeOptions,
+ defaultPageSize,
+ className,
+ getTdProps,
+ sortByID,
+ minRows = 5,
+}) {
+ const { t } = useTranslation();
+ const defaultSorted = sortByID
+ ? [
+ {
+ id: sortByID,
+ desc: true,
+ },
+ ]
+ : [{ id: columns?.[0]?.id, desc: true }];
+ const pageSize = showPagination
+ ? Math.min(Math.max(data?.length || minRows || 5, minRows), defaultPageSize)
+ : undefined;
+ return (
+ defaultPageSize}
+ pageSizeOptions={pageSizeOptions}
+ defaultPageSize={pageSize}
+ minRows={showPagination ? undefined : minRows} // Messes up pagination
+ getTdProps={getTdProps}
+ defaultSorted={defaultSorted}
+ noDataText={t('TABLE.NO_DATA_TEXT')}
+ previousText={t('TABLE.PREVIOUS_TEXT')}
+ nextText={t('TABLE.NEXT_TEXT')}
+ loadingText={t('TABLE.LOADING_TEXT')}
+ pageText={t('TABLE.PAGE_TEXT')}
+ ofText={t('TABLE.OF_TEXT')}
+ rowsText={t('TABLE.ROWS_TEXT')}
+ />
+ );
+}
+
+export default Table;
diff --git a/packages/webapp/src/components/Task/AbandonTask/index.js b/packages/webapp/src/components/Task/AbandonTask/index.js
deleted file mode 100644
index e90ab0f315..0000000000
--- a/packages/webapp/src/components/Task/AbandonTask/index.js
+++ /dev/null
@@ -1,150 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import Layout from '../../Layout';
-import PageTitle from '../../PageTitle/v2';
-import { Info, Underlined } from '../../Typography';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import ReactSelect from '../../Form/ReactSelect';
-import { Controller, useForm } from 'react-hook-form';
-import InputAutoSize from '../../Form/InputAutoSize';
-import Input from '../../Form/Input';
-import { Main } from '../../Typography';
-import TimeSlider from '../../Form/Slider/TimeSlider';
-import Checkbox from '../../Form/Checkbox';
-import Rating from '../../Rating';
-
-const PureAbandonTask = ({ onSubmit, onError, onGoBack, hasAssignee }) => {
- const { t } = useTranslation();
- const {
- register,
- handleSubmit,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- });
-
- const REASON_FOR_ABANDONMENT = 'reason_for_abandonment';
- const OTHER_REASON_FOR_ABANDONMENT = 'other_abandonment_reason';
- const TASK_ABANDONMENT_NOTES = 'abandonment_notes';
- const DURATION = 'duration';
- const HAPPINESS = 'happiness';
- const NO_WORK_COMPLETED = 'no_work_completed';
- const PREFER_NOT_TO_SAY = 'prefer_not_to_say';
-
- const reason_for_abandonment = watch(REASON_FOR_ABANDONMENT);
- const prefer_not_to_say = watch(PREFER_NOT_TO_SAY);
- const no_work_completed = watch(NO_WORK_COMPLETED);
- const happiness = watch(HAPPINESS);
-
- const disabled = !isValid || (hasAssignee && !happiness && !prefer_not_to_say);
-
- // TODO: bring the options up to the smart component (eventually will be an api call + selector)
- const abandonmentReasonOptions = [
- { label: t('TASK.ABANDON.REASON.CROP_FAILURE'), value: 'CROP_FAILURE' },
- { label: t('TASK.ABANDON.REASON.LABOUR_ISSUE'), value: 'LABOUR_ISSUE' },
- { label: t('TASK.ABANDON.REASON.MARKET_PROBLEM'), value: 'MARKET_PROBLEM' },
- { label: t('TASK.ABANDON.REASON.WEATHER'), value: 'WEATHER' },
- { label: t('TASK.ABANDON.REASON.MACHINERY_ISSUE'), value: 'MACHINERY_ISSUE' },
- { label: t('TASK.ABANDON.REASON.SCHEDULING_ISSUE'), value: 'SCHEDULING_ISSUE' },
- { label: t('TASK.ABANDON.REASON.OTHER'), value: 'OTHER' },
- ];
-
- return (
-
- {t('TASK.ABANDON.ABANDON')}
-
- }
- >
-
-
- {t('TASK.ABANDON.INFO')}
-
- (
-
- )}
- rules={{ required: true }}
- />
-
- {reason_for_abandonment?.value === 'OTHER' && (
-
- )}
-
- {hasAssignee && (
- <>
- {t('TASK.ABANDON_TASK_DURATION')}
-
- {!no_work_completed && (
- setValue(DURATION, durationInMinutes)}
- />
- )}
-
-
-
- {t('TASK.DID_YOU_ENJOY')}
-
- {!prefer_not_to_say && (
- setValue(HAPPINESS, value)}
- />
- )}
-
- setValue(HAPPINESS, null)}
- />
- >
- )}
-
-
-
- );
-};
-
-PureAbandonTask.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
- onGoBack: PropTypes.func,
-};
-
-export default PureAbandonTask;
diff --git a/packages/webapp/src/components/Task/AbandonTask/index.jsx b/packages/webapp/src/components/Task/AbandonTask/index.jsx
new file mode 100644
index 0000000000..aa669142a4
--- /dev/null
+++ b/packages/webapp/src/components/Task/AbandonTask/index.jsx
@@ -0,0 +1,175 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Layout from '../../Layout';
+import PageTitle from '../../PageTitle/v2';
+import { Info, Main } from '../../Typography';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import ReactSelect from '../../Form/ReactSelect';
+import { Controller, useForm } from 'react-hook-form';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Input from '../../Form/Input';
+import TimeSlider from '../../Form/Slider/TimeSlider';
+import Checkbox from '../../Form/Checkbox';
+import Rating from '../../Rating';
+import { getDateInputFormat } from '../../../util/moment';
+
+const PureAbandonTask = ({
+ onSubmit,
+ onError,
+ onGoBack,
+ hasAssignee,
+ isAssigneeTheLoggedInUser,
+}) => {
+ const REASON_FOR_ABANDONMENT = 'reason_for_abandonment';
+ const OTHER_REASON_FOR_ABANDONMENT = 'other_abandonment_reason';
+ const ABANDON_DATE = 'abandon_date';
+ const TASK_ABANDONMENT_NOTES = 'abandonment_notes';
+ const DURATION = 'duration';
+ const HAPPINESS = 'happiness';
+ const NO_WORK_COMPLETED = 'no_work_completed';
+ const PREFER_NOT_TO_SAY = 'prefer_not_to_say';
+ const { t } = useTranslation();
+ const {
+ register,
+ handleSubmit,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: {
+ [ABANDON_DATE]: getDateInputFormat(),
+ [PREFER_NOT_TO_SAY]: !isAssigneeTheLoggedInUser,
+ },
+ });
+
+ const reason_for_abandonment = watch(REASON_FOR_ABANDONMENT);
+ const prefer_not_to_say = watch(PREFER_NOT_TO_SAY);
+ const no_work_completed = watch(NO_WORK_COMPLETED);
+ const happiness = watch(HAPPINESS);
+
+ const disabled = !isValid || (hasAssignee && !happiness && !prefer_not_to_say);
+
+ // TODO: bring the options up to the smart component (eventually will be an api call + selector)
+ const abandonmentReasonOptions = [
+ { label: t('TASK.ABANDON.REASON.CROP_FAILURE'), value: 'CROP_FAILURE' },
+ { label: t('TASK.ABANDON.REASON.LABOUR_ISSUE'), value: 'LABOUR_ISSUE' },
+ { label: t('TASK.ABANDON.REASON.MARKET_PROBLEM'), value: 'MARKET_PROBLEM' },
+ { label: t('TASK.ABANDON.REASON.WEATHER'), value: 'WEATHER' },
+ { label: t('TASK.ABANDON.REASON.MACHINERY_ISSUE'), value: 'MACHINERY_ISSUE' },
+ { label: t('TASK.ABANDON.REASON.SCHEDULING_ISSUE'), value: 'SCHEDULING_ISSUE' },
+ { label: t('TASK.ABANDON.REASON.OTHER'), value: 'OTHER' },
+ ];
+
+ return (
+
+ {t('TASK.ABANDON.ABANDON')}
+
+ }
+ >
+
+
+ {t('TASK.ABANDON.INFO')}
+
+ {t('TASK.ABANDON.WHEN')}
+
+
+
+ (
+
+ )}
+ rules={{ required: true }}
+ />
+
+ {reason_for_abandonment?.value === 'OTHER' && (
+
+ )}
+
+ {hasAssignee && (
+ <>
+ {t('TASK.ABANDON_TASK_DURATION')}
+
+ {!no_work_completed && (
+ setValue(DURATION, durationInMinutes)}
+ />
+ )}
+
+
+
+ {isAssigneeTheLoggedInUser && (
+ <>
+ {t('TASK.DID_YOU_ENJOY')}
+ {!prefer_not_to_say && (
+ setValue(HAPPINESS, value)}
+ />
+ )}
+ setValue(HAPPINESS, null)}
+ />
+ >
+ )}
+ >
+ )}
+
+
+
+ );
+};
+
+PureAbandonTask.prototype = {
+ subject: PropTypes.string,
+ items: PropTypes.array,
+ onGoBack: PropTypes.func,
+ isAssigneeTheLoggedInUser: PropTypes.bool,
+};
+
+export default PureAbandonTask;
diff --git a/packages/webapp/src/components/Task/AddProduct/index.js b/packages/webapp/src/components/Task/AddProduct/index.js
deleted file mode 100644
index b44f8438c2..0000000000
--- a/packages/webapp/src/components/Task/AddProduct/index.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import ReactSelect from '../../Form/ReactSelect';
-import React, { useEffect, useMemo, useState } from 'react';
-import { ReactComponent as Leaf } from '../../../assets/images/farmMapFilter/Leaf.svg';
-import { useTranslation } from 'react-i18next';
-import Input, { getInputErrors } from '../../Form/Input';
-import RadioGroup from '../../Form/RadioGroup';
-import { pest, soilAmounts, waterUsage } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import { Main } from '../../Typography';
-import { CANADA } from './constants';
-
-const AddProduct = ({
- products,
- type,
- system,
- getValues,
- setValue,
- watch,
- control,
- register,
- formState: { errors },
- farm,
- disabled,
-}) => {
- const { t } = useTranslation();
- const { farm_id, interested, country_id } = farm;
-
- const productsOfType = useMemo(() => products.filter((product) => product.type === type), [
- products.length,
- type,
- ]);
-
- const [productValue, setProductValue] = useState(null);
- const typesOfProduct = {
- cleaning_task: {
- units: waterUsage,
- label: t('ADD_TASK.CLEANING_VIEW.IS_PERMITTED'),
- },
- soil_amendment_task: {
- units: soilAmounts,
- label: t('ADD_TASK.SOIL_AMENDMENT_VIEW.IS_PERMITTED'),
- },
- pest_control_task: {
- label: t('ADD_TASK.PEST_CONTROL_VIEW.IS_PERMITTED'),
- units: pest,
- },
- };
- const NAME = `${type}.product.name`;
- const FARM = `${type}.product.farm_id`;
- const SUPPLIER = `${type}.product.supplier`;
- const TYPE = `${type}.product.type`;
- const PERMITTED = `${type}.product.on_permitted_substances_list`;
- const PRODUCT_QUANTITY = `${type}.product_quantity`;
- const PRODUCT_QUANTITY_UNIT = `${type}.product_quantity_unit`;
- const PRODUCT_ID = `${type}.product_id`;
-
- const processProduct = (value) => {
- setValue(`${type}.product.product_id`, undefined);
- let product = productsOfType.find(({ product_id }) => product_id === value?.value);
- if (product) {
- const { supplier, on_permitted_substances_list } = product;
- setValue(NAME, value?.label, { shouldValidate: true });
- setValue(PRODUCT_ID, value?.value);
- setValue(SUPPLIER, supplier);
- setValue(PERMITTED, on_permitted_substances_list, { shouldValidate: true });
- } else {
- setValue(NAME, value?.label, { shouldValidate: true });
- setValue(PRODUCT_ID, null);
- setValue(SUPPLIER, null);
- setValue(PERMITTED, null);
- }
- };
- const isInterestedInCanada = useMemo(() => interested && country_id === CANADA, [
- country_id,
- interested,
- ]);
- const transformProductsToLabel = (products) =>
- products.map(({ product_id, name }) => ({ label: name, value: product_id }));
-
- useEffect(() => {
- setValue(FARM, farm_id);
- setValue(TYPE, type);
- const [id, name] = getValues([PRODUCT_ID, NAME]);
- if (id && name) {
- setProductValue({ label: name, value: id });
- } else if (!id && name) {
- setProductValue({ label: name, value: name });
- }
- }, []);
-
- return (
- <>
- {
- processProduct(e);
- setProductValue(e);
- }}
- placeholder={t('ADD_PRODUCT.PRESS_ENTER')}
- value={productValue}
- style={{ marginBottom: '40px' }}
- creatable
- icon={ }
- isDisabled={disabled}
- />
-
-
-
- {isInterestedInCanada && (
- <>
-
- {typesOfProduct[type].label}
-
-
-
- >
- )}
-
- >
- );
-};
-
-export default AddProduct;
diff --git a/packages/webapp/src/components/Task/AddProduct/index.jsx b/packages/webapp/src/components/Task/AddProduct/index.jsx
new file mode 100644
index 0000000000..aeb3da64c3
--- /dev/null
+++ b/packages/webapp/src/components/Task/AddProduct/index.jsx
@@ -0,0 +1,153 @@
+import ReactSelect from '../../Form/ReactSelect';
+import React, { useEffect, useMemo, useState } from 'react';
+import { ReactComponent as Leaf } from '../../../assets/images/farmMapFilter/Leaf.svg';
+import { useTranslation } from 'react-i18next';
+import Input, { getInputErrors } from '../../Form/Input';
+import RadioGroup from '../../Form/RadioGroup';
+import { pest, soilAmounts, waterUsage } from '../../../util/convert-units/unit';
+import Unit from '../../Form/Unit';
+import { Main } from '../../Typography';
+import { CANADA } from './constants';
+
+const AddProduct = ({
+ products,
+ type,
+ system,
+ getValues,
+ setValue,
+ watch,
+ control,
+ register,
+ formState: { errors },
+ farm,
+ disabled,
+}) => {
+ const { t } = useTranslation();
+ const { farm_id, interested, country_id } = farm;
+
+ const productsOfType = useMemo(() => products.filter((product) => product.type === type), [
+ products.length,
+ type,
+ ]);
+
+ const [productValue, setProductValue] = useState(null);
+ const typesOfProduct = {
+ cleaning_task: {
+ units: waterUsage,
+ label: t('ADD_TASK.CLEANING_VIEW.IS_PERMITTED'),
+ },
+ soil_amendment_task: {
+ units: soilAmounts,
+ label: t('ADD_TASK.SOIL_AMENDMENT_VIEW.IS_PERMITTED'),
+ },
+ pest_control_task: {
+ label: t('ADD_TASK.PEST_CONTROL_VIEW.IS_PERMITTED'),
+ units: pest,
+ },
+ };
+ const NAME = `${type}.product.name`;
+ const FARM = `${type}.product.farm_id`;
+ const SUPPLIER = `${type}.product.supplier`;
+ const TYPE = `${type}.product.type`;
+ const PERMITTED = `${type}.product.on_permitted_substances_list`;
+ const PRODUCT_QUANTITY = `${type}.product_quantity`;
+ const PRODUCT_QUANTITY_UNIT = `${type}.product_quantity_unit`;
+ const PRODUCT_ID = `${type}.product_id`;
+
+ const processProduct = (value) => {
+ setValue(`${type}.product.product_id`, undefined);
+ let product = productsOfType.find(({ product_id }) => product_id === value?.value);
+ if (product) {
+ const { supplier, on_permitted_substances_list } = product;
+ setValue(NAME, value?.label, { shouldValidate: true });
+ setValue(PRODUCT_ID, value?.value);
+ setValue(SUPPLIER, supplier);
+ setValue(PERMITTED, on_permitted_substances_list, { shouldValidate: true });
+ } else {
+ setValue(NAME, value?.label, { shouldValidate: true });
+ setValue(PRODUCT_ID, null);
+ setValue(SUPPLIER, null);
+ setValue(PERMITTED, null);
+ }
+ };
+ const isInterestedInCanada = useMemo(() => interested && country_id === CANADA, [
+ country_id,
+ interested,
+ ]);
+ const transformProductsToLabel = (products) =>
+ products.map(({ product_id, name }) => ({ label: name, value: product_id }));
+
+ useEffect(() => {
+ setValue(FARM, farm_id);
+ setValue(TYPE, type);
+ const [id, name] = getValues([PRODUCT_ID, NAME]);
+ if (id && name) {
+ setProductValue({ label: name, value: id });
+ } else if (!id && name) {
+ setProductValue({ label: name, value: name });
+ }
+ }, []);
+
+ return (
+ <>
+ {
+ processProduct(e);
+ setProductValue(e);
+ }}
+ placeholder={t('ADD_PRODUCT.PRESS_ENTER')}
+ value={productValue}
+ style={{ marginBottom: '40px' }}
+ creatable
+ icon={ }
+ isDisabled={disabled}
+ />
+
+
+
+ {isInterestedInCanada && (
+ <>
+
+ {typesOfProduct[type].label}
+
+
+
+ >
+ )}
+
+ >
+ );
+};
+
+export default AddProduct;
diff --git a/packages/webapp/src/components/Task/CleaningTask/index.js b/packages/webapp/src/components/Task/CleaningTask/index.js
deleted file mode 100644
index 0ebdfe807c..0000000000
--- a/packages/webapp/src/components/Task/CleaningTask/index.js
+++ /dev/null
@@ -1,91 +0,0 @@
-import React, { useEffect } from 'react';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import Input from '../../Form/Input';
-import RadioGroup from '../../Form/RadioGroup';
-import { waterUsage } from '../../../util/unit';
-import Unit from '../../Form/Unit';
-import AddProduct from '../AddProduct';
-
-const PureCleaningTask = ({
- system,
- products,
- register,
- control,
- setValue,
- getValues,
- formState,
- watch,
- farm,
- disabled = false,
-}) => {
- const { t } = useTranslation();
- const CLEANING_TARGET = 'cleaning_task.cleaning_target';
- const AGENT_USED = 'cleaning_task.agent_used';
- const WATER_USAGE = 'cleaning_task.water_usage';
- const WATER_USAGE_UNIT = 'cleaning_task.water_usage_unit';
- const isCleaningAgentUsed = watch(AGENT_USED);
-
- useEffect(() => {
- if (isCleaningAgentUsed === false && getValues('cleaning_task.product')) {
- setValue('cleaning_task.product', null);
- setValue('cleaning_task.product_id', null);
- setValue('cleaning_task.product_quantity', undefined);
- setValue('cleaning_task.product_quantity_unit', null, { shouldValidate: true });
- }
- }, [isCleaningAgentUsed]);
- return (
- <>
-
-
- {t('ADD_TASK.CLEANING_VIEW.WILL_CLEANER_BE_USED')}
-
-
- {isCleaningAgentUsed && (
-
- )}
-
- >
- );
-};
-
-export default PureCleaningTask;
diff --git a/packages/webapp/src/components/Task/CleaningTask/index.jsx b/packages/webapp/src/components/Task/CleaningTask/index.jsx
new file mode 100644
index 0000000000..be50fc20bd
--- /dev/null
+++ b/packages/webapp/src/components/Task/CleaningTask/index.jsx
@@ -0,0 +1,91 @@
+import React, { useEffect } from 'react';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import Input from '../../Form/Input';
+import RadioGroup from '../../Form/RadioGroup';
+import { waterUsage } from '../../../util/convert-units/unit';
+import Unit from '../../Form/Unit';
+import AddProduct from '../AddProduct';
+
+const PureCleaningTask = ({
+ system,
+ products,
+ register,
+ control,
+ setValue,
+ getValues,
+ formState,
+ watch,
+ farm,
+ disabled = false,
+}) => {
+ const { t } = useTranslation();
+ const CLEANING_TARGET = 'cleaning_task.cleaning_target';
+ const AGENT_USED = 'cleaning_task.agent_used';
+ const WATER_USAGE = 'cleaning_task.water_usage';
+ const WATER_USAGE_UNIT = 'cleaning_task.water_usage_unit';
+ const isCleaningAgentUsed = watch(AGENT_USED);
+
+ useEffect(() => {
+ if (isCleaningAgentUsed === false && getValues('cleaning_task.product')) {
+ setValue('cleaning_task.product', null);
+ setValue('cleaning_task.product_id', null);
+ setValue('cleaning_task.product_quantity', undefined);
+ setValue('cleaning_task.product_quantity_unit', null, { shouldValidate: true });
+ }
+ }, [isCleaningAgentUsed]);
+ return (
+ <>
+
+
+ {t('ADD_TASK.CLEANING_VIEW.WILL_CLEANER_BE_USED')}
+
+
+ {isCleaningAgentUsed && (
+
+ )}
+
+ >
+ );
+};
+
+export default PureCleaningTask;
diff --git a/packages/webapp/src/components/Task/FieldWorkTask/index.js b/packages/webapp/src/components/Task/FieldWorkTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/FieldWorkTask/index.js
rename to packages/webapp/src/components/Task/FieldWorkTask/index.jsx
diff --git a/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.js b/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.js
deleted file mode 100644
index 6e96957d47..0000000000
--- a/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.js
+++ /dev/null
@@ -1,110 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import { harvestAmounts } from '../../../util/unit';
-import Checkbox from '../../Form/Checkbox';
-import Unit from '../../Form/Unit';
-import ReactSelect from '../../Form/ReactSelect';
-
-export const PureHarvestingTaskReadOnly = ({
- system,
- register,
- control,
- setValue,
- getValues,
- watch,
- isCompleted,
- disabled = false,
-}) => {
- const { t } = useTranslation();
- const HARVEST_QUANTITY = 'harvest_task.projected_quantity';
- const HARVEST_QUANTITY_UNIT = 'harvest_task.projected_quantity_unit';
- const HARVEST_EVERYTHING = 'harvest_task.harvest_everything';
-
- const harvest_everything = watch(HARVEST_EVERYTHING);
-
- return (
- <>
- {!isCompleted && (
- <>
- {!harvest_everything && (
-
- )}
- {harvest_everything && (
-
- )}
- >
- )}
- >
- );
-};
-
-export const PureHavestTaskCompleted = ({
- system,
- register,
- control,
- setValue,
- getValues,
- watch,
- task,
- harvestUseTypes,
- disabled = false,
-}) => {
- const { t } = useTranslation();
- const harvest_uses = task.harvest_task.harvest_use;
- const harvest_uses_type_map = {};
- for (let i = 0; i < harvestUseTypes.length; i++) {
- harvest_uses_type_map[harvestUseTypes[i].harvest_use_type_id] = harvestUseTypes[i];
- }
-
- return (
- <>
- {harvest_uses.map((use, index) => (
-
-
-
-
- ))}
- >
- );
-};
diff --git a/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.jsx b/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.jsx
new file mode 100644
index 0000000000..68284fab09
--- /dev/null
+++ b/packages/webapp/src/components/Task/HarvestingTask/ReadOnly.jsx
@@ -0,0 +1,111 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { harvestAmounts } from '../../../util/convert-units/unit';
+import Checkbox from '../../Form/Checkbox';
+import Unit from '../../Form/Unit';
+import ReactSelect from '../../Form/ReactSelect';
+
+export const PureHarvestingTaskReadOnly = ({
+ system,
+ register,
+ control,
+ setValue,
+ getValues,
+ watch,
+ isCompleted,
+ disabled = false,
+}) => {
+ const { t } = useTranslation();
+ const HARVEST_QUANTITY = 'harvest_task.projected_quantity';
+ const HARVEST_QUANTITY_UNIT = 'harvest_task.projected_quantity_unit';
+ const HARVEST_EVERYTHING = 'harvest_task.harvest_everything';
+
+ const harvest_everything = watch(HARVEST_EVERYTHING);
+
+ return (
+ <>
+ {!isCompleted && (
+ <>
+ {!harvest_everything && (
+
+ )}
+ {harvest_everything && (
+
+ )}
+ >
+ )}
+ >
+ );
+};
+
+export const PureHavestTaskCompleted = ({
+ system,
+ register,
+ control,
+ setValue,
+ getValues,
+ watch,
+ task,
+ harvestUseTypes,
+ disabled = false,
+}) => {
+ const { t } = useTranslation();
+ const harvest_uses = task.harvest_task.harvest_use;
+ const harvest_uses_type_map = {};
+ for (let i = 0; i < harvestUseTypes.length; i++) {
+ harvest_uses_type_map[harvestUseTypes[i].harvest_use_type_id] = harvestUseTypes[i];
+ }
+
+ return (
+ <>
+ {harvest_uses?.map((use, index) => (
+
+
+
+
+ ))}
+ >
+ );
+};
diff --git a/packages/webapp/src/components/Task/HarvestingTask/index.js b/packages/webapp/src/components/Task/HarvestingTask/index.js
deleted file mode 100644
index 5243dec0d8..0000000000
--- a/packages/webapp/src/components/Task/HarvestingTask/index.js
+++ /dev/null
@@ -1,174 +0,0 @@
-import React, { useMemo } from 'react';
-import { useTranslation } from 'react-i18next';
-import Input from '../../Form/Input';
-import { useFieldArray } from 'react-hook-form';
-import { Info } from '../../Typography';
-import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
-import PageBreak from '../../PageBreak';
-import Unit from '../../Form/Unit';
-import { harvestAmounts } from '../../../util/unit';
-import styles from './styles.module.scss';
-import Checkbox from '../../Form/Checkbox';
-
-const HARVEST_QUANTITY = 'projected_quantity';
-const HARVEST_QUANTITY_UNIT = 'projected_quantity_unit';
-const NOTES = 'notes';
-const HARVEST_EVERYTHING = 'harvest_everything';
-
-const PureHarvestingTask = ({
- persistedFormData,
- setValue,
- getValues,
- watch,
- control,
- register,
- system,
- managementPlanByLocations,
- wildManagementPlanTiles,
-}) => {
- const { t } = useTranslation();
- const managementPlansMap = useMemo(() => {
- return Object.keys(managementPlanByLocations).reduce((managementPlansMap, location_id) => {
- for (const managementPlan of managementPlanByLocations[location_id]) {
- managementPlansMap[managementPlan.management_plan_id] = managementPlan;
- }
- return managementPlansMap;
- }, {});
- }, []);
- const { fields, append } = useFieldArray({
- control,
- name: 'harvest_tasks',
- shouldUnregister: false,
- });
-
- return (
- <>
- {t('ADD_TASK.HARVESTING_INFO')}
- {Object.keys(managementPlanByLocations).map((location_id) => {
- const location_name = managementPlanByLocations[location_id][0].location.name;
- return (
-
-
-
- {fields.map((field, index) => {
- let managementLocation = field.id.split('.')[0];
- let managementPlanId = field.id.split('.')[1];
- let managementPlan = managementPlansMap[managementPlanId];
- if (managementLocation === location_id) {
- return (
-
- );
- }
- })}
-
-
- );
- })}
- {wildManagementPlanTiles?.length && (
-
-
-
- {fields.map((field, index) => {
- let managementLocation = field.id.split('.')[0];
- let managementPlanId = field.id.split('.')[1];
- let managementPlan = wildManagementPlanTiles.find(
- ({ management_plan_id }) => management_plan_id === Number(managementPlanId),
- );
- if (managementLocation === 'PIN_LOCATION') {
- return (
-
- );
- }
- })}
-
-
- )}
- >
- );
-};
-
-function HarvestForm({
- managementPlan,
- field,
- register,
- index,
- system,
- setValue,
- getValues,
- watch,
- control,
-}) {
- const { t } = useTranslation();
- const quantityName = `harvest_tasks.${index}.` + HARVEST_QUANTITY;
- const is_harvest_everything = watch(`harvest_tasks.${index}.` + HARVEST_EVERYTHING);
- return (
-
-
-
-
- e.target.checked && setValue(quantityName, '')}
- sm
- />
-
-
-
- );
-}
-
-export default PureHarvestingTask;
diff --git a/packages/webapp/src/components/Task/HarvestingTask/index.jsx b/packages/webapp/src/components/Task/HarvestingTask/index.jsx
new file mode 100644
index 0000000000..46a1b1eaff
--- /dev/null
+++ b/packages/webapp/src/components/Task/HarvestingTask/index.jsx
@@ -0,0 +1,174 @@
+import React, { useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+import Input from '../../Form/Input';
+import { useFieldArray } from 'react-hook-form';
+import { Info } from '../../Typography';
+import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
+import PageBreak from '../../PageBreak';
+import Unit from '../../Form/Unit';
+import { harvestAmounts } from '../../../util/convert-units/unit';
+import styles from './styles.module.scss';
+import Checkbox from '../../Form/Checkbox';
+
+const HARVEST_QUANTITY = 'projected_quantity';
+const HARVEST_QUANTITY_UNIT = 'projected_quantity_unit';
+const NOTES = 'notes';
+const HARVEST_EVERYTHING = 'harvest_everything';
+
+const PureHarvestingTask = ({
+ persistedFormData,
+ setValue,
+ getValues,
+ watch,
+ control,
+ register,
+ system,
+ managementPlanByLocations,
+ wildManagementPlanTiles,
+}) => {
+ const { t } = useTranslation();
+ const managementPlansMap = useMemo(() => {
+ return Object.keys(managementPlanByLocations).reduce((managementPlansMap, location_id) => {
+ for (const managementPlan of managementPlanByLocations[location_id]) {
+ managementPlansMap[managementPlan.management_plan_id] = managementPlan;
+ }
+ return managementPlansMap;
+ }, {});
+ }, []);
+ const { fields, append } = useFieldArray({
+ control,
+ name: 'harvest_tasks',
+ shouldUnregister: false,
+ });
+
+ return (
+ <>
+ {t('ADD_TASK.HARVESTING_INFO')}
+ {Object.keys(managementPlanByLocations).map((location_id) => {
+ const location_name = managementPlanByLocations[location_id][0].location.name;
+ return (
+
+
+
+ {fields.map((field, index) => {
+ let managementLocation = field?.location_id;
+ let managementPlanId = field?.management_plan_id;
+ let managementPlan = managementPlansMap[managementPlanId];
+ if (managementLocation === location_id) {
+ return (
+
+ );
+ }
+ })}
+
+
+ );
+ })}
+ {!!wildManagementPlanTiles?.length && (
+
+
+
+ {fields.map((field, index) => {
+ let managementLocation = field?.location_id;
+ let managementPlanId = field?.management_plan_id;
+ let managementPlan = wildManagementPlanTiles.find(
+ ({ management_plan_id }) => management_plan_id === Number(managementPlanId),
+ );
+ if (managementLocation === 'PIN_LOCATION') {
+ return (
+
+ );
+ }
+ })}
+
+
+ )}
+ >
+ );
+};
+
+function HarvestForm({
+ managementPlan,
+ field,
+ register,
+ index,
+ system,
+ setValue,
+ getValues,
+ watch,
+ control,
+}) {
+ const { t } = useTranslation();
+ const quantityName = `harvest_tasks.${index}.` + HARVEST_QUANTITY;
+ const is_harvest_everything = watch(`harvest_tasks.${index}.` + HARVEST_EVERYTHING);
+ return (
+
+
+
+
+ e.target.checked && setValue(quantityName, '')}
+ sm
+ />
+
+
+
+ );
+}
+
+export default PureHarvestingTask;
diff --git a/packages/webapp/src/components/Task/PestControlTask/index.js b/packages/webapp/src/components/Task/PestControlTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PestControlTask/index.js
rename to packages/webapp/src/components/Task/PestControlTask/index.jsx
diff --git a/packages/webapp/src/components/Task/PlantingTask/index.js b/packages/webapp/src/components/Task/PlantingTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PlantingTask/index.js
rename to packages/webapp/src/components/Task/PlantingTask/index.jsx
diff --git a/packages/webapp/src/components/Task/PureAddCustomTask/index.js b/packages/webapp/src/components/Task/PureAddCustomTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PureAddCustomTask/index.js
rename to packages/webapp/src/components/Task/PureAddCustomTask/index.jsx
diff --git a/packages/webapp/src/components/Task/PureEditCustomTask/index.js b/packages/webapp/src/components/Task/PureEditCustomTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PureEditCustomTask/index.js
rename to packages/webapp/src/components/Task/PureEditCustomTask/index.jsx
diff --git a/packages/webapp/src/components/Task/PureEditCustomTaskUpdate/index.js b/packages/webapp/src/components/Task/PureEditCustomTaskUpdate/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PureEditCustomTaskUpdate/index.js
rename to packages/webapp/src/components/Task/PureEditCustomTaskUpdate/index.jsx
diff --git a/packages/webapp/src/components/Task/PureTaskAssignment/index.js b/packages/webapp/src/components/Task/PureTaskAssignment/index.js
deleted file mode 100644
index cc175f17ef..0000000000
--- a/packages/webapp/src/components/Task/PureTaskAssignment/index.js
+++ /dev/null
@@ -1,158 +0,0 @@
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import Button from '../../Form/Button';
-import Form from '../../Form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { Controller, useForm } from 'react-hook-form';
-import { Main } from '../../Typography';
-import styles from '../../CertificationReportingPeriod/styles.module.scss';
-import ReactSelect from '../../Form/ReactSelect';
-import RadioGroup from '../../Form/RadioGroup';
-import Input, { getInputErrors, numberOnKeyDown } from '../../Form/Input';
-import { cloneObject } from '../../../util';
-
-const PureTaskAssignment = ({
- onSubmit,
- handleGoBack,
- onError,
- userFarmOptions,
- wageData,
- isFarmWorker,
- currencySymbol,
- useHookFormPersist,
- persistedFormData,
-}) => {
- const { t } = useTranslation();
- const OVERRIDE_HOURLY_WAGE = 'override_hourly_wage';
- const ASSIGNEE = 'assignee_user_id';
- const WAGE_OVERRIDE = 'wage_at_moment';
- const {
- register,
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- formState: { errors, isValid },
- clearErrors,
- } = useForm({
- mode: 'onChange',
- shouldUnregister: true,
- defaultValues: {
- assignee_user_id: persistedFormData.assignee_user_id
- ? persistedFormData.assignee_user_id
- : userFarmOptions.length === 2
- ? userFarmOptions[1]
- : userFarmOptions[0],
- [OVERRIDE_HOURLY_WAGE]: persistedFormData[OVERRIDE_HOURLY_WAGE] || false,
- wage_at_moment: persistedFormData.wage_at_moment ? persistedFormData.wage_at_moment : null,
- ...cloneObject(persistedFormData),
- },
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const override = watch(OVERRIDE_HOURLY_WAGE);
-
- const populateWageData = (assignee) => {
- const wageDataOfCurrentlyAssigned = wageData.find(
- (userWageObject) => !!userWageObject[assignee?.value],
- );
- const hourlyWageOfCurrentlyAssigned =
- typeof wageDataOfCurrentlyAssigned === 'undefined'
- ? 0
- : wageDataOfCurrentlyAssigned[assignee.value].hourly_wage;
- setValue(WAGE_OVERRIDE, hourlyWageOfCurrentlyAssigned);
- clearErrors(WAGE_OVERRIDE);
- };
-
- return (
- <>
-
- >
- );
-};
-
-export default PureTaskAssignment;
diff --git a/packages/webapp/src/components/Task/PureTaskAssignment/index.jsx b/packages/webapp/src/components/Task/PureTaskAssignment/index.jsx
new file mode 100644
index 0000000000..823fe090ad
--- /dev/null
+++ b/packages/webapp/src/components/Task/PureTaskAssignment/index.jsx
@@ -0,0 +1,163 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import Button from '../../Form/Button';
+import Form from '../../Form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { Controller, useForm } from 'react-hook-form';
+import { Main } from '../../Typography';
+import styles from '../../CertificationReportingPeriod/styles.module.scss';
+import ReactSelect from '../../Form/ReactSelect';
+import RadioGroup from '../../Form/RadioGroup';
+import Input, { getInputErrors, numberOnKeyDown } from '../../Form/Input';
+import { cloneObject } from '../../../util';
+
+const PureTaskAssignment = ({
+ onSubmit,
+ handleGoBack,
+ onError,
+ userFarmOptions,
+ wageData,
+ isFarmWorker,
+ currencySymbol,
+ useHookFormPersist,
+ persistedFormData,
+}) => {
+ const { t } = useTranslation();
+ const OVERRIDE_HOURLY_WAGE = 'override_hourly_wage';
+ const ASSIGNEE = 'assignee_user_id';
+ const WAGE_OVERRIDE = 'wage_at_moment';
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ clearErrors,
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: true,
+ defaultValues: {
+ assignee_user_id: persistedFormData.assignee_user_id
+ ? persistedFormData.assignee_user_id
+ : userFarmOptions.length === 2
+ ? userFarmOptions[1]
+ : userFarmOptions[0],
+ [OVERRIDE_HOURLY_WAGE]: persistedFormData[OVERRIDE_HOURLY_WAGE] || false,
+ wage_at_moment: persistedFormData.wage_at_moment ? persistedFormData.wage_at_moment : null,
+ ...cloneObject(persistedFormData),
+ },
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const override = watch(OVERRIDE_HOURLY_WAGE);
+
+ const populateWageData = (assignee) => {
+ const wageDataOfCurrentlyAssigned = wageData.find(
+ (userWageObject) => !!userWageObject[assignee?.value],
+ );
+ const hourlyWageOfCurrentlyAssigned =
+ typeof wageDataOfCurrentlyAssigned === 'undefined'
+ ? 0
+ : wageDataOfCurrentlyAssigned[assignee.value].hourly_wage;
+ setValue(WAGE_OVERRIDE, hourlyWageOfCurrentlyAssigned);
+ clearErrors(WAGE_OVERRIDE);
+ };
+
+ return (
+ <>
+
+ >
+ );
+};
+
+export default PureTaskAssignment;
diff --git a/packages/webapp/src/components/Task/PureTaskCrops/index.js b/packages/webapp/src/components/Task/PureTaskCrops/index.js
deleted file mode 100644
index 65aa1b1890..0000000000
--- a/packages/webapp/src/components/Task/PureTaskCrops/index.js
+++ /dev/null
@@ -1,326 +0,0 @@
-import React, { useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { Main, Underlined } from '../../Typography';
-import { useForm } from 'react-hook-form';
-import Button from '../../Form/Button';
-import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
-import PureCropTileContainer from '../../CropTile/CropTileContainer';
-import PageBreak from '../../PageBreak';
-import Input from '../../Form/Input';
-import Square from '../../Square';
-import produce from 'immer';
-import { cloneObject } from '../../../util';
-import { getArrayWithUniqueValues } from '../../../util/getArrayWithUniqueValues';
-
-const PureTaskCrops = ({
- handleGoBack,
- onError,
- persistedFormData,
- onContinue,
-
-
- useHookFormPersist,
- managementPlansByLocationIds,
- wildManagementPlanTiles,
- isMulti = true,
- isRequired,
-}) => {
- const { t } = useTranslation();
-
- const {
- handleSubmit,
- getValues,
- watch,
- control,
- setValue,
- register,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- defaultValues: cloneObject(persistedFormData),
- });
- //TODO managementPlans should be an array or management_plan_id
- const { historyCancel } = useHookFormPersist(getValues);
-
- const [filter, setFilter] = useState();
- const onFilterChange = (e) => {
- setFilter(e.target.value);
- };
-
- const locationIds = Object.keys(managementPlansByLocationIds);
- const filterManagementPlansByCropVarietyName = (mp) =>
- mp.crop_variety_name.toLowerCase().includes(filter?.toLowerCase()) ||
- mp.crop_common_name.toLowerCase().includes(filter?.toLowerCase());
- const managementPlansFilteredByInput = useMemo(() => {
- if (!filter) {
- return managementPlansByLocationIds;
- } else {
- return locationIds.reduce((filteredManagementPlansByLocationId, locationId) => {
- filteredManagementPlansByLocationId[locationId] = managementPlansByLocationIds[
- locationId
- ]?.filter(filterManagementPlansByCropVarietyName);
- return filteredManagementPlansByLocationId;
- }, {});
- }
- }, [filter, managementPlansByLocationIds]);
-
- const wildCropTilesFilteredByInput = useMemo(() => {
- if (!filter) return wildManagementPlanTiles;
- else return wildManagementPlanTiles?.filter(filterManagementPlansByCropVarietyName);
- }, [wildManagementPlanTiles, filter]);
-
- const MANAGEMENT_PLANS = 'managementPlans';
- register(MANAGEMENT_PLANS, { required: false });
-
- const onSubmit = () => {
- setValue(
- MANAGEMENT_PLANS,
- selectedManagementPlanIds.map((management_plan_id) => ({ management_plan_id })),
- );
- onContinue();
- };
-
- const managementPlanIds = useMemo(() => {
- const locationManagementPlans = Object.keys(managementPlansByLocationIds).reduce(
- (managementPlanIds, location_id) => {
- return [
- ...managementPlanIds,
- ...managementPlansByLocationIds[location_id].map(
- ({ management_plan_id }) => management_plan_id,
- ),
- ];
- },
- [],
- );
-
- const wildManagementPlanIds =
- wildManagementPlanTiles?.map(({ management_plan_id }) => management_plan_id) || [];
- return [...locationManagementPlans, ...wildManagementPlanIds];
- }, []);
-
- const [selectedManagementPlanIds, setSelectedManagementPlanIds] = useState(
- isMulti
- ? (getValues(MANAGEMENT_PLANS) || [])
- .map((management_plan) => management_plan.management_plan_id)
- .filter((management_plan_id) => managementPlanIds.includes(management_plan_id))
- : getValues(MANAGEMENT_PLANS)?.length
- ? [getValues(MANAGEMENT_PLANS)?.[0]?.management_plan_id]
- : [],
- );
-
- const onSelectManagementPlan = (management_plan_id) => {
- setSelectedManagementPlanIds((selectedManagementPlanIds) => {
- if (!isMulti) {
- return [management_plan_id];
- } else {
- return produce(selectedManagementPlanIds, (selectedManagementPlanIds) => {
- if (selectedManagementPlanIds.includes(management_plan_id)) {
- selectedManagementPlanIds = selectedManagementPlanIds.splice(
- selectedManagementPlanIds.indexOf(management_plan_id),
- 1,
- );
- }
- selectedManagementPlanIds.push(management_plan_id);
- });
- }
- });
- };
- const selectAllCrops = () => {
- setSelectedManagementPlanIds((prevManagementPlanIds) =>
- Object.keys(managementPlansFilteredByInput).reduce((managementPlanIds, location_id) => {
- managementPlanIds = [
- ...prevManagementPlanIds,
- ...managementPlanIds,
- ...managementPlansFilteredByInput[location_id].map(
- ({ management_plan_id }) => management_plan_id,
- ),
- ];
- return getArrayWithUniqueValues(managementPlanIds);
- }, []),
- );
- selectAllWildManagementPlans();
- };
-
- const selectAllManagementPlansOfALocation = (location_id) => {
- setSelectedManagementPlanIds((prevManagementPlanIds) =>
- getArrayWithUniqueValues([
- ...prevManagementPlanIds,
- ...managementPlansFilteredByInput[location_id].map(
- ({ management_plan_id }) => management_plan_id,
- ),
- ]),
- );
- };
-
- const clearAllManagementPlansOfALocation = (location_id) => {
- const managementPlanIdsOfLocation = managementPlansFilteredByInput[location_id].map(
- ({ management_plan_id }) => management_plan_id,
- );
- setSelectedManagementPlanIds(
- selectedManagementPlanIds.filter(
- (management_plan_id) => !managementPlanIdsOfLocation.includes(management_plan_id),
- ),
- );
- };
-
- const selectAllWildManagementPlans = () => {
- wildCropTilesFilteredByInput?.length &&
- setSelectedManagementPlanIds((prevManagementPlanIds) =>
- getArrayWithUniqueValues([
- ...prevManagementPlanIds,
- ...wildCropTilesFilteredByInput.map(({ management_plan_id }) => management_plan_id),
- ]),
- );
- };
-
- const clearAllWildManagementPlans = () => {
- const managementPlanIds = wildCropTilesFilteredByInput?.map(
- ({ management_plan_id }) => management_plan_id,
- );
- managementPlanIds?.length &&
- setSelectedManagementPlanIds(
- selectedManagementPlanIds.filter(
- (management_plan_id) => !managementPlanIds.includes(management_plan_id),
- ),
- );
- };
-
- const clearAllCrops = () => {
- const managementPlanIds = Object.values(managementPlansFilteredByInput).reduce(
- (managementPlanIds, managementPlans) => [
- ...managementPlanIds,
- ...managementPlans.map(({ management_plan_id }) => management_plan_id),
- ],
- [],
- );
- const wildManagementPlanIds = wildCropTilesFilteredByInput?.map(
- ({ management_plan_id }) => management_plan_id,
- );
- setSelectedManagementPlanIds(
- selectedManagementPlanIds.filter(
- (management_plan_id) =>
- !managementPlanIds.includes(management_plan_id) &&
- !wildManagementPlanIds?.includes(management_plan_id),
- ),
- );
- };
-
- const disabled = isRequired && !selectedManagementPlanIds?.length;
-
- return (
- <>
-
- >
- );
-};
-
-export default PureTaskCrops;
diff --git a/packages/webapp/src/components/Task/PureTaskCrops/index.jsx b/packages/webapp/src/components/Task/PureTaskCrops/index.jsx
new file mode 100644
index 0000000000..1dae4b469f
--- /dev/null
+++ b/packages/webapp/src/components/Task/PureTaskCrops/index.jsx
@@ -0,0 +1,343 @@
+import React, { useEffect, useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { Main, Underlined } from '../../Typography';
+import { useForm } from 'react-hook-form';
+import Button from '../../Form/Button';
+import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
+import PureCropTileContainer from '../../CropTile/CropTileContainer';
+import PageBreak from '../../PageBreak';
+import Input from '../../Form/Input';
+import Square from '../../Square';
+import produce from 'immer';
+import { cloneObject } from '../../../util';
+import { getArrayWithUniqueValues } from '../../../util/getArrayWithUniqueValues';
+
+const PureTaskCrops = ({
+ handleGoBack,
+ onError,
+ persistedFormData,
+ onContinue,
+ bypass,
+ useHookFormPersist,
+ managementPlansByLocationIds,
+ wildManagementPlanTiles,
+ isMulti = true,
+ isRequired,
+ defaultManagementPlanId,
+ history,
+ location,
+}) => {
+ const { t } = useTranslation();
+
+ const {
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ setValue,
+ register,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: cloneObject(persistedFormData),
+ });
+ //TODO managementPlans should be an array or management_plan_id
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const [filter, setFilter] = useState();
+ const onFilterChange = (e) => {
+ setFilter(e.target.value);
+ };
+
+ const locationIds = Object.keys(managementPlansByLocationIds);
+
+ if (bypass) {
+ history.replace('/add_task/task_locations', location.state);
+ onContinue();
+ }
+
+ const filterManagementPlansByCropVarietyName = (mp) =>
+ mp.crop_variety_name.toLowerCase().includes(filter?.toLowerCase()) ||
+ mp.crop_common_name.toLowerCase().includes(filter?.toLowerCase());
+ const managementPlansFilteredByInput = useMemo(() => {
+ if (!filter) {
+ return managementPlansByLocationIds;
+ } else {
+ return locationIds.reduce((filteredManagementPlansByLocationId, locationId) => {
+ filteredManagementPlansByLocationId[locationId] = managementPlansByLocationIds[
+ locationId
+ ]?.filter(filterManagementPlansByCropVarietyName);
+ return filteredManagementPlansByLocationId;
+ }, {});
+ }
+ }, [filter, managementPlansByLocationIds]);
+
+ const wildCropTilesFilteredByInput = useMemo(() => {
+ if (!filter) return wildManagementPlanTiles;
+ else return wildManagementPlanTiles?.filter(filterManagementPlansByCropVarietyName);
+ }, [wildManagementPlanTiles, filter]);
+
+ const MANAGEMENT_PLANS = 'managementPlans';
+ register(MANAGEMENT_PLANS, { required: false });
+
+ const onSubmit = () => {
+ setValue(
+ MANAGEMENT_PLANS,
+ selectedManagementPlanIds.map((management_plan_id) => ({ management_plan_id })),
+ );
+ onContinue();
+ };
+
+ const managementPlanIds = useMemo(() => {
+ const locationManagementPlans = Object.keys(managementPlansByLocationIds).reduce(
+ (managementPlanIds, location_id) => {
+ return [
+ ...managementPlanIds,
+ ...managementPlansByLocationIds[location_id].map(
+ ({ management_plan_id }) => management_plan_id,
+ ),
+ ];
+ },
+ [],
+ );
+
+ const wildManagementPlanIds =
+ wildManagementPlanTiles?.map(({ management_plan_id }) => management_plan_id) || [];
+ return [...locationManagementPlans, ...wildManagementPlanIds];
+ }, []);
+
+ const [selectedManagementPlanIds, setSelectedManagementPlanIds] = useState(
+ isMulti
+ ? (getValues(MANAGEMENT_PLANS) || [])
+ .map((management_plan) => management_plan.management_plan_id)
+ .filter((management_plan_id) => managementPlanIds.includes(management_plan_id))
+ : getValues(MANAGEMENT_PLANS)?.length
+ ? [getValues(MANAGEMENT_PLANS)?.[0]?.management_plan_id]
+ : [],
+ );
+
+ const onSelectManagementPlan = (management_plan_id) => {
+ setSelectedManagementPlanIds((selectedManagementPlanIds) => {
+ if (!isMulti) {
+ return [management_plan_id];
+ } else {
+ return produce(selectedManagementPlanIds, (selectedManagementPlanIds) => {
+ if (selectedManagementPlanIds.includes(management_plan_id)) {
+ selectedManagementPlanIds = selectedManagementPlanIds.splice(
+ selectedManagementPlanIds.indexOf(management_plan_id),
+ 1,
+ );
+ }
+ selectedManagementPlanIds.push(management_plan_id);
+ });
+ }
+ });
+ };
+ const selectAllCrops = () => {
+ setSelectedManagementPlanIds((prevManagementPlanIds) =>
+ Object.keys(managementPlansFilteredByInput).reduce((managementPlanIds, location_id) => {
+ managementPlanIds = [
+ ...prevManagementPlanIds,
+ ...managementPlanIds,
+ ...managementPlansFilteredByInput[location_id].map(
+ ({ management_plan_id }) => management_plan_id,
+ ),
+ ];
+ return getArrayWithUniqueValues(managementPlanIds);
+ }, []),
+ );
+ selectAllWildManagementPlans();
+ };
+
+ const selectAllManagementPlansOfALocation = (location_id) => {
+ setSelectedManagementPlanIds((prevManagementPlanIds) =>
+ getArrayWithUniqueValues([
+ ...prevManagementPlanIds,
+ ...managementPlansFilteredByInput[location_id].map(
+ ({ management_plan_id }) => management_plan_id,
+ ),
+ ]),
+ );
+ };
+
+ const clearAllManagementPlansOfALocation = (location_id) => {
+ const managementPlanIdsOfLocation = managementPlansFilteredByInput[location_id].map(
+ ({ management_plan_id }) => management_plan_id,
+ );
+ setSelectedManagementPlanIds(
+ selectedManagementPlanIds.filter(
+ (management_plan_id) => !managementPlanIdsOfLocation.includes(management_plan_id),
+ ),
+ );
+ };
+
+ const selectAllWildManagementPlans = () => {
+ wildCropTilesFilteredByInput?.length &&
+ setSelectedManagementPlanIds((prevManagementPlanIds) =>
+ getArrayWithUniqueValues([
+ ...prevManagementPlanIds,
+ ...wildCropTilesFilteredByInput.map(({ management_plan_id }) => management_plan_id),
+ ]),
+ );
+ };
+
+ const clearAllWildManagementPlans = () => {
+ const managementPlanIds = wildCropTilesFilteredByInput?.map(
+ ({ management_plan_id }) => management_plan_id,
+ );
+ managementPlanIds?.length &&
+ setSelectedManagementPlanIds(
+ selectedManagementPlanIds.filter(
+ (management_plan_id) => !managementPlanIds.includes(management_plan_id),
+ ),
+ );
+ };
+
+ const clearAllCrops = () => {
+ const managementPlanIds = Object.values(managementPlansFilteredByInput).reduce(
+ (managementPlanIds, managementPlans) => [
+ ...managementPlanIds,
+ ...managementPlans.map(({ management_plan_id }) => management_plan_id),
+ ],
+ [],
+ );
+ const wildManagementPlanIds = wildCropTilesFilteredByInput?.map(
+ ({ management_plan_id }) => management_plan_id,
+ );
+ setSelectedManagementPlanIds(
+ selectedManagementPlanIds.filter(
+ (management_plan_id) =>
+ !managementPlanIds.includes(management_plan_id) &&
+ !wildManagementPlanIds?.includes(management_plan_id),
+ ),
+ );
+ };
+
+ const disabled = isRequired && !selectedManagementPlanIds?.length;
+
+ useEffect(() => {
+ defaultManagementPlanId && setSelectedManagementPlanIds([parseInt(defaultManagementPlanId)]);
+ }, []);
+
+ return (
+ <>
+
+ >
+ );
+};
+
+export default PureTaskCrops;
diff --git a/packages/webapp/src/components/Task/PureTaskDetails/index.js b/packages/webapp/src/components/Task/PureTaskDetails/index.js
deleted file mode 100644
index f352953a89..0000000000
--- a/packages/webapp/src/components/Task/PureTaskDetails/index.js
+++ /dev/null
@@ -1,173 +0,0 @@
-import React, { useMemo } from 'react';
-import Form from '../../Form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { useTranslation } from 'react-i18next';
-import { Main } from '../../Typography';
-import { useForm } from 'react-hook-form';
-import Button from '../../Form/Button';
-import PureCleaningTask from '../CleaningTask';
-import PureSoilAmendmentTask from '../SoilAmendmentTask';
-import PureFieldWorkTask from '../FieldWorkTask';
-import PurePestControlTask from '../PestControlTask';
-import PureHarvestingTask from '../HarvestingTask';
-import InputAutoSize from '../../Form/InputAutoSize';
-import { isTaskType } from '../../../containers/Task/useIsTaskType';
-
-export default function PureTaskDetails({
- handleGoBack,
- onSubmit,
- onError,
- persistedFormData,
- useHookFormPersist,
-
-
- products,
- system,
- selectedTaskType,
- farm,
- managementPlanByLocations,
- wildManagementPlanTiles,
-}) {
- const { t } = useTranslation();
- const taskType = selectedTaskType.task_translation_key;
- const taskName = selectedTaskType.task_name;
- const isCustomType = !!selectedTaskType.farm_id;
- const isHarvest = isTaskType(selectedTaskType, 'HARVEST_TASK');
-
- const defaults = {
- CLEANING_TASK: { cleaning_task: { agent_used: false } },
- };
-
- const harvest_tasks = useMemo(() => {
- const harvestTasksById = persistedFormData?.harvest_tasks?.reduce(
- (harvestTasksById, harvestTask) => {
- harvestTasksById[harvestTask.id] = harvestTask;
- return harvestTasksById;
- },
- {},
- );
-
- const harvestTasksWithLocations = Object.keys(managementPlanByLocations).reduce(
- (harvest_tasks, location_id) => {
- for (const managementPlan of managementPlanByLocations[location_id]) {
- const id = `${location_id}.${managementPlan.management_plan_id}`;
- harvest_tasks.push(
- harvestTasksById?.[id] || {
- id,
- harvest_everything: false,
- },
- );
- }
- return harvest_tasks;
- },
- [],
- );
-
- const allHarvestTasks =
- wildManagementPlanTiles?.reduce?.((harvest_tasks, managementPlan) => {
- const id = `PIN_LOCATION.${managementPlan.management_plan_id}`;
- harvest_tasks.push(
- harvestTasksById?.[id] || {
- id,
- harvest_everything: false,
- },
- );
- return harvest_tasks;
- }, harvestTasksWithLocations) || harvestTasksWithLocations;
-
- return allHarvestTasks;
- }, [persistedFormData]);
-
- const formFunctions = useForm({
- mode: 'onChange',
- defaultValues: {
- ...defaults[taskType],
- ...persistedFormData,
- harvest_tasks: isHarvest ? harvest_tasks : persistedFormData?.harvest_tasks,
- },
- });
-
- const {
- handleSubmit,
- watch,
- register,
- setValue,
- getValues,
- control,
- formState: { errors, isValid },
- } = formFunctions;
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const NOTES = 'notes';
- register(NOTES, { required: false });
-
- return (
- <>
-
- >
- );
-}
-
-const taskComponents = {
- CLEANING_TASK: (props) => ,
- FIELD_WORK_TASK: (props) => ,
- SOIL_AMENDMENT_TASK: (props) => ,
- PEST_CONTROL_TASK: (props) => ,
- HARVEST_TASK: (props) => ,
-};
diff --git a/packages/webapp/src/components/Task/PureTaskDetails/index.jsx b/packages/webapp/src/components/Task/PureTaskDetails/index.jsx
new file mode 100644
index 0000000000..d14bb6824e
--- /dev/null
+++ b/packages/webapp/src/components/Task/PureTaskDetails/index.jsx
@@ -0,0 +1,177 @@
+import React, { useMemo } from 'react';
+import Form from '../../Form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { useTranslation } from 'react-i18next';
+import { Main } from '../../Typography';
+import { useForm } from 'react-hook-form';
+import Button from '../../Form/Button';
+import PureCleaningTask from '../CleaningTask';
+import PureSoilAmendmentTask from '../SoilAmendmentTask';
+import PureFieldWorkTask from '../FieldWorkTask';
+import PurePestControlTask from '../PestControlTask';
+import PureHarvestingTask from '../HarvestingTask';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { isTaskType } from '../../../containers/Task/useIsTaskType';
+
+export default function PureTaskDetails({
+ handleGoBack,
+ onSubmit,
+ onError,
+ persistedFormData,
+ useHookFormPersist,
+ products,
+ system,
+ selectedTaskType,
+ farm,
+ managementPlanByLocations,
+ wildManagementPlanTiles,
+}) {
+ const { t } = useTranslation();
+ const taskType = selectedTaskType.task_translation_key;
+ const taskName = selectedTaskType.task_name;
+ const isCustomType = !!selectedTaskType.farm_id;
+ const isHarvest = isTaskType(selectedTaskType, 'HARVEST_TASK');
+
+ const defaults = {
+ CLEANING_TASK: { cleaning_task: { agent_used: false } },
+ };
+
+ const harvest_tasks = useMemo(() => {
+ const harvestTasksById = persistedFormData?.harvest_tasks?.reduce(
+ (harvestTasksById, harvestTask) => {
+ const { location_id, management_plan_id } = harvestTask;
+ harvestTasksById[`${location_id}.${management_plan_id}`] = harvestTask;
+ return harvestTasksById;
+ },
+ {},
+ );
+
+ const harvestTasksWithLocations = Object.keys(managementPlanByLocations).reduce(
+ (harvest_tasks, location_id) => {
+ for (const { management_plan_id } of managementPlanByLocations[location_id]) {
+ harvest_tasks.push(
+ harvestTasksById?.[`${location_id}.${management_plan_id}`] || {
+ location_id,
+ management_plan_id,
+ harvest_everything: false,
+ },
+ );
+ }
+ return harvest_tasks;
+ },
+ [],
+ );
+
+ const allHarvestTasks =
+ wildManagementPlanTiles?.reduce?.((harvest_tasks, { management_plan_id }) => {
+ harvest_tasks.push(
+ harvestTasksById?.[`PIN_LOCATION.${management_plan_id}`] || {
+ location_id: 'PIN_LOCATION',
+ management_plan_id,
+ harvest_everything: false,
+ },
+ );
+ return harvest_tasks;
+ }, harvestTasksWithLocations) || harvestTasksWithLocations;
+
+ return allHarvestTasks;
+ }, [persistedFormData]);
+
+ const formFunctions = useForm({
+ mode: 'onChange',
+ defaultValues: {
+ ...defaults[taskType],
+ ...persistedFormData,
+ harvest_tasks: isHarvest ? harvest_tasks : persistedFormData?.harvest_tasks,
+ },
+ });
+
+ const {
+ handleSubmit,
+ watch,
+ register,
+ setValue,
+ getValues,
+ control,
+ formState: { errors, isValid },
+ } = formFunctions;
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const NOTES = 'notes';
+ register(NOTES, { required: false });
+
+ return (
+ <>
+
+ >
+ );
+}
+
+const taskComponents = {
+ CLEANING_TASK: (props) => ,
+ FIELD_WORK_TASK: (props) => ,
+ SOIL_AMENDMENT_TASK: (props) => ,
+ PEST_CONTROL_TASK: (props) => ,
+ HARVEST_TASK: (props) => ,
+};
diff --git a/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.js b/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.js
deleted file mode 100644
index 260b3a3412..0000000000
--- a/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import Button from '../../Form/Button';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { cloneObject } from '../../../util';
-import { PurePlantingMethod } from '../../Crop/PlantingMethod/PurePlantingMethod';
-
-export function PureTaskPlantingMethod({ useHookFormPersist, persistedFormData, history, entryPath}) {
- const { t } = useTranslation();
-
- const {
- handleSubmit,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(persistedFormData),
- });
-
- const PLANTING_METHOD = `transplant_task.planting_management_plan.planting_method`;
- const planting_method = watch(PLANTING_METHOD);
-
- useHookFormPersist(getValues);
-
- const onError = () => {};
-
- const onSubmit = () => history.push(`/add_task/${planting_method.toLowerCase()}`);
- const onGoBack = () => history.goBack();
- const onCancel = () => history.push(entryPath);
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PureTaskPlantingMethod.prototype = {
- history: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.jsx b/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.jsx
new file mode 100644
index 0000000000..2e891777da
--- /dev/null
+++ b/packages/webapp/src/components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod.jsx
@@ -0,0 +1,77 @@
+import Button from '../../Form/Button';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { cloneObject } from '../../../util';
+import { PurePlantingMethod } from '../../Crop/PlantingMethod/PurePlantingMethod';
+
+export function PureTaskPlantingMethod({
+ useHookFormPersist,
+ persistedFormData,
+ history,
+ entryPath,
+ location,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ handleSubmit,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(persistedFormData),
+ });
+
+ const PLANTING_METHOD = `transplant_task.planting_management_plan.planting_method`;
+ const planting_method = watch(PLANTING_METHOD);
+
+ useHookFormPersist(getValues);
+
+ const onError = () => {};
+
+ const onSubmit = () => history.push(`/add_task/${planting_method.toLowerCase()}`, location.state);
+ const onGoBack = () => history.back();
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PureTaskPlantingMethod.prototype = {
+ history: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Task/PureTaskTypeSelection/PureManageCustomTasks.js b/packages/webapp/src/components/Task/PureTaskTypeSelection/PureManageCustomTasks.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/PureTaskTypeSelection/PureManageCustomTasks.js
rename to packages/webapp/src/components/Task/PureTaskTypeSelection/PureManageCustomTasks.jsx
diff --git a/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.js b/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.js
deleted file mode 100644
index 70edb94612..0000000000
--- a/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.js
+++ /dev/null
@@ -1,219 +0,0 @@
-import React, { useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { Main } from '../../Typography';
-import styles from './styles.module.scss';
-import { ReactComponent as CollectSoilSample } from '../../../assets/images/task/CollectSoilSample.svg';
-import { ReactComponent as Transport } from '../../../assets/images/task/Transport.svg';
-import { ReactComponent as Clean } from '../../../assets/images/task/Clean.svg';
-import { ReactComponent as Fertilize } from '../../../assets/images/task/Fertilize.svg';
-import { ReactComponent as FieldWork } from '../../../assets/images/task/FieldWork.svg';
-import { ReactComponent as Harvest } from '../../../assets/images/task/Harvest.svg';
-import { ReactComponent as Irrigate } from '../../../assets/images/task/Irrigate.svg';
-import { ReactComponent as Maintenance } from '../../../assets/images/task/Maintenance.svg';
-import { ReactComponent as PestControl } from '../../../assets/images/task/PestControl.svg';
-import { ReactComponent as Plant } from '../../../assets/images/task/Plant.svg';
-import { ReactComponent as RecordSoilSample } from '../../../assets/images/task/RecordSoilSample.svg';
-import { ReactComponent as Sales } from '../../../assets/images/task/Sales.svg';
-import { ReactComponent as Scout } from '../../../assets/images/task/Scout.svg';
-import { ReactComponent as SocialEvent } from '../../../assets/images/task/SocialEvent.svg';
-import { ReactComponent as SoilAmendment } from '../../../assets/images/task/SoilAmendment.svg';
-import { ReactComponent as Transplant } from '../../../assets/images/task/Transplant.svg';
-import { ReactComponent as WashAndPack } from '../../../assets/images/task/WashAndPack.svg';
-import { ReactComponent as CustomTask } from '../../../assets/images/task/Custom.svg';
-import { useForm } from 'react-hook-form';
-import clsx from 'clsx';
-import Button from '../../Form/Button';
-import { PlantingTaskModal } from '../../Modals/PlantingTaskModal';
-import { isTaskType } from '../../../containers/Task/useIsTaskType';
-import { NoCropManagementPlanModal } from '../../Modals/NoCropManagementPlanModal';
-
-const icons = {
- SOIL_AMENDMENT_TASK: ,
- FIELD_WORK_TASK: ,
- HARVEST_TASK: ,
- IRRIGATION_TASK: ,
- PEST_CONTROL_TASK: ,
- PLANT_TASK: ,
- SOIL_TASK: ,
- SALE_TASK: ,
- SCOUTING_TASK: ,
- SOCIAL_TASK: ,
- TRANSPORT_TASK: ,
- WASH_AND_PACK_TASK: ,
- CLEANING_TASK: ,
- TRANSPLANT_TASK: ,
- FERTILIZE_TASK: ,
- COLLECT_SOIL_SAMPLE_TASK: ,
- MAINTENANCE_TASK: ,
-};
-
-/**
- *
- * @param isAdmin {boolean}
- * @return {Set}
- */
-const getSupportedTaskTypesSet = (isAdmin) => {
- const supportedTaskTypes = new Set([
- 'SOIL_AMENDMENT_TASK',
- 'FIELD_WORK_TASK',
- 'PEST_CONTROL_TASK',
- 'CLEANING_TASK',
- 'HARVEST_TASK',
- ]);
-
- if (isAdmin) {
- supportedTaskTypes.add('PLANT_TASK');
- supportedTaskTypes.add('TRANSPLANT_TASK');
- }
- return supportedTaskTypes;
-};
-
-export const PureTaskTypeSelection = ({
- onCustomTask,
- handleGoBack,
- history,
-
-
- persistedFormData,
- useHookFormPersist,
- onContinue,
- onError,
- taskTypes,
- customTasks,
- isAdmin,
- shouldShowPlantTaskSpotLight,
- updatePlantTaskSpotlight,
- hasCurrentManagementPlans,
-}) => {
- const { t } = useTranslation();
- const { watch, getValues, register, setValue } = useForm({
- defaultValues: persistedFormData,
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const TASK_TYPE_ID = 'task_type_id';
- register(TASK_TYPE_ID);
- const selected_task_type = watch(TASK_TYPE_ID);
-
-
- const onSelectTask = (task_type_id) => {
- setValue(TASK_TYPE_ID, task_type_id);
- onContinue();
- };
-
- const [showPlantTaskModal, setShowPlantTaskModal] = useState();
- const goToCatalogue = () => history.push('/crop_catalogue');
- const onPlantTaskTypeClick = () => {
- if (shouldShowPlantTaskSpotLight) {
- setShowPlantTaskModal(true);
- } else {
- goToCatalogue();
- }
- };
- const [showNoManagementPlanModal, setShowNoManagementPlanModal] = useState();
- const onHarvestTransplantTaskClick = (task_type_id) => {
- hasCurrentManagementPlans ? onSelectTask(task_type_id) : setShowNoManagementPlanModal(true);
- };
-
- const onTileClick = (taskType) => {
- if (isTaskType(taskType, 'PLANT_TASK')) return onPlantTaskTypeClick(taskType.task_type_id);
- if (isTaskType(taskType, 'TRANSPLANT_TASK') || isTaskType(taskType, 'HARVEST_TASK')) {
- return onHarvestTransplantTaskClick(taskType.task_type_id);
- }
- return onSelectTask(taskType.task_type_id);
- };
- return (
- <>
-
- {showPlantTaskModal && shouldShowPlantTaskSpotLight && (
- setShowPlantTaskModal(false)}
- updatePlantTaskSpotlight={updatePlantTaskSpotlight}
- />
- )}
- {showNoManagementPlanModal &&
- setShowNoManagementPlanModal(false)}
- goToCatalogue={goToCatalogue}
- />
- }
- >
- );
-};
diff --git a/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.jsx b/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.jsx
new file mode 100644
index 0000000000..bc3725169e
--- /dev/null
+++ b/packages/webapp/src/components/Task/PureTaskTypeSelection/PureTaskTypeSelection.jsx
@@ -0,0 +1,197 @@
+import React, { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { Main } from '../../Typography';
+import styles from './styles.module.scss';
+import { ReactComponent as CollectSoilSample } from '../../../assets/images/task/CollectSoilSample.svg';
+import { ReactComponent as Transport } from '../../../assets/images/task/Transport.svg';
+import { ReactComponent as Clean } from '../../../assets/images/task/Clean.svg';
+import { ReactComponent as Fertilize } from '../../../assets/images/task/Fertilize.svg';
+import { ReactComponent as FieldWork } from '../../../assets/images/task/FieldWork.svg';
+import { ReactComponent as Harvest } from '../../../assets/images/task/Harvest.svg';
+import { ReactComponent as Irrigate } from '../../../assets/images/task/Irrigate.svg';
+import { ReactComponent as Maintenance } from '../../../assets/images/task/Maintenance.svg';
+import { ReactComponent as PestControl } from '../../../assets/images/task/PestControl.svg';
+import { ReactComponent as Plant } from '../../../assets/images/task/Plant.svg';
+import { ReactComponent as RecordSoilSample } from '../../../assets/images/task/RecordSoilSample.svg';
+import { ReactComponent as Sales } from '../../../assets/images/task/Sales.svg';
+import { ReactComponent as Scout } from '../../../assets/images/task/Scout.svg';
+import { ReactComponent as SocialEvent } from '../../../assets/images/task/SocialEvent.svg';
+import { ReactComponent as SoilAmendment } from '../../../assets/images/task/SoilAmendment.svg';
+import { ReactComponent as Transplant } from '../../../assets/images/task/Transplant.svg';
+import { ReactComponent as WashAndPack } from '../../../assets/images/task/WashAndPack.svg';
+import { ReactComponent as CustomTask } from '../../../assets/images/task/Custom.svg';
+import { useForm } from 'react-hook-form';
+import clsx from 'clsx';
+import Button from '../../Form/Button';
+import { PlantingTaskModal } from '../../Modals/PlantingTaskModal';
+import { isTaskType } from '../../../containers/Task/useIsTaskType';
+import { NoCropManagementPlanModal } from '../../Modals/NoCropManagementPlanModal';
+import { getSupportedTaskTypesSet } from '../getSupportedTaskTypesSet';
+
+const icons = {
+ SOIL_AMENDMENT_TASK: ,
+ FIELD_WORK_TASK: ,
+ HARVEST_TASK: ,
+ IRRIGATION_TASK: ,
+ PEST_CONTROL_TASK: ,
+ PLANT_TASK: ,
+ SOIL_TASK: ,
+ SALE_TASK: ,
+ SCOUTING_TASK: ,
+ SOCIAL_TASK: ,
+ TRANSPORT_TASK: ,
+ WASH_AND_PACK_TASK: ,
+ CLEANING_TASK: ,
+ TRANSPLANT_TASK: ,
+ FERTILIZE_TASK: ,
+ COLLECT_SOIL_SAMPLE_TASK: ,
+ MAINTENANCE_TASK: ,
+};
+
+export const PureTaskTypeSelection = ({
+ onCustomTask,
+ handleGoBack,
+ history,
+
+ persistedFormData,
+ useHookFormPersist,
+ onContinue,
+ onError,
+ taskTypes,
+ customTasks,
+ isAdmin,
+ shouldShowPlantTaskSpotLight,
+ updatePlantTaskSpotlight,
+ hasCurrentManagementPlans,
+}) => {
+ const { t } = useTranslation();
+ const { watch, getValues, register, setValue } = useForm({
+ defaultValues: persistedFormData,
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const TASK_TYPE_ID = 'task_type_id';
+ register(TASK_TYPE_ID);
+ const selected_task_type = watch(TASK_TYPE_ID);
+
+ const onSelectTask = (task_type_id) => {
+ setValue(TASK_TYPE_ID, task_type_id);
+ onContinue();
+ };
+
+ const [showPlantTaskModal, setShowPlantTaskModal] = useState();
+ const goToCatalogue = () => history.push('/crop_catalogue');
+ const onPlantTaskTypeClick = () => {
+ if (shouldShowPlantTaskSpotLight) {
+ setShowPlantTaskModal(true);
+ } else {
+ goToCatalogue();
+ }
+ };
+ const [showNoManagementPlanModal, setShowNoManagementPlanModal] = useState();
+ const onHarvestTransplantTaskClick = (task_type_id) => {
+ hasCurrentManagementPlans ? onSelectTask(task_type_id) : setShowNoManagementPlanModal(true);
+ };
+
+ const onTileClick = (taskType) => {
+ if (isTaskType(taskType, 'PLANT_TASK')) return onPlantTaskTypeClick(taskType.task_type_id);
+ if (isTaskType(taskType, 'TRANSPLANT_TASK') || isTaskType(taskType, 'HARVEST_TASK')) {
+ return onHarvestTransplantTaskClick(taskType.task_type_id);
+ }
+ return onSelectTask(taskType.task_type_id);
+ };
+ return (
+ <>
+
+ {showPlantTaskModal && shouldShowPlantTaskSpotLight && (
+ setShowPlantTaskModal(false)}
+ updatePlantTaskSpotlight={updatePlantTaskSpotlight}
+ />
+ )}
+ {showNoManagementPlanModal && (
+ setShowNoManagementPlanModal(false)}
+ goToCatalogue={goToCatalogue}
+ />
+ )}
+ >
+ );
+};
diff --git a/packages/webapp/src/components/Task/SoilAmendmentTask/index.js b/packages/webapp/src/components/Task/SoilAmendmentTask/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/SoilAmendmentTask/index.js
rename to packages/webapp/src/components/Task/SoilAmendmentTask/index.jsx
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.js b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.js
deleted file mode 100644
index 96fcb68db9..0000000000
--- a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.js
+++ /dev/null
@@ -1,192 +0,0 @@
-import React, { useMemo } from 'react';
-import MultiStepPageTitle from '../../../PageTitle/MultiStepPageTitle';
-import { useTranslation } from 'react-i18next';
-import Form from '../../../Form';
-import { Controller, useFieldArray, useForm } from 'react-hook-form';
-import Button from '../../../Form/Button';
-import { AddLink, Error, Label, Main, SubtractLink } from '../../../Typography';
-import Unit from '../../../Form/Unit';
-import { harvestAmounts, roundToTwoDecimal } from '../../../../util/unit';
-import ReactSelect from '../../../Form/ReactSelect';
-import UnitLabel from './UnitLabel';
-import { cloneObject } from '../../../../util';
-import { colors } from '../../../../assets/theme';
-import PageBreak from '../../../PageBreak';
-
-export default function PureHarvestUses({
- onContinue,
- onGoBack,
- system,
- persistedFormData,
-
-
- useHookFormPersist,
- amount,
- unit,
- harvestUseTypes,
- task,
- onAddHarvestType,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: {
- ...persistedFormData,
- harvest_uses: persistedFormData?.harvest_uses ?? [{}],
- ...cloneObject(task),
- },
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- const progress = 50;
-
- const HARVEST_USE_QUANTITY_UNIT = 'quantity_unit';
- const HARVEST_USE_QUANTITY = 'quantity';
- const HARVEST_USE_TYPE = 'harvest_use_type_id';
-
- const { fields, append, remove, swap } = useFieldArray({
- control,
- name: 'harvest_uses',
- shouldUnregister: false,
- });
-
- const watchFields = watch('harvest_uses');
- const quantities = watchFields.map((field) => field[HARVEST_USE_QUANTITY]);
-
- const { allocated_amount, amount_to_allocate } = useMemo(() => {
- let allocated_amount = 0;
- for (let field of watchFields) {
- const quantity = field[HARVEST_USE_QUANTITY] || 0;
- if (quantity !== undefined) {
- allocated_amount += quantity;
- }
- }
- return { allocated_amount, amount_to_allocate: amount - allocated_amount };
- }, [quantities]);
-
- const harvestUseIds = watchFields.map((field) => field?.[HARVEST_USE_TYPE]?.value);
-
- const harvest_uses_options = useMemo(() => {
- return harvestUseTypes
- .map((harvestUseType) => ({
- value: harvestUseType.harvest_use_type_id,
- label: t(`harvest_uses:${harvestUseType.harvest_use_type_translation_key}`),
- }))
- .filter((harvestUseType) => !harvestUseIds.includes(harvestUseType.value));
- }, [harvestUseIds]);
-
- const disabled = !isValid || roundToTwoDecimal(amount_to_allocate) !== 0;
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.jsx b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.jsx
new file mode 100644
index 0000000000..1b89761c0d
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/HarvestUses.jsx
@@ -0,0 +1,191 @@
+import React, { useMemo } from 'react';
+import MultiStepPageTitle from '../../../PageTitle/MultiStepPageTitle';
+import { useTranslation } from 'react-i18next';
+import Form from '../../../Form';
+import { Controller, useFieldArray, useForm } from 'react-hook-form';
+import Button from '../../../Form/Button';
+import { AddLink, Error, Label, Main, SubtractLink } from '../../../Typography';
+import Unit from '../../../Form/Unit';
+import { harvestAmounts, roundToTwoDecimal } from '../../../../util/convert-units/unit';
+import ReactSelect from '../../../Form/ReactSelect';
+import UnitLabel from './UnitLabel';
+import { cloneObject } from '../../../../util';
+import { colors } from '../../../../assets/theme';
+import PageBreak from '../../../PageBreak';
+
+export default function PureHarvestUses({
+ onContinue,
+ onGoBack,
+ system,
+ persistedFormData,
+ useHookFormPersist,
+ amount,
+ unit,
+ harvestUseTypes,
+ task,
+ onAddHarvestType,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: {
+ ...persistedFormData,
+ harvest_uses: persistedFormData?.harvest_uses ?? [{}],
+ ...cloneObject(task),
+ },
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const progress = 50;
+
+ const HARVEST_USE_QUANTITY_UNIT = 'quantity_unit';
+ const HARVEST_USE_QUANTITY = 'quantity';
+ const HARVEST_USE_TYPE = 'harvest_use_type_id';
+
+ const { fields, append, remove, swap } = useFieldArray({
+ control,
+ name: 'harvest_uses',
+ shouldUnregister: false,
+ });
+
+ const watchFields = watch('harvest_uses');
+ const quantities = watchFields.map((field) => field[HARVEST_USE_QUANTITY]);
+
+ const { allocated_amount, amount_to_allocate } = useMemo(() => {
+ let allocated_amount = 0;
+ for (let field of watchFields) {
+ const quantity = field[HARVEST_USE_QUANTITY] || 0;
+ if (quantity !== undefined) {
+ allocated_amount += quantity;
+ }
+ }
+ return { allocated_amount, amount_to_allocate: amount - allocated_amount };
+ }, [quantities]);
+
+ const harvestUseIds = watchFields.map((field) => field?.[HARVEST_USE_TYPE]?.value);
+
+ const harvest_uses_options = useMemo(() => {
+ return harvestUseTypes
+ .map((harvestUseType) => ({
+ value: harvestUseType.harvest_use_type_id,
+ label: t(`harvest_uses:${harvestUseType.harvest_use_type_translation_key}`),
+ }))
+ .filter((harvestUseType) => !harvestUseIds.includes(harvestUseType.value));
+ }, [harvestUseIds]);
+
+ const disabled = !isValid || roundToTwoDecimal(amount_to_allocate) !== 0;
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.js b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.js
deleted file mode 100644
index e74eba6fca..0000000000
--- a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React from 'react';
-import MultiStepPageTitle from '../../../PageTitle/MultiStepPageTitle';
-import { useTranslation } from 'react-i18next';
-import Form from '../../../Form';
-import { useForm } from 'react-hook-form';
-import Button from '../../../Form/Button';
-import { Main } from '../../../Typography';
-import Unit from '../../../Form/Unit';
-import { harvestAmounts } from '../../../../util/unit';
-
-export default function PureHarvestCompleteQuantity({
- onContinue,
- onGoBack,
- system,
- task,
- persistedFormData,
-
-
- useHookFormPersist,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: {
- ...persistedFormData,
- actual_quantity: persistedFormData.actual_quantity || task.harvest_task.projected_quantity,
- },
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- const progress = 25;
-
- const ACTUAL_HARVEST_QUANTITY = 'actual_quantity';
- const ACTUAL_HARVEST_QUANTITY_UNIT = 'actual_quantity_unit';
-
- const disabled = !isValid;
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.jsx b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.jsx
new file mode 100644
index 0000000000..e2d000662f
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/Quantity.jsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import MultiStepPageTitle from '../../../PageTitle/MultiStepPageTitle';
+import { useTranslation } from 'react-i18next';
+import Form from '../../../Form';
+import { useForm } from 'react-hook-form';
+import Button from '../../../Form/Button';
+import { Main } from '../../../Typography';
+import Unit from '../../../Form/Unit';
+import { harvestAmounts } from '../../../../util/convert-units/unit';
+
+export default function PureHarvestCompleteQuantity({
+ onContinue,
+ onGoBack,
+ system,
+ task,
+ persistedFormData,
+
+ useHookFormPersist,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: {
+ ...persistedFormData,
+ actual_quantity: persistedFormData.actual_quantity || task.harvest_task.projected_quantity,
+ },
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const progress = 25;
+
+ const ACTUAL_HARVEST_QUANTITY = 'actual_quantity';
+ const ACTUAL_HARVEST_QUANTITY_UNIT = 'actual_quantity_unit';
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.js b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.js
deleted file mode 100644
index 0c2926bb08..0000000000
--- a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import { makeStyles } from '@material-ui/core/styles';
-import { colors } from '../../../../assets/theme';
-import clsx from 'clsx';
-import convert from 'convert-units';
-import { roundToTwoDecimal } from '../../../../util/unit';
-
-const useStyles = makeStyles({
- container: {
- display: 'inline-flex',
- justifyContent: 'center',
- alignItems: 'center',
- padding: '4px 8px',
- height: '24px',
- fontFamily: '"Open Sans"," SansSerif", serif',
- color: 'white',
- fontWeight: 700,
- borderRadius: '4px',
- },
- positive: {
- backgroundColor: colors.blue700,
- },
- zero: {
- backgroundColor: colors.brightGreen700,
- },
- negative: {
- backgroundColor: colors.red700,
- },
-});
-
-const UnitLabel = ({ unitLabel = 'kg', amount, style }) => {
- const classes = useStyles();
- const status = Math.abs(amount) < 0.01 ? 'zero' : amount > 0 ? 'positive' : 'negative';
- return (
- {`${roundToTwoDecimal(
- convert(amount).from('kg').to(unitLabel),
- )} ${unitLabel}`}
- );
-};
-
-export default UnitLabel;
diff --git a/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.jsx b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.jsx
new file mode 100644
index 0000000000..a80526aafa
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskComplete/HarvestComplete/UnitLabel.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import { colors } from '../../../../assets/theme';
+import clsx from 'clsx';
+import { convert } from '../../../../util/convert-units/convert';
+import { roundToTwoDecimal } from '../../../../util/convert-units/unit';
+
+const useStyles = makeStyles({
+ container: {
+ display: 'inline-flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ padding: '4px 8px',
+ height: '24px',
+ fontFamily: '"Open Sans"," SansSerif", serif',
+ color: 'white',
+ fontWeight: 700,
+ borderRadius: '4px',
+ },
+ positive: {
+ backgroundColor: colors.blue700,
+ },
+ zero: {
+ backgroundColor: colors.brightGreen700,
+ },
+ negative: {
+ backgroundColor: colors.red700,
+ },
+});
+
+const UnitLabel = ({ unitLabel = 'kg', amount, style }) => {
+ const classes = useStyles();
+ const status = Math.abs(amount) < 0.01 ? 'zero' : amount > 0 ? 'positive' : 'negative';
+ return (
+ {`${roundToTwoDecimal(
+ convert(amount).from('kg').to(unitLabel),
+ )} ${unitLabel}`}
+ );
+};
+
+export default UnitLabel;
diff --git a/packages/webapp/src/components/Task/TaskComplete/StepOne.js b/packages/webapp/src/components/Task/TaskComplete/StepOne.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/TaskComplete/StepOne.js
rename to packages/webapp/src/components/Task/TaskComplete/StepOne.jsx
diff --git a/packages/webapp/src/components/Task/TaskComplete/index.js b/packages/webapp/src/components/Task/TaskComplete/index.js
deleted file mode 100644
index fba27737a3..0000000000
--- a/packages/webapp/src/components/Task/TaskComplete/index.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import React from 'react';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import Button from '../../Form/Button';
-import { Main } from '../../Typography';
-import TimeSlider from '../../Form/Slider/TimeSlider';
-import Checkbox from '../../Form/Checkbox';
-import InputAutoSize from '../../Form/InputAutoSize';
-import Rating from '../../Rating';
-import styles from './styles.module.scss';
-import { getObjectInnerValues } from '../../../util';
-
-export default function PureTaskComplete({
- onSave,
- onGoBack,
- persistedFormData,
-
-
- useHookFormPersist,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: { ...persistedFormData },
- });
-
- const { historyCancel } = useHookFormPersist(getValues);
-
-
- const progress = 66;
-
- const DURATION = 'duration';
- const COMPLETION_NOTES = 'completion_notes';
- const HAPPINESS = 'happiness';
- const PREFER_NOT_TO_SAY = 'prefer_not_to_say';
-
- const duration = watch(DURATION);
- const prefer_not_to_say = watch(PREFER_NOT_TO_SAY);
- const happiness = watch(HAPPINESS);
-
- const notes = watch(COMPLETION_NOTES);
-
- const disabled = !isValid || (!happiness && !prefer_not_to_say);
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/components/Task/TaskComplete/index.jsx b/packages/webapp/src/components/Task/TaskComplete/index.jsx
new file mode 100644
index 0000000000..7f70f0e157
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskComplete/index.jsx
@@ -0,0 +1,151 @@
+import React from 'react';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import Button from '../../Form/Button';
+import { Main } from '../../Typography';
+import TimeSlider from '../../Form/Slider/TimeSlider';
+import Checkbox from '../../Form/Checkbox';
+import InputAutoSize from '../../Form/InputAutoSize';
+import Rating from '../../Rating';
+import styles from './styles.module.scss';
+import { getObjectInnerValues } from '../../../util';
+import Input from '../../Form/Input';
+import { getDateInputFormat } from '../../../util/moment';
+
+export default function PureTaskComplete({
+ onSave,
+ onGoBack,
+ persistedFormData,
+ useHookFormPersist,
+}) {
+ const DURATION = 'duration';
+ const COMPLETION_NOTES = 'completion_notes';
+ const HAPPINESS = 'happiness';
+ const PREFER_NOT_TO_SAY = 'prefer_not_to_say';
+ const COMPLETE_DATE = 'complete_date';
+
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: { [COMPLETE_DATE]: getDateInputFormat(), ...persistedFormData },
+ });
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const progress = 66;
+
+ const duration = watch(DURATION);
+ const prefer_not_to_say = watch(PREFER_NOT_TO_SAY);
+ const happiness = watch(HAPPINESS);
+
+ const notes = watch(COMPLETION_NOTES);
+
+ const disabled = !isValid || (!happiness && !prefer_not_to_say);
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/components/Task/TaskCount/index.jsx b/packages/webapp/src/components/Task/TaskCount/index.jsx
new file mode 100644
index 0000000000..2cab11103d
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskCount/index.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import styles from './styles.module.scss';
+import { AddLink } from '../../Typography';
+import { useTranslation } from 'react-i18next';
+
+export default function TaskCount({ count, handleAddTask }) {
+ const { t } = useTranslation();
+ return (
+
+
{t('TASK.TASKS_COUNT', { count })}
+
{t('TASK.ADD_TASK')}
+
+ );
+}
diff --git a/packages/webapp/src/components/Task/TaskCount/styles.module.scss b/packages/webapp/src/components/Task/TaskCount/styles.module.scss
new file mode 100644
index 0000000000..07428280b5
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskCount/styles.module.scss
@@ -0,0 +1,17 @@
+.taskCountContainer {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ gap: 18px;
+ margin-bottom: 16px;
+}
+
+.taskCount {
+ background: var(--teal700);
+ color: #ffffff;
+ border-radius: 4px;
+ font-weight: bold;
+ font-size: 14px;
+ line-height: 20px;
+ padding: 2px 8px;
+}
diff --git a/packages/webapp/src/components/Task/TaskDate/index.js b/packages/webapp/src/components/Task/TaskDate/index.js
deleted file mode 100644
index 5190af4f3a..0000000000
--- a/packages/webapp/src/components/Task/TaskDate/index.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import Form from '../../Form';
-import { useForm } from 'react-hook-form';
-import Button from '../../Form/Button';
-import Input from '../../Form/Input';
-import { Main } from '../../Typography';
-
-export default function PureTaskDate({
- onContinue,
- onGoBack,
- persistedFormData,
- useHookFormPersist,
-}) {
- const { t } = useTranslation();
-
- const {
- register,
- handleSubmit,
- getValues,
- formState: { isValid, errors },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: { ...persistedFormData },
- });
-
- const progress = 28;
-
- const { historyCancel } = useHookFormPersist(getValues);
-
- const DUE_DATE = 'due_date';
-
- const disabled = !isValid;
-
- return (
-
- );
-}
-
-PureTaskDate.prototype = {
- onContinue: PropTypes.func,
- onGoBack: PropTypes.func,
- onCancel: PropTypes.func,
- useHookFormPersist: PropTypes.func,
- persistedFormData: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Task/TaskDate/index.jsx b/packages/webapp/src/components/Task/TaskDate/index.jsx
new file mode 100644
index 0000000000..76433de996
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskDate/index.jsx
@@ -0,0 +1,79 @@
+import React from 'react';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import Form from '../../Form';
+import { useForm } from 'react-hook-form';
+import Button from '../../Form/Button';
+import Input from '../../Form/Input';
+import { Main } from '../../Typography';
+
+export default function PureTaskDate({
+ onContinue,
+ onGoBack,
+ persistedFormData,
+ useHookFormPersist,
+}) {
+ const { t } = useTranslation();
+
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ watch,
+ formState: { isValid, errors },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: { ...persistedFormData },
+ });
+
+ const progress = 28;
+
+ const { historyCancel } = useHookFormPersist(getValues);
+
+ const DUE_DATE = 'due_date';
+ const date = watch(DUE_DATE);
+
+ const disabled = !isValid;
+
+ return (
+
+ );
+}
+
+PureTaskDate.prototype = {
+ onContinue: PropTypes.func,
+ onGoBack: PropTypes.func,
+ onCancel: PropTypes.func,
+ useHookFormPersist: PropTypes.func,
+ persistedFormData: PropTypes.object,
+};
diff --git a/packages/webapp/src/components/Task/TaskLocations/index.js b/packages/webapp/src/components/Task/TaskLocations/index.js
deleted file mode 100644
index abe2ff9ef3..0000000000
--- a/packages/webapp/src/components/Task/TaskLocations/index.js
+++ /dev/null
@@ -1,137 +0,0 @@
-import React, { useMemo } from 'react';
-import Button from '../../Form/Button';
-import LocationPicker from '../../LocationPicker/SingleLocationPicker';
-import { useTranslation } from 'react-i18next';
-import Layout from '../../Layout';
-import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
-import { Main } from '../../Typography';
-import PropTypes from 'prop-types';
-import { useForm } from 'react-hook-form';
-import { cloneObject } from '../../../util';
-import Checkbox from '../../Form/Checkbox';
-
-export default function PureTaskLocations({
- locations,
- readOnlyPinCoordinates,
- onContinue,
- onGoBack,
- farmCenterCoordinate,
- persistedFormData,
- useHookFormPersist,
- isMulti = true,
- title,
- maxZoomRef,
- getMaxZoom,
-}) {
- const { t } = useTranslation();
- const progress = 43;
- const defaultLocations = useMemo(() => {
- const locationIdsSet = new Set(locations.map(({ location_id }) => location_id));
- if (isMulti) {
- return (
- persistedFormData.locations?.filter(({ location_id }) => locationIdsSet.has(location_id)) ||
- []
- );
- } else {
- const location = persistedFormData.locations?.find(({ location_id }) =>
- locationIdsSet.has(location_id),
- );
- return location ? [location] : [];
- }
- }, []);
- const { getValues, watch, setValue, register } = useForm({
- defaultValues: cloneObject({ ...persistedFormData, locations: defaultLocations }),
- shouldUnregister: false,
- });
- const { historyCancel } = useHookFormPersist(getValues);
- const SHOW_WILD_CROP = 'show_wild_crop';
- const show_wild_crop = watch(SHOW_WILD_CROP);
- const LOCATIONS = 'locations';
- const selectedLocations = watch(LOCATIONS);
- const selectedLocationIds = useMemo(
- () => selectedLocations?.map(({ location_id }) => location_id),
- [selectedLocations],
- );
-
- const onSelectLocation = (location_id) => {
- setValue(
- LOCATIONS,
- isMulti ? getSelectedLocations(location_id, selectedLocations) : [{ location_id }],
- );
- };
-
- const getSelectedLocations = (location_id, selectedLocations) => {
- const isSelected = selectedLocations
- .map((location) => location.location_id)
- .includes(location_id);
- return isSelected
- ? selectedLocations.filter((location) => location.location_id !== location_id)
- : [...selectedLocations, { location_id }];
- };
-
- const clearLocations = () => setValue(LOCATIONS, []);
-
- const showWildCropCheckBox = !!readOnlyPinCoordinates?.length;
-
- return (
- <>
-
-
- {t('common:CONTINUE')}
-
- >
- }
- >
-
-
-
- {title || t('TASK.SELECT_TASK_LOCATIONS')}
-
-
- {showWildCropCheckBox && (
-
- )}
-
- >
- );
-}
-
-PureTaskLocations.prototype = {
- onContinue: PropTypes.func,
- onGoBack: PropTypes.func,
- storedLocations: PropTypes.array,
- locations: PropTypes.arrayOf(PropTypes.object),
- farmCenterCoordinate: PropTypes.object,
- persistedFormData: PropTypes.object,
- useHookFormPersist: PropTypes.func,
- isMulti: PropTypes.bool,
- title: PropTypes.string,
- readOnlyPinCoordinates: PropTypes.array,
- maxZoomRef: PropTypes.object,
- getMaxZoom: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/Task/TaskLocations/index.jsx b/packages/webapp/src/components/Task/TaskLocations/index.jsx
new file mode 100644
index 0000000000..ba20505a53
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskLocations/index.jsx
@@ -0,0 +1,150 @@
+import React, { useEffect, useMemo } from 'react';
+import Button from '../../Form/Button';
+import LocationPicker from '../../LocationPicker/SingleLocationPicker';
+import { useTranslation } from 'react-i18next';
+import Layout from '../../Layout';
+import MultiStepPageTitle from '../../PageTitle/MultiStepPageTitle';
+import { Main } from '../../Typography';
+import PropTypes from 'prop-types';
+import { useForm } from 'react-hook-form';
+import { cloneObject } from '../../../util';
+import Checkbox from '../../Form/Checkbox';
+
+export default function PureTaskLocations({
+ locations,
+ readOnlyPinCoordinates,
+ onContinue,
+ onGoBack,
+ farmCenterCoordinate,
+ persistedFormData,
+ useHookFormPersist,
+ isMulti = true,
+ title,
+ maxZoomRef,
+ getMaxZoom,
+ defaultLocation,
+ targetsWildCrop,
+}) {
+ const { t } = useTranslation();
+ const progress = 43;
+ const defaultLocations = useMemo(() => {
+ const locationIdsSet = new Set(locations.map(({ location_id }) => location_id));
+ if (isMulti) {
+ return (
+ persistedFormData.locations?.filter(({ location_id }) => locationIdsSet.has(location_id)) ||
+ []
+ );
+ } else {
+ const location = persistedFormData.locations?.find(({ location_id }) =>
+ locationIdsSet.has(location_id),
+ );
+ return location ? [location] : [];
+ }
+ }, []);
+ const { getValues, watch, setValue, register } = useForm({
+ defaultValues: cloneObject({ ...persistedFormData, locations: defaultLocations }),
+ shouldUnregister: false,
+ });
+ const { historyCancel } = useHookFormPersist(getValues);
+ const SHOW_WILD_CROP = 'show_wild_crop';
+ const show_wild_crop = watch(SHOW_WILD_CROP);
+ const LOCATIONS = 'locations';
+ const selectedLocations = watch(LOCATIONS);
+ const selectedLocationIds = useMemo(
+ () => selectedLocations?.map(({ location_id }) => location_id),
+ [selectedLocations],
+ );
+
+ const onSelectLocation = (location_id) => {
+ setValue(
+ LOCATIONS,
+ isMulti ? getSelectedLocations(location_id, selectedLocations) : [{ location_id }],
+ );
+ };
+
+ useEffect(() => {
+ defaultLocation &&
+ locations.some((location) => location.location_id === defaultLocation.location_id) &&
+ onSelectLocation(defaultLocation.location_id);
+ }, [defaultLocation]);
+
+ useEffect(() => {
+ setValue(SHOW_WILD_CROP, targetsWildCrop);
+ }, []);
+
+ const getSelectedLocations = (location_id, selectedLocations) => {
+ const isSelected = selectedLocations
+ .map((location) => location.location_id)
+ .includes(location_id);
+ return isSelected
+ ? selectedLocations.filter((location) => location.location_id !== location_id)
+ : [...selectedLocations, { location_id }];
+ };
+
+ const clearLocations = () => setValue(LOCATIONS, []);
+
+ const showWildCropCheckBox = !!readOnlyPinCoordinates?.length;
+
+ return (
+ <>
+
+
+ {t('common:CONTINUE')}
+
+ >
+ }
+ >
+
+
+
+ {title || t('TASK.SELECT_TASK_LOCATIONS')}
+
+
+ {showWildCropCheckBox && (
+
+ )}
+
+ >
+ );
+}
+
+PureTaskLocations.prototype = {
+ onContinue: PropTypes.func,
+ onGoBack: PropTypes.func,
+ storedLocations: PropTypes.array,
+ locations: PropTypes.arrayOf(PropTypes.object),
+ farmCenterCoordinate: PropTypes.object,
+ persistedFormData: PropTypes.object,
+ useHookFormPersist: PropTypes.func,
+ isMulti: PropTypes.bool,
+ title: PropTypes.string,
+ readOnlyPinCoordinates: PropTypes.array,
+ maxZoomRef: PropTypes.object,
+ getMaxZoom: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/Task/TaskReadOnly/TransplantLocationLabel/TransplantLocationLabel.js b/packages/webapp/src/components/Task/TaskReadOnly/TransplantLocationLabel/TransplantLocationLabel.jsx
similarity index 100%
rename from packages/webapp/src/components/Task/TaskReadOnly/TransplantLocationLabel/TransplantLocationLabel.js
rename to packages/webapp/src/components/Task/TaskReadOnly/TransplantLocationLabel/TransplantLocationLabel.jsx
diff --git a/packages/webapp/src/components/Task/TaskReadOnly/index.js b/packages/webapp/src/components/Task/TaskReadOnly/index.js
deleted file mode 100644
index e455fafc00..0000000000
--- a/packages/webapp/src/components/Task/TaskReadOnly/index.js
+++ /dev/null
@@ -1,337 +0,0 @@
-import Layout from '../../Layout';
-import Button from '../../Form/Button';
-import React from 'react';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../../PageTitle/v2';
-import Input from '../../Form/Input';
-import InputAutoSize from '../../Form/InputAutoSize';
-import { Label, Main, Semibold, Underlined } from '../../Typography';
-import styles from './styles.module.scss';
-import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
-import PureCropTileContainer from '../../CropTile/CropTileContainer';
-import PageBreak from '../../PageBreak';
-import { useForm } from 'react-hook-form';
-import TimeSlider from '../../Form/Slider/TimeSlider';
-import Rating from '../../Rating';
-import Checkbox from '../../Form/Checkbox';
-import { cloneObject } from '../../../util';
-import PureCleaningTask from '../CleaningTask';
-import PureFieldWorkTask from '../FieldWorkTask';
-import PureSoilAmendmentTask from '../SoilAmendmentTask';
-import PurePestControlTask from '../PestControlTask';
-import { PureHarvestingTaskReadOnly, PureHavestTaskCompleted } from '../HarvestingTask/ReadOnly';
-import { PurePlantingTask } from '../PlantingTask';
-import LocationPicker from '../../LocationPicker/SingleLocationPicker';
-import { StatusLabel } from '../../CardWithStatus/StatusLabel';
-import { getTaskStatus } from '../../../containers/Task/taskCardContentSelector';
-import { taskStatusTranslateKey } from '../../CardWithStatus/TaskCard/TaskCard';
-import { TransplantLocationLabel } from './TransplantLocationLabel/TransplantLocationLabel';
-import { isTaskType } from '../../../containers/Task/useIsTaskType';
-import ReactSelect from '../../Form/ReactSelect';
-
-export default function PureTaskReadOnly({
- onGoBack,
- onComplete,
- onEdit,
- onAbandon,
- task,
- users,
- user,
- isAdmin,
- system,
- products,
- harvestUseTypes,
- maxZoomRef,
- getMaxZoom,
-}) {
- const { t } = useTranslation();
- const taskType = task.taskType;
- const dueDate = task.due_date.split('T')[0];
- const locationIds = task.locations.map(({ location_id }) => location_id);
- const owner_user_id = task.owner_user_id;
- const {
- register,
- handleSubmit,
- watch,
- getValues,
- control,
- setValue,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onChange',
- shouldUnregister: false,
- defaultValues: cloneObject(task),
- });
-
- const taskAfterCompleteComponents = {
- HARVEST_TASK: (props) => (
-
- ),
- };
-
- const assignee = users.find((user) => user.user_id === task.assignee_user_id);
- const assigneeName = assignee && `${assignee.first_name} ${assignee.last_name}`;
-
- const isCompleted = !!task.completed_time;
- const isAbandoned = !!task.abandoned_time;
- const isCurrent = !isCompleted && !isAbandoned;
- const taskStatus = getTaskStatus(task);
-
- const showTaskNotes =
- !isTaskType(taskType, 'PLANT_TASK') && !isTaskType(taskType, 'TRANSPLANT_TASK');
- return (
-
-
- {t('common:MARK_COMPLETE')}
-
- >
- )
- }
- >
-
- )
- }
- // TODO: Evaluate edit tasks
- // onEdit={(isAdmin || owner_user_id === user.user_id) && isCurrent ? onEdit : false}
- // editLink={t('TASK.EDIT_TASK')}
- />
-
-
-
-
-
- {t('TASK.LOCATIONS')}
- {isTaskType(taskType, 'TRANSPLANT_TASK') && (
-
- )}
- {
- // TODO: fix onSelectLocationRef in LocationPicker
- }}
- readOnlyPinCoordinates={task.pinCoordinates}
- style={{ minHeight: '160px', marginBottom: '40px' }}
- locations={task.locations}
- selectedLocationIds={task.selectedLocationIds || []}
- farmCenterCoordinate={user.grid_points}
- maxZoomRef={maxZoomRef}
- getMaxZoom={getMaxZoom}
- />
-
- {Object.keys(task.managementPlansByLocation).map((location_id) => {
- return (
-
-
-
- {task.managementPlansByLocation[location_id]?.map((managementPlan) => {
- return (
-
- );
- })}
-
-
- );
- })}
-
- {Object.keys(task.managementPlansByPinCoordinate).map((pin_coordinate) => {
- const managementPlan = task.managementPlansByPinCoordinate[pin_coordinate];
- return (
-
- );
- })}
-
- {isCompleted && (
-
-
{t('TASK.COMPLETION_DETAILS')}
-
{}}
- disabled={true}
- />
- {t('TASK.DID_YOU_ENJOY')}
- {task.happiness > 0 && (
-
- {t('TASK.RATE_THIS_TASK')}
-
-
- )}
- {!task.happiness && (
-
- )}
-
- {taskAfterCompleteComponents[taskType.task_translation_key] !== undefined &&
- !taskType.farm_id &&
- taskAfterCompleteComponents[taskType.task_translation_key]({
- setValue,
- getValues,
- watch,
- control,
- register,
- errors,
- disabled: true,
- farm: user,
- system,
- products,
- task,
- isCompleted,
- })}
-
- )}
-
- {isAbandoned && (
-
-
{t('TASK.ABANDONMENT_DETAILS')}
-
-
-
- {task.duration > 0 && (
-
{}}
- disabled={true}
- />
- )}
-
- {t('TASK.DID_YOU_ENJOY')}
- {task.happiness > 0 && (
-
- {t('TASK.RATE_THIS_TASK')}
-
-
- )}
- {!task.happiness && (
-
- )}
-
-
- )}
-
-
- {t(`task:${taskType.task_translation_key}`) + ' ' + t('TASK.DETAILS')}
-
-
- {taskComponents[taskType.task_translation_key] !== undefined &&
- !taskType.farm_id &&
- taskComponents[taskType.task_translation_key]({
- setValue,
- getValues,
- watch,
- control,
- register,
- formState: { errors, isValid },
- errors,
- disabled: true,
- farm: user,
- system,
- products,
- task,
- })}
- {showTaskNotes && (
-
- )}
-
- {(user.user_id === task.assignee_user_id || user.user_id === owner_user_id || isAdmin) &&
- isCurrent && (
-
- {t('TASK.ABANDON_TASK')}
-
- )}
-
- );
-}
-
-const taskComponents = {
- CLEANING_TASK: (props) => ,
- FIELD_WORK_TASK: (props) => ,
- SOIL_AMENDMENT_TASK: (props) => ,
- PEST_CONTROL_TASK: (props) => ,
- PLANT_TASK: (props) => ,
- TRANSPLANT_TASK: (props) => ,
- HARVEST_TASK: (props) => ,
-};
diff --git a/packages/webapp/src/components/Task/TaskReadOnly/index.jsx b/packages/webapp/src/components/Task/TaskReadOnly/index.jsx
new file mode 100644
index 0000000000..c09fd0bac7
--- /dev/null
+++ b/packages/webapp/src/components/Task/TaskReadOnly/index.jsx
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import Layout from '../../Layout';
+import Button from '../../Form/Button';
+import React, { useMemo, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../PageTitle/v2';
+import Input from '../../Form/Input';
+import InputAutoSize from '../../Form/InputAutoSize';
+import { Label, Main, Semibold, Underlined } from '../../Typography';
+import styles from './styles.module.scss';
+import PureManagementPlanTile from '../../CropTile/ManagementPlanTile';
+import PureCropTileContainer from '../../CropTile/CropTileContainer';
+import PageBreak from '../../PageBreak';
+import { useForm } from 'react-hook-form';
+import TimeSlider from '../../Form/Slider/TimeSlider';
+import Rating from '../../Rating';
+import Checkbox from '../../Form/Checkbox';
+import { cloneObject } from '../../../util';
+import PureCleaningTask from '../CleaningTask';
+import PureFieldWorkTask from '../FieldWorkTask';
+import PureSoilAmendmentTask from '../SoilAmendmentTask';
+import PurePestControlTask from '../PestControlTask';
+import { PureHarvestingTaskReadOnly, PureHavestTaskCompleted } from '../HarvestingTask/ReadOnly';
+import { PurePlantingTask } from '../PlantingTask';
+import LocationPicker from '../../LocationPicker/SingleLocationPicker';
+import { StatusLabel } from '../../CardWithStatus/StatusLabel';
+import { getTaskStatus } from '../../../containers/Task/taskCardContentSelector';
+import { taskStatusTranslateKey } from '../../CardWithStatus/TaskCard/TaskCard';
+import { TransplantLocationLabel } from './TransplantLocationLabel/TransplantLocationLabel';
+import { isTaskType } from '../../../containers/Task/useIsTaskType';
+import ReactSelect from '../../Form/ReactSelect';
+import { BiPencil } from 'react-icons/bi';
+import TaskQuickAssignModal from '../../Modals/QuickAssignModal';
+import { getDateInputFormat } from '../../../util/moment';
+import UpdateTaskDateModal from '../../Modals/UpdateTaskDateModal';
+
+export default function PureTaskReadOnly({
+ onGoBack,
+ onComplete,
+ onEdit,
+ onAbandon,
+ task,
+ users,
+ user,
+ isAdmin,
+ system,
+ products,
+ harvestUseTypes,
+ maxZoomRef,
+ getMaxZoom,
+ onAssignTasksOnDate,
+ onAssignTask,
+ onChangeTaskDate,
+}) {
+ const { t } = useTranslation();
+ const taskType = task.taskType;
+ const { date, dateLabel, secondDate, secondDateLabel } = useMemo(() => {
+ if (task.abandon_date) {
+ return {
+ date: getDateInputFormat(task.abandon_date),
+ dateLabel: t('TASK.ABANDON.DATE'),
+ secondDate: getDateInputFormat(task.due_date),
+ secondDateLabel: t('TASK.DUE_DATE'),
+ };
+ } else if (task.complete_date) {
+ return {
+ date: getDateInputFormat(task.complete_date),
+ dateLabel: t('TASK.COMPLETE.DATE'),
+ secondDate: null,
+ secondDateLabel: null,
+ };
+ } else {
+ return {
+ date: getDateInputFormat(task.due_date),
+ dateLabel: t('TASK.DUE_DATE'),
+ secondDate: null,
+ secondDateLabel: null,
+ };
+ }
+ }, [task]);
+ const locationIds = task.locations.map(({ location_id }) => location_id);
+ const owner_user_id = task.owner_user_id;
+ const {
+ register,
+ handleSubmit,
+ watch,
+ getValues,
+ control,
+ setValue,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onChange',
+ shouldUnregister: false,
+ defaultValues: cloneObject(task),
+ });
+
+ const taskAfterCompleteComponents = {
+ HARVEST_TASK: (props) => (
+
+ ),
+ };
+
+ const assignee = users.find((user) => user.user_id === task.assignee_user_id);
+ const assigneeName = assignee && `${assignee.first_name} ${assignee.last_name}`;
+ const assignedToPseudoUser = assignee && assignee.role_id === 4;
+
+ const isCompleted = !!task.complete_date;
+ const isAbandoned = !!task.abandon_date;
+ const isCurrent = !isCompleted && !isAbandoned;
+ const taskStatus = getTaskStatus(task);
+
+ const showTaskNotes =
+ !isTaskType(taskType, 'PLANT_TASK') && !isTaskType(taskType, 'TRANSPLANT_TASK');
+
+ const [showTaskAssignModal, setShowTaskAssignModal] = useState(false);
+ const [showDueDateModal, setShowDueDateModal] = useState(false);
+
+ const canCompleteTask =
+ user.user_id === task.assignee_user_id || (assignedToPseudoUser && user.is_admin);
+
+ return (
+
+
+ {t('common:MARK_COMPLETE')}
+
+ >
+ )
+ }
+ >
+
+ }
+ />
+
+
+ {isCurrent && (
+ setShowTaskAssignModal(true)}
+ />
+ )}
+
+
+
+
+ {isCurrent && isAdmin && (
+ setShowDueDateModal(true)} />
+ )}
+
+
+ {secondDate && (
+
+
+
+ )}
+
+ {t('TASK.LOCATIONS')}
+ {isTaskType(taskType, 'TRANSPLANT_TASK') && (
+
+ )}
+ {
+ // TODO: fix onSelectLocationRef in LocationPicker
+ }}
+ readOnlyPinCoordinates={task.pinCoordinates}
+ style={{ minHeight: '160px', marginBottom: '40px' }}
+ locations={task.locations}
+ selectedLocationIds={task.selectedLocationIds || []}
+ farmCenterCoordinate={user.grid_points}
+ maxZoomRef={maxZoomRef}
+ getMaxZoom={getMaxZoom}
+ />
+
+ {Object.keys(task.managementPlansByLocation).map((location_id) => {
+ return (
+
+
+
+ {task.managementPlansByLocation[location_id]?.map((managementPlan) => {
+ return (
+
+ );
+ })}
+
+
+ );
+ })}
+
+ {Object.keys(task.managementPlansByPinCoordinate).map((pin_coordinate) => {
+ const managementPlan = task.managementPlansByPinCoordinate[pin_coordinate];
+ return (
+
+ );
+ })}
+
+ {isCompleted && (
+
+
{t('TASK.COMPLETION_DETAILS')}
+
{}}
+ disabled={true}
+ />
+ {t('TASK.DID_YOU_ENJOY')}
+ {task.happiness > 0 && (
+
+ {t('TASK.RATE_THIS_TASK')}
+
+
+ )}
+ {!task.happiness && (
+
+ )}
+
+ {taskAfterCompleteComponents[taskType.task_translation_key] !== undefined &&
+ !taskType.farm_id &&
+ taskAfterCompleteComponents[taskType.task_translation_key]({
+ setValue,
+ getValues,
+ watch,
+ control,
+ register,
+ errors,
+ disabled: true,
+ farm: user,
+ system,
+ products,
+ task,
+ isCompleted,
+ })}
+
+ )}
+
+ {isAbandoned && (
+
+
{t('TASK.ABANDONMENT_DETAILS')}
+
+
+
+ {task.duration > 0 && (
+
{}}
+ disabled={true}
+ />
+ )}
+
+ {t('TASK.DID_YOU_ENJOY')}
+ {task.happiness > 0 && (
+
+ {t('TASK.RATE_THIS_TASK')}
+
+
+ )}
+ {!task.happiness && (
+
+ )}
+
+
+ )}
+
+
+ {t(`task:${taskType.task_translation_key}`) + ' ' + t('TASK.DETAILS')}
+
+
+ {taskComponents[taskType.task_translation_key] !== undefined &&
+ !taskType.farm_id &&
+ taskComponents[taskType.task_translation_key]({
+ setValue,
+ getValues,
+ watch,
+ control,
+ register,
+ formState: { errors, isValid },
+ errors,
+ disabled: true,
+ farm: user,
+ system,
+ products,
+ task,
+ })}
+ {showTaskNotes && (
+
+ )}
+
+ {(user.user_id === task.assignee_user_id || user.user_id === owner_user_id || isAdmin) &&
+ isCurrent && (
+
+ {t('TASK.ABANDON_TASK')}
+
+ )}
+ {showTaskAssignModal && (
+ setShowTaskAssignModal(false)}
+ />
+ )}
+ {showDueDateModal && (
+ setShowDueDateModal(false)}
+ />
+ )}
+
+ );
+}
+
+const taskComponents = {
+ CLEANING_TASK: (props) => ,
+ FIELD_WORK_TASK: (props) => ,
+ SOIL_AMENDMENT_TASK: (props) => ,
+ PEST_CONTROL_TASK: (props) => ,
+ PLANT_TASK: (props) => ,
+ TRANSPLANT_TASK: (props) => ,
+ HARVEST_TASK: (props) => ,
+};
diff --git a/packages/webapp/src/components/Task/TaskReadOnly/styles.module.scss b/packages/webapp/src/components/Task/TaskReadOnly/styles.module.scss
index a45c5ecdcc..dbc47f3d29 100644
--- a/packages/webapp/src/components/Task/TaskReadOnly/styles.module.scss
+++ b/packages/webapp/src/components/Task/TaskReadOnly/styles.module.scss
@@ -13,10 +13,22 @@
}
.pencil {
- width: 15.06px;
- height: 15.02px;
+ font-size: 24px;
+ transform: translateY(30px);
+ margin-left: 20px;
+ color: var(--grey600);
+ cursor: pointer;
+}
+
+.editableContainer {
+ display: flex;
+ flex-direction: row;
+ margin-bottom: 40px;
+ div {
+ flex-grow: 1;
+ }
}
.rating {
display: table-row;
-}
\ No newline at end of file
+}
diff --git a/packages/webapp/src/components/Task/getSupportedTaskTypesSet.js b/packages/webapp/src/components/Task/getSupportedTaskTypesSet.js
new file mode 100644
index 0000000000..0d6135c5d6
--- /dev/null
+++ b/packages/webapp/src/components/Task/getSupportedTaskTypesSet.js
@@ -0,0 +1,20 @@
+/**
+ *
+ * @param isAdmin {boolean}
+ * @return {Set}
+ */
+export const getSupportedTaskTypesSet = (isAdmin) => {
+ const supportedTaskTypes = new Set([
+ 'SOIL_AMENDMENT_TASK',
+ 'FIELD_WORK_TASK',
+ 'PEST_CONTROL_TASK',
+ 'CLEANING_TASK',
+ 'HARVEST_TASK',
+ ]);
+
+ if (isAdmin) {
+ supportedTaskTypes.add('PLANT_TASK');
+ supportedTaskTypes.add('TRANSPLANT_TASK');
+ }
+ return supportedTaskTypes;
+};
diff --git a/packages/webapp/src/components/Tooltip/Infoi/index.js b/packages/webapp/src/components/Tooltip/Infoi/index.js
deleted file mode 100644
index bbf8f3f715..0000000000
--- a/packages/webapp/src/components/Tooltip/Infoi/index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { AiOutlineInfoCircle } from 'react-icons/ai';
-import OverlayTooltip from '../index';
-import React from 'react';
-import PropTypes from 'prop-types';
-
-export default function Infoi({ content, placement = 'bottom', style, ...props }) {
- return (
- }
- {...props}
- >
- );
-}
-
-Infoi.propTypes = {
- style: PropTypes.object,
- content: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- placement: PropTypes.string,
-};
diff --git a/packages/webapp/src/components/Tooltip/Infoi/index.tsx b/packages/webapp/src/components/Tooltip/Infoi/index.tsx
new file mode 100644
index 0000000000..263446968d
--- /dev/null
+++ b/packages/webapp/src/components/Tooltip/Infoi/index.tsx
@@ -0,0 +1,14 @@
+import { AiOutlineInfoCircle } from 'react-icons/ai';
+import OverlayTooltip, { OverlayTooltipProps } from '../';
+import React from 'react';
+
+export default function Infoi({ content, placement = 'bottom', style, ...props }: OverlayTooltipProps) {
+ return (
+ }
+ {...props}
+ />
+ );
+}
diff --git a/packages/webapp/src/components/Tooltip/MoreInfo/index.js b/packages/webapp/src/components/Tooltip/MoreInfo/index.jsx
similarity index 100%
rename from packages/webapp/src/components/Tooltip/MoreInfo/index.js
rename to packages/webapp/src/components/Tooltip/MoreInfo/index.jsx
diff --git a/packages/webapp/src/components/Tooltip/index.js b/packages/webapp/src/components/Tooltip/index.js
deleted file mode 100644
index 056ff24ea4..0000000000
--- a/packages/webapp/src/components/Tooltip/index.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { makeStyles, Tooltip } from '@material-ui/core';
-import { colors } from '../../assets/theme';
-
-const useStyles = ({ arrowOffset = 0, isChildrenIcon } = {}) =>
- makeStyles((theme) => ({
- arrow: {
- zIndex: -1,
- color: 'var(--grey400)',
- // width: '15px',
- overflow: 'initial',
- '&::before': {
- // width: '15px',
- // height: '15px',
- transform: `translate(${arrowOffset}px, 0px) rotate(45deg)`,
- },
- },
- tooltip: {
- zIndex: 1000,
- backgroundColor: 'var(--grey400)',
- padding: '12px 16px',
- boxShadow: '2px 6px 12px rgba(102, 115, 138, 0.2)',
- borderRadius: '4px',
- textAlign: 'left',
- maxWidth: '264px',
- userSelect: 'none',
- margin: isChildrenIcon ? '8px 0' : '16px 0',
- fontSize: '14px',
- lineHeight: '24px',
- color: colors.grey900,
- fontStyle: 'normal',
- fontWeight: 'normal',
- fontFamily: 'Open Sans, SansSerif, serif',
- },
- childrenContainer: {
- userSelect: 'none',
- '& svg': {
- color: colors.teal700,
- fontSize: '16px',
- },
- },
- }));
-export default function OverlayTooltip({
- children = 'LiteFarm',
- content = 'LiteFarm',
- placement,
- arrowOffset,
- autoOpen,
- isChildrenIcon,
- icon,
- ...props
-}) {
- const classes = useStyles({ arrowOffset, isChildrenIcon: !!icon || isChildrenIcon })();
- return (
-
- {icon || children}
-
- );
-}
-
-OverlayTooltip.propTypes = {
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- content: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
- placement: PropTypes.string,
- arrowOffset: PropTypes.number,
- style: PropTypes.objectOf(PropTypes.string),
- autoOpen: PropTypes.bool,
-};
diff --git a/packages/webapp/src/components/Tooltip/index.tsx b/packages/webapp/src/components/Tooltip/index.tsx
new file mode 100644
index 0000000000..66249a206b
--- /dev/null
+++ b/packages/webapp/src/components/Tooltip/index.tsx
@@ -0,0 +1,78 @@
+import React, { ReactNode } from 'react';
+import { makeStyles, Tooltip, TooltipProps } from '@material-ui/core';
+import { colors } from '../../assets/theme';
+
+const useStyles = ({ arrowOffset = 0, isChildrenIcon = false }) =>
+ makeStyles((theme) => ({
+ arrow: {
+ zIndex: -1,
+ color: 'var(--grey400)',
+ // width: '15px',
+ overflow: 'initial',
+ '&::before': {
+ // width: '15px',
+ // height: '15px',
+ transform: `translate(${arrowOffset}px, 0px) rotate(45deg)`,
+ },
+ },
+ tooltip: {
+ zIndex: 1000,
+ backgroundColor: 'var(--grey400)',
+ padding: '12px 16px',
+ boxShadow: '2px 6px 12px rgba(102, 115, 138, 0.2)',
+ borderRadius: '4px',
+ textAlign: 'left',
+ maxWidth: '264px',
+ userSelect: 'none',
+ margin: isChildrenIcon ? '8px 0' : '16px 0',
+ fontSize: '14px',
+ lineHeight: '24px',
+ color: colors.grey900,
+ fontStyle: 'normal',
+ fontWeight: 'normal',
+ fontFamily: 'Open Sans, SansSerif, serif',
+ },
+ childrenContainer: {
+ userSelect: 'none',
+ '& svg': {
+ color: colors.teal700,
+ fontSize: '16px',
+ },
+ },
+ }));
+
+export type OverlayTooltipProps = Omit & {
+ content: TooltipProps['title'],
+ children?: ReactNode,
+ arrowOffset?: number,
+ autoOpen?: boolean,
+ isChildrenIcon?: boolean,
+ icon?: ReactNode,
+}
+
+export default function OverlayTooltip({
+ children,
+ content,
+ placement,
+ arrowOffset,
+ autoOpen,
+ isChildrenIcon,
+ icon,
+ ...props
+ }: OverlayTooltipProps) {
+ const classes = useStyles({ arrowOffset, isChildrenIcon: !!icon || isChildrenIcon })();
+ return (
+
+ {icon || children}
+
+ );
+}
+
diff --git a/packages/webapp/src/components/TourProviderWrapper/TourProviderWrapper.tsx b/packages/webapp/src/components/TourProviderWrapper/TourProviderWrapper.tsx
new file mode 100644
index 0000000000..8c0811e3ea
--- /dev/null
+++ b/packages/webapp/src/components/TourProviderWrapper/TourProviderWrapper.tsx
@@ -0,0 +1,298 @@
+import { StepType, TourProvider } from '@reactour/tour';
+import React, { ReactNode, useMemo } from 'react';
+import { makeStyles } from '@material-ui/core/styles';
+import { useTranslation } from 'react-i18next';
+import { Label, Semibold } from '../Typography';
+import { colors } from '../../assets/theme';
+import Button from '../Form/Button';
+import { ProviderProps, TourProps } from '@reactour/tour/dist/types';
+import { ContentProps } from '@reactour/tour/src/types';
+import { keyframes } from '@emotion/react';
+
+const opositeSide = {
+ top: 'bottom',
+ bottom: 'top',
+ right: 'left',
+ left: 'right',
+};
+type VerticalAlign = 'top' | 'bottom';
+type HorizontalAlign = 'left' | 'right';
+type Position = VerticalAlign | HorizontalAlign | 'custom' | 'center';
+
+type Style = { [prop: string]: string };
+
+type getStylesProps = {
+ arrowOffset: number;
+ popoverStyles: Style;
+ maskStyles: Style;
+ showMaskArea?: boolean;
+};
+
+const getStyles = ({
+ showMaskArea,
+ arrowOffset = 0,
+ popoverStyles,
+ maskStyles,
+}: getStylesProps): TourProps['styles'] => ({
+ maskArea: (base, state) => ({ ...base, rx: 8, display: showMaskArea ? undefined : 'none' }),
+ popover: (base, state) => {
+ const fadein = keyframes`
+ 0%, 50% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 100%;
+ }`;
+ const baseStyles = {
+ borderRadius: 8,
+ display: 'flex',
+ maxWidth: '500px',
+ background: colors.grey100,
+ padding: '16px',
+ animation: `${fadein} 0.5s ease`,
+ ...popoverStyles,
+ };
+ const position: Position = state?.position;
+ if (!position || position === 'custom' || position === 'center') {
+ return {
+ ...base,
+ flexDirection: 'column',
+ ...baseStyles,
+ width: 'min(500px, calc(100vw - 48px))',
+ };
+ }
+
+ const width = 32;
+ const height = 16;
+ const isVertical = position === 'top' || position === 'bottom';
+ const verticalAlign: VerticalAlign = state?.verticalAlign;
+ const horizontalAlign: HorizontalAlign = state?.horizontalAlign;
+ const getPopoverOffset = () => {
+ switch (position) {
+ case 'top':
+ return { top: '-24px' };
+ case 'bottom':
+ return { top: '12px' };
+ default:
+ return {};
+ }
+ };
+ return {
+ ...base,
+ flexDirection: 'column',
+ ...baseStyles,
+ ...getPopoverOffset(),
+ '&::after': {
+ content: "''",
+ width: 0,
+ height: 0,
+ position: 'absolute',
+ [isVertical ? 'borderLeft' : 'borderTop']: `${width / 2}px solid transparent`,
+ [isVertical ? 'borderRight' : 'borderBottom']: `${width / 2}px solid transparent`,
+ [`border${position[0].toUpperCase()}${position.substring(
+ 1,
+ )}`]: `${height}px solid ${colors.grey100}`,
+ [isVertical ? opositeSide[horizontalAlign] : verticalAlign]: height - 10 + arrowOffset,
+ [opositeSide[position]]: -height,
+ },
+ };
+ },
+});
+
+type TourContentBodyStep = {
+ title?: ReactNode;
+ children?: ReactNode;
+ contents?: ReactNode[];
+ isOrdered?: boolean;
+ list?: ReactNode[];
+ buttonText?: ReactNode;
+ icon?: ReactNode;
+ onNext?(): void;
+};
+
+type Step = Omit & TourContentBodyStep & getStylesProps;
+
+type TourProviderWrapperProps = ReactourChildrenWrapperProps &
+ Omit & {
+ steps: Step[];
+ onFinish?(): void;
+ };
+
+export function TourProviderWrapper({
+ steps,
+ children =
,
+ open,
+ onFinish,
+ ...props
+}: TourProviderWrapperProps) {
+ if (!open) return children;
+ const processedSteps = useMemo(() => {
+ return steps.map(({ arrowOffset, popoverStyles, maskStyles, ...step }) => {
+ return {
+ ...step,
+ styles: getStyles({
+ showMaskArea: !!step.selector,
+ arrowOffset,
+ popoverStyles,
+ maskStyles,
+ }),
+ content: (props: ContentProps) => (
+
+ ),
+ };
+ });
+ }, []);
+ return (
+ {
+ if (currentStep === steps.length - 1) {
+ setIsOpen(false);
+ onFinish?.();
+ } else {
+ setCurrentStep((s) => (s === steps.length - 1 ? 0 : s + 1));
+ }
+ }}
+ showBadge={false}
+ showNavigation={false}
+ showCloseButton={false}
+ defaultOpen={open}
+ steps={processedSteps}
+ {...props}
+ >
+ {children}
+
+ );
+}
+
+type ReactourChildrenWrapperProps = {
+ open: boolean;
+ children?: ReactNode;
+};
+
+function ReactourChildrenWrapper({ open, children }: ReactourChildrenWrapperProps) {
+ return <>{children}>;
+}
+
+const useStyles = makeStyles((theme) => ({
+ container: {
+ display: 'flex',
+ flexDirection: 'column',
+ maxWidth: '500px',
+ width: 'calc(100vw - 48px)',
+ background: '#fafafd',
+ borderRadius: '7.05466px',
+ position: 'relative',
+ padding: '16px',
+ },
+ contentsContainer: {
+ display: 'grid',
+ gap: '8px',
+ },
+ buttonGroup: {
+ marginTop: '16px',
+ display: 'flex',
+ },
+}));
+
+type TourContentBodyProps = ContentProps & {
+ step: TourContentBodyStep;
+ continuous?: boolean;
+ primaryProps?: object;
+ isLastStep?: boolean;
+ onFinish?(): void;
+};
+
+export function TourContentBody({
+ step: { title, children, contents, isOrdered, list, buttonText, icon, onNext },
+ continuous,
+ primaryProps,
+ isLastStep,
+ setCurrentStep,
+ currentStep,
+ setIsOpen,
+ onFinish,
+}: TourContentBodyProps) {
+ const { t } = useTranslation();
+ const classes = useStyles();
+ const onClick = () => {
+ if (isLastStep) {
+ setIsOpen(false);
+ onFinish?.();
+ } else {
+ setCurrentStep(currentStep + 1);
+ }
+ onNext?.();
+ };
+ return (
+ <>
+ {!!title && (
+
+ {icon && icon}
+ {title}
+
+ )}
+
+ {contents && !!contents.length && (
+
+ {contents?.map((line, index) => (
+
+ {line}
+
+ ))}
+
+ )}
+ {list && !!list.length && (
+
+ {list?.map((line, index) => (
+
+ {line}
+
+ ))}
+
+ )}
+
+
+ {children}
+ {
+
+
+ {buttonText || (isLastStep ? t('common:GOT_IT') : t('common:NEXT'))}
+
+
+ }
+ >
+ );
+}
+
+type ListProps = {
+ children?: ReactNode;
+ isOrdered?: boolean;
+ classes: {
+ contentsContainer?: string;
+ };
+};
+
+function List({ children, isOrdered, classes }: ListProps) {
+ const style = { marginLeft: '20px' };
+ return isOrdered ? (
+
+ {children}
+
+ ) : (
+
+ );
+}
diff --git a/packages/webapp/src/components/Typography/index.js b/packages/webapp/src/components/Typography/index.js
deleted file mode 100644
index 7325a7da5b..0000000000
--- a/packages/webapp/src/components/Typography/index.js
+++ /dev/null
@@ -1,221 +0,0 @@
-import React from 'react';
-import styles from './typography.module.scss';
-import clsx from 'clsx';
-import PropTypes from 'prop-types';
-import Infoi from '../Tooltip/Infoi';
-import { ReactComponent as Leaf } from '../../assets/images/farmMapFilter/Leaf.svg';
-import { ReactComponent as Pencil } from '../../assets/images/managementPlans/pencil.svg';
-
-export const Underlined = ({ children = 'Link', className = '', style, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Underlined.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const IconLink = ({
- children = 'IconLink',
- className = '',
- style,
- onClick,
- icon,
- ...props
-}) => {
- return (
-
- {icon}{' '}
-
- {children}
-
-
- );
-};
-
-IconLink.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
- icon: PropTypes.node,
-};
-
-export const AddLink = ({ children = 'AddLink', className = '', style, onClick, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-AddLink.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const SubtractLink = ({
- children = 'SubtractLink',
- className = '',
- style,
- onClick,
- color,
- ...props
-}) => {
- return (
-
- {children}
-
- );
-};
-
-SubtractLink.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const EditLink = ({ children = 'Link', className = '', style, onClick, ...props }) => {
- return (
-
-
-
- {children}
-
-
- );
-};
-
-EditLink.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const Title = ({ children = 'Title', className = '', style, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Title.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const Semibold = ({ children = 'Semibold', className = '', style, sm, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Semibold.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
- sm: PropTypes.bool,
-};
-
-export const Label = ({ children = 'Label', className = '', sm = false, style, ...props }) => {
- return sm ? (
-
- {children}
-
- ) : (
-
- {children}
-
- );
-};
-
-Label.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
- sm: PropTypes.bool,
-};
-
-export const Error = ({ children = 'Error', className = '', style, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Error.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const Info = ({ children = 'Info', className = '', style, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Info.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
-
-export const Main = ({
- children = 'Main',
- tooltipContent,
- hasLeaf,
- className = '',
- style,
- ...props
-}) => {
- return (
-
- {children}
- {hasLeaf && }
- {tooltipContent && (
- <>
-
-
- >
- )}
-
- );
-};
-
-Main.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
- tooltipContent: PropTypes.string,
- hasLeaf: PropTypes.bool,
-};
-
-export const Text = ({ children = 'Text', className = '', style, ...props }) => {
- return (
-
- {children}
-
- );
-};
-
-Text.propTypes = {
- children: PropTypes.node,
- className: PropTypes.string,
- style: PropTypes.object,
-};
diff --git a/packages/webapp/src/components/Typography/index.tsx b/packages/webapp/src/components/Typography/index.tsx
new file mode 100644
index 0000000000..4521625670
--- /dev/null
+++ b/packages/webapp/src/components/Typography/index.tsx
@@ -0,0 +1,207 @@
+import React, { ReactNode } from 'react';
+import styles from './typography.module.scss';
+import clsx from 'clsx';
+import PropTypes from 'prop-types';
+import Infoi from '../Tooltip/Infoi';
+import { ReactComponent as Leaf } from '../../assets/images/farmMapFilter/Leaf.svg';
+import { ReactComponent as Pencil } from '../../assets/images/managementPlans/pencil.svg';
+
+type TypographyProps = {
+ style?: object;
+ onClick?: () => void;
+ children?: ReactNode;
+ className?: string;
+};
+
+export const Underlined = ({
+ children = 'Link',
+ className = '',
+ style = {},
+ ...props
+}: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+type IconLinkProps = TypographyProps & {
+ icon?: ReactNode;
+};
+export const IconLink = ({
+ children = 'IconLink',
+ className = '',
+ style,
+ onClick,
+ icon,
+ ...props
+}: IconLinkProps) => {
+ return (
+
+ {icon}{' '}
+
+ {children}
+
+
+ );
+};
+
+export const AddLink = ({
+ children = 'AddLink',
+ className = '',
+ style,
+ onClick,
+ ...props
+}: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+type SubtractLinkProps = TypographyProps & {
+ color?: string;
+};
+export const SubtractLink = ({
+ children = 'SubtractLink',
+ className = '',
+ style,
+ onClick,
+ color,
+ ...props
+}: SubtractLinkProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export const EditLink = ({
+ children = 'Link',
+ className = '',
+ style,
+ onClick,
+ ...props
+}: TypographyProps) => {
+ return (
+
+
+
+ {children}
+
+
+ );
+};
+
+export const Title = ({ children = 'Title', className = '', style, ...props }: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+type TypographySmProps = TypographyProps & { sm?: boolean };
+
+export const Semibold = ({
+ children = 'Semibold',
+ className = '',
+ style,
+ sm,
+ ...props
+}: TypographySmProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+export const Label = ({
+ children = 'Label',
+ className = '',
+ sm = false,
+ style,
+ ...props
+}: TypographySmProps) => {
+ return sm ? (
+
+ {children}
+
+ ) : (
+
+ {children}
+
+ );
+};
+
+export const Error = ({ children = 'Error', className = '', style, ...props }: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+Error.propTypes = {
+ children: PropTypes.node,
+ className: PropTypes.string,
+ style: PropTypes.object,
+};
+
+export const Info = ({ children = 'Info', className = '', style, ...props }: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
+
+type MainProps = TypographyProps & {
+ hasLeaf?: boolean;
+ tooltipContent?: boolean | React.ReactChild | React.ReactFragment | React.ReactPortal;
+};
+
+export const Main = ({
+ children = 'Main',
+ tooltipContent,
+ hasLeaf,
+ className = '',
+ style,
+ ...props
+}: MainProps) => {
+ return (
+
+ {children}
+ {hasLeaf && }
+ {tooltipContent && (
+ <>
+
+
+ >
+ )}
+
+ );
+};
+
+Main.propTypes = {
+ children: PropTypes.node,
+ className: PropTypes.string,
+ style: PropTypes.object,
+ tooltipContent: PropTypes.string,
+ hasLeaf: PropTypes.bool,
+};
+
+export const Text = ({ children = 'Text', className = '', style, ...props }: TypographyProps) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/webapp/src/components/WarningBox/index.js b/packages/webapp/src/components/WarningBox/index.jsx
similarity index 100%
rename from packages/webapp/src/components/WarningBox/index.js
rename to packages/webapp/src/components/WarningBox/index.jsx
diff --git a/packages/webapp/src/components/WeatherBoard/WeatherIcon.js b/packages/webapp/src/components/WeatherBoard/WeatherIcon.jsx
similarity index 100%
rename from packages/webapp/src/components/WeatherBoard/WeatherIcon.js
rename to packages/webapp/src/components/WeatherBoard/WeatherIcon.jsx
diff --git a/packages/webapp/src/components/WeatherBoard/assets/weatherBoard.module.scss b/packages/webapp/src/components/WeatherBoard/assets/weatherBoard.module.scss
index a83c8d119c..6032c7a91e 100644
--- a/packages/webapp/src/components/WeatherBoard/assets/weatherBoard.module.scss
+++ b/packages/webapp/src/components/WeatherBoard/assets/weatherBoard.module.scss
@@ -7,14 +7,12 @@
padding: 4.44% 9.44%;
width: 84%;
display: grid;
- grid-template-columns: 78fr 25fr 11fr 11fr 25fr 78fr;
- grid-template-rows: 24fr 24fr 80fr 24fr;
- gap: 0px 0px;
grid-template-areas:
- 'city city city city city city'
- 'date date date date date date'
- 'temperature temperature temperature temperature . icon'
- 'wind wind wind humidity humidity humidity';
+ 'city city'
+ 'date date'
+ 'temperature icon'
+ 'wind humidity';
+ word-break: break-word;
background-color: var(--overlay);
font-size: 3.88vw;
line-height: 6.66vw;
@@ -39,6 +37,10 @@
display: flex;
align-items: center;
justify-content: center;
+ padding-top: 16px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.icon {
@@ -46,14 +48,18 @@
display: flex;
align-items: center;
font-size: 15.55vw;
+ justify-content: center;
+ padding-top: 16px;
}
.wind {
grid-area: wind;
+ padding-top: 16px;
}
.humidity {
grid-area: humidity;
+ padding-top: 16px;
}
@media only screen and (min-width: 960px) {
@@ -73,9 +79,19 @@
.temperature {
font-size: 136.5px;
line-height: 126px;
+ padding-top: 20px;
}
.icon {
font-size: 144.375px;
+ padding-top: 20px;
+ }
+
+ .wind {
+ padding-top: 20px;
+ }
+
+ .humidity {
+ padding-top: 20px;
}
}
diff --git a/packages/webapp/src/components/WeatherBoard/index.js b/packages/webapp/src/components/WeatherBoard/index.jsx
similarity index 100%
rename from packages/webapp/src/components/WeatherBoard/index.js
rename to packages/webapp/src/components/WeatherBoard/index.jsx
diff --git a/packages/webapp/src/components/WelcomeScreen/index.js b/packages/webapp/src/components/WelcomeScreen/index.js
deleted file mode 100644
index efa3b0f807..0000000000
--- a/packages/webapp/src/components/WelcomeScreen/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import Layout from '../Layout';
-import Button from '../Form/Button';
-import { ReactComponent as SignupEnglish } from '../../assets/images/signUp/signup_english.svg';
-import { ReactComponent as SignupSpanish } from '../../assets/images/signUp/signup_spanish.svg';
-import { ReactComponent as SignupPortuguese } from '../../assets/images/signUp/signup_portuguese.svg';
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
-
-export default function PureWelcomeScreen({ onClick }) {
- const { t } = useTranslation();
- const languageToSvg = {
- en: ,
- es: ,
- pt: ,
- };
- const language = getLanguageFromLocalStorage();
- return (
-
- {t('WELCOME_SCREEN.BUTTON')}
-
- }
- >
- {languageToSvg[language] ?? }
-
- );
-}
-
-PureWelcomeScreen.prototype = {
- onClick: PropTypes.func,
-};
diff --git a/packages/webapp/src/components/WelcomeScreen/index.jsx b/packages/webapp/src/components/WelcomeScreen/index.jsx
new file mode 100644
index 0000000000..84f4d7819d
--- /dev/null
+++ b/packages/webapp/src/components/WelcomeScreen/index.jsx
@@ -0,0 +1,37 @@
+import Layout from '../Layout';
+import Button from '../Form/Button';
+import { ReactComponent as SignupEnglish } from '../../assets/images/signUp/signup_english.svg';
+import { ReactComponent as SignupSpanish } from '../../assets/images/signUp/signup_spanish.svg';
+import { ReactComponent as SignupPortuguese } from '../../assets/images/signUp/signup_portuguese.svg';
+import { ReactComponent as SignupFrench } from '../../assets/images/signUp/signup_french.svg';
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+
+export default function PureWelcomeScreen({ onClick }) {
+ const { t } = useTranslation();
+ const languageToSvg = {
+ en: ,
+ es: ,
+ pt: ,
+ fr: ,
+ };
+ const language = getLanguageFromLocalStorage();
+ return (
+
+ {t('WELCOME_SCREEN.BUTTON')}
+
+ }
+ >
+ {languageToSvg[language] ?? }
+
+ );
+}
+
+PureWelcomeScreen.prototype = {
+ onClick: PropTypes.func,
+};
diff --git a/packages/webapp/src/components/proceedCancelFooter/index.js b/packages/webapp/src/components/proceedCancelFooter/index.jsx
similarity index 100%
rename from packages/webapp/src/components/proceedCancelFooter/index.js
rename to packages/webapp/src/components/proceedCancelFooter/index.jsx
diff --git a/packages/webapp/src/components/util/getTaskTypeIcon.js b/packages/webapp/src/components/util/getTaskTypeIcon.js
new file mode 100644
index 0000000000..f52ca522a9
--- /dev/null
+++ b/packages/webapp/src/components/util/getTaskTypeIcon.js
@@ -0,0 +1,46 @@
+import { ReactComponent as CustomIcon } from '../../assets/images/task/Custom.svg';
+import { ReactComponent as RecordSoilSample } from '../../assets/images/task/RecordSoilSample.svg';
+import { ReactComponent as Sales } from '../../assets/images/task/Sales.svg';
+import { ReactComponent as Scout } from '../../assets/images/task/Scout.svg';
+import { ReactComponent as WashAndPack } from '../../assets/images/task/WashAndPack.svg';
+import { ReactComponent as Transplant } from '../../assets/images/task/Transplant.svg';
+import { ReactComponent as Harvest } from '../../assets/images/task/Harvest.svg';
+import { ReactComponent as PestControl } from '../../assets/images/task/PestControl.svg';
+import { ReactComponent as Irrigate } from '../../assets/images/task/Irrigate.svg';
+import { ReactComponent as Transport } from '../../assets/images/task/Transport.svg';
+import { ReactComponent as FieldWork } from '../../assets/images/task/FieldWork.svg';
+import { ReactComponent as Plant } from '../../assets/images/task/Plant.svg';
+import { ReactComponent as SocialEvent } from '../../assets/images/task/SocialEvent.svg';
+import { ReactComponent as Clean } from '../../assets/images/task/Clean.svg';
+import { ReactComponent as SoilAmendment } from '../../assets/images/task/SoilAmendment.svg';
+
+/**
+ * Provides the appropriate icon for a specified task type.
+ * @param {string} key - A translation key that specifies a task type.
+ * @returns {ReactComponent | undefined} The icon for the specified task type.
+ */
+export default function getTaskTypeIcon(key) {
+ const iconDict = {
+ CLEANING_TASK: Clean, // for release
+ HARVEST_TASK: Harvest, // for release
+ PEST_CONTROL_TASK: PestControl, // for release
+ PLANT_TASK: Plant, // for release
+ FIELD_WORK_TASK: FieldWork, // for release
+ TRANSPLANT_TASK: Transplant, // for release
+ SOIL_AMENDMENT_TASK: SoilAmendment, // for release
+ BED_PREPARATION_TASK: CustomIcon,
+ SALE_TASK: Sales,
+ FERTILIZING: SoilAmendment, // soil amendment replaces fertilizing
+ SCOUTING_TASK: Scout,
+ WASH_AND_PACK_TASK: WashAndPack,
+ OTHER_TASK: CustomIcon,
+ BREAK_TASK: CustomIcon,
+ SOIL_TASK: RecordSoilSample,
+ IRRIGATION_TASK: Irrigate,
+ TRANSPORT_TASK: Transport,
+ SOCIAL_TASK: SocialEvent,
+ CUSTOM_TASK: CustomIcon,
+ };
+
+ return iconDict[key] || CustomIcon;
+}
diff --git a/packages/webapp/src/containers/AddCropVariety/AddCropVariety.js b/packages/webapp/src/containers/AddCropVariety/AddCropVariety.js
deleted file mode 100644
index af33e82912..0000000000
--- a/packages/webapp/src/containers/AddCropVariety/AddCropVariety.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react';
-import PureAddCropVariety from '../../components/AddCropVariety';
-import { shallowEqual, useDispatch, useSelector } from 'react-redux';
-import { cropSelector } from '../cropSlice';
-import { postCropAndVarietal, postVarietal } from './saga';
-import { certifierSurveySelector } from '../OrganicCertifierSurvey/slice';
-import { hookFormPersistSelector } from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import ImagePickerWrapper from '../ImagePickerWrapper';
-import { AddLink } from '../../components/Typography';
-import { useTranslation } from 'react-i18next';
-import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
-
-function AddCropVarietyForm({ history, match }) {
- const { t } = useTranslation(['translation']);
- const dispatch = useDispatch();
- const crop_id = match.params.crop_id;
- const existingCropInfo = useSelector(cropSelector(crop_id));
- const { interested } = useSelector(certifierSurveySelector, shallowEqual);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const isNewCrop = crop_id === 'new';
- const crop = isNewCrop ? persistedFormData : existingCropInfo;
- const onError = (error) => {
- console.log(error);
- };
- const onContinue = (data) => {
- history.push(`/crop/${crop_id}/add_crop_variety/compliance`);
- };
-
- const onSubmit = (data) => {
- const cropData = {
- ...persistedFormData,
- ...data,
- compliance_file_url: '',
- organic: null,
- treated: null,
- genetically_engineered: null,
- searched: null,
- };
- if (isNewCrop) {
- dispatch(postCropAndVarietal(cropData));
- } else {
- dispatch(postVarietal({ ...cropData, crop_id: Number(crop_id) }));
- }
- };
-
- return (
-
-
- {t('CROP.ADD_IMAGE')}
-
- }
- handleGoBack={() => history.goBack()}
- />
-
- );
-}
-
-export default AddCropVarietyForm;
diff --git a/packages/webapp/src/containers/AddCropVariety/AddCropVariety.jsx b/packages/webapp/src/containers/AddCropVariety/AddCropVariety.jsx
new file mode 100644
index 0000000000..80194fb19b
--- /dev/null
+++ b/packages/webapp/src/containers/AddCropVariety/AddCropVariety.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import PureAddCropVariety from '../../components/AddCropVariety';
+import { shallowEqual, useDispatch, useSelector } from 'react-redux';
+import { cropSelector } from '../cropSlice';
+import { postCropAndVarietal, postVarietal } from './saga';
+import { certifierSurveySelector } from '../OrganicCertifierSurvey/slice';
+import { hookFormPersistSelector } from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import ImagePickerWrapper from '../ImagePickerWrapper';
+import { AddLink } from '../../components/Typography';
+import { useTranslation } from 'react-i18next';
+import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
+
+function AddCropVarietyForm({ history, match }) {
+ const { t } = useTranslation(['translation']);
+ const dispatch = useDispatch();
+ const crop_id = match.params.crop_id;
+ const existingCropInfo = useSelector(cropSelector(crop_id));
+ const { interested } = useSelector(certifierSurveySelector, shallowEqual);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const isNewCrop = crop_id === 'new';
+ const crop = isNewCrop ? persistedFormData : existingCropInfo;
+ const onError = (error) => {
+ console.log(error);
+ };
+ const onContinue = (data) => {
+ history.push(`/crop/${crop_id}/add_crop_variety/compliance`);
+ };
+
+ const onSubmit = (data) => {
+ const cropData = {
+ ...persistedFormData,
+ ...data,
+ crop_variety_name: data.crop_variety_name.trim(),
+ supplier: data.supplier.trim(),
+ compliance_file_url: '',
+ organic: null,
+ treated: null,
+ genetically_engineered: null,
+ searched: null,
+ };
+ if (isNewCrop) {
+ dispatch(postCropAndVarietal(cropData));
+ } else {
+ dispatch(postVarietal({ ...cropData, crop_id: Number(crop_id) }));
+ }
+ };
+
+ return (
+
+
+ {t('CROP.ADD_IMAGE')}
+
+ }
+ handleGoBack={() => history.back()}
+ />
+
+ );
+}
+
+export default AddCropVarietyForm;
diff --git a/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.js b/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.js
deleted file mode 100644
index b38c84ef8e..0000000000
--- a/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import ComplianceInfo from '../../components/AddCropVariety/ComplianceInfo';
-import { useDispatch, useSelector } from 'react-redux';
-import { postCropAndVarietal, postVarietal } from './saga';
-import { hookFormPersistSelector } from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
-import { cropSelector } from '../cropSlice';
-
-function ComplianceInfoForm({ history, match }) {
- const dispatch = useDispatch();
- const persistedFormData = useSelector(hookFormPersistSelector);
-
- //TODO: create two different route for creating crop / crop_variety
- const crop_id = match.params.crop_id;
- const crop = useSelector(cropSelector(crop_id));
- const isNewCrop = crop_id === 'new';
-
- const onError = (err) => {
- console.log(err);
- };
-
- const onSubmit = (data) => {
- const cropData = {
- ...persistedFormData,
- ...data,
- hs_code_id: data.hs_code_id || undefined,
- compliance_file_url: '',
- };
- if (isNewCrop) {
- dispatch(postCropAndVarietal(cropData));
- } else {
- dispatch(postVarietal({ ...cropData, crop_id: Number(crop_id) }));
- }
- };
-
- const onGoBack = () => {
- history.goBack();
- };
-
-
- return (
-
-
-
- );
-}
-
-export default ComplianceInfoForm;
diff --git a/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.jsx b/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.jsx
new file mode 100644
index 0000000000..dcd01ece3d
--- /dev/null
+++ b/packages/webapp/src/containers/AddCropVariety/ComplianceInfo.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import ComplianceInfo from '../../components/AddCropVariety/ComplianceInfo';
+import { useDispatch, useSelector } from 'react-redux';
+import { postCropAndVarietal, postVarietal } from './saga';
+import { hookFormPersistSelector } from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
+import { cropSelector } from '../cropSlice';
+
+function ComplianceInfoForm({ history, match }) {
+ const dispatch = useDispatch();
+ const persistedFormData = useSelector(hookFormPersistSelector);
+
+ //TODO: create two different route for creating crop / crop_variety
+ const crop_id = match.params.crop_id;
+ const crop = useSelector(cropSelector(crop_id));
+ const isNewCrop = crop_id === 'new';
+
+ const onError = (err) => {
+ console.log(err);
+ };
+
+ const onSubmit = (data) => {
+ const cropData = {
+ ...persistedFormData,
+ ...data,
+ hs_code_id: data.hs_code_id || undefined,
+ compliance_file_url: '',
+ };
+ if (isNewCrop) {
+ dispatch(postCropAndVarietal(cropData));
+ } else {
+ dispatch(postVarietal({ ...cropData, crop_id: Number(crop_id) }));
+ }
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+
+ return (
+
+
+
+ );
+}
+
+export default ComplianceInfoForm;
diff --git a/packages/webapp/src/containers/AddFarm/currency/commonCurrency.json b/packages/webapp/src/containers/AddFarm/currency/commonCurrency.json
index e1c2612444..4991092f64 100644
--- a/packages/webapp/src/containers/AddFarm/currency/commonCurrency.json
+++ b/packages/webapp/src/containers/AddFarm/currency/commonCurrency.json
@@ -656,6 +656,15 @@
"code": "MUR",
"name_plural": "Mauritian rupees"
},
+ "MWK": {
+ "symbol": "MK",
+ "name": "Malawian Kwacha",
+ "symbol_native": "MK",
+ "decimal_digits": 2,
+ "rounding": 0,
+ "code": "MWK",
+ "name_plural": "Malawian kwachas"
+ },
"MXN": {
"symbol": "MX$",
"name": "Mexican Peso",
diff --git a/packages/webapp/src/containers/AddFarm/currency/currency.js b/packages/webapp/src/containers/AddFarm/currency/currency.js
deleted file mode 100644
index 4bf124e821..0000000000
--- a/packages/webapp/src/containers/AddFarm/currency/currency.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import commonCurrency from './commonCurrency.json';
-
-export const currencyOutput = (code) => {
- if (!code in commonCurrency) {
- console.log('WARNING: ' + code + ' is not part of the common currency in the system');
- return '$';
- } else {
- return commonCurrency[code]['symbol_native'];
- }
-};
diff --git a/packages/webapp/src/containers/AddFarm/index.js b/packages/webapp/src/containers/AddFarm/index.js
deleted file mode 100644
index 2fe3f7ae66..0000000000
--- a/packages/webapp/src/containers/AddFarm/index.js
+++ /dev/null
@@ -1,323 +0,0 @@
-import { useForm } from 'react-hook-form';
-import React, { useRef, useState } from 'react';
-import Script from 'react-load-script';
-import GoogleMap from 'google-map-react';
-import { VscLocation } from 'react-icons/vsc';
-import { useDispatch, useSelector } from 'react-redux';
-import {
- userFarmReducerSelector,
- userFarmsByUserSelector,
- userFarmSelector,
-} from '../userFarmSlice';
-
-import PureAddFarm from '../../components/AddFarm';
-import { patchFarm, postFarm } from './saga';
-import { ReactComponent as MapPin } from '../../assets/images/signUp/map_pin.svg';
-import { ReactComponent as MapErrorPin } from '../../assets/images/signUp/map_error_pin.svg';
-import { ReactComponent as LoadingAnimation } from '../../assets/images/signUp/animated_loading_farm.svg';
-import { useTranslation } from 'react-i18next';
-import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
-import history from '../../history';
-import { useThrottle } from '../hooks/useThrottle';
-import { pick } from '../../util/pick';
-
-const AddFarm = () => {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const farm = useSelector(userFarmSelector);
- const farms = useSelector(userFarmsByUserSelector);
- const isFirstFarm = !farms.length;
- const mainUserFarmSelector = useSelector(userFarmReducerSelector);
- const FARMNAME = 'farm_name';
- const ADDRESS = 'address';
- const GRID_POINTS = 'grid_points';
- const COUNTRY = 'country';
- const {
- register,
- handleSubmit,
- getValues,
- setValue,
- setError,
- watch,
- trigger,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onBlur',
- defaultValues: pick(farm, [FARMNAME, ADDRESS, GRID_POINTS, COUNTRY]),
- });
-
- const gridPoints = watch(GRID_POINTS);
- const disabled = !isValid;
- const [isGettingLocation, setIsGettingLocation] = useState(false);
- const farmNameRegister = register(FARMNAME, {
- required: { value: true, message: t('ADD_FARM.FARM_IS_REQUIRED') },
- });
- const addressRegister = register(ADDRESS, {
- required: { value: true, message: t('ADD_FARM.ADDRESS_IS_REQUIRED') },
- });
- const gridPointsRegister = register(GRID_POINTS, {
- required: { value: true, message: t('ADD_FARM.ENTER_A_VALID_ADDRESS') },
- });
- const countryRegister = register(COUNTRY, {
- required: { value: true, message: t('ADD_FARM.INVALID_FARM_LOCATION') },
- });
- const errorMessage = {
- geolocationDisabled: t('ADD_FARM.DISABLE_GEO_LOCATION'),
- };
-
- const addressErrors =
- errors[ADDRESS]?.message ||
- errors[GRID_POINTS]?.message ||
- errors[COUNTRY]?.message ||
- errorMessage[errors[ADDRESS]?.type];
-
- const onSubmit = (data) => {
- const farmInfo = {
- ...data,
- gridPoints,
- farm_id: farm ? farm.farm_id : undefined,
- };
- farm.farm_id ? dispatch(patchFarm(farmInfo)) : dispatch(postFarm(farmInfo));
- };
-
- const onGoBack = () => {
- history.push('/farm_selection');
- };
-
- const placesAutocompleteRef = useRef();
- const handleScriptLoad = () => {
- const options = {
- types: ['address'],
- language: getLanguageFromLocalStorage(),
- };
-
- // Initialize Google Autocomplete
- placesAutocompleteRef.current = new google.maps.places.Autocomplete(
- document.getElementById('autocomplete'),
- options,
- );
-
- // Avoid paying for data that you don't need by restricting the set of
- // place fields that are returned to just the address components and formatted
- // address.
- placesAutocompleteRef.current.setFields(['geometry', 'formatted_address', 'address_component']);
-
- // Fire Event when a suggested name is selected
- placesAutocompleteRef.current.addListener('place_changed', handlePlaceChanged);
- };
-
- const geocoderRef = useRef();
- const geocoderTimeout = useThrottle();
- const setCountryFromLatLng = (latlng, callback) => {
- const { lat, lng } = latlng;
- if (!geocoderRef.current) {
- geocoderRef.current = new google.maps.Geocoder();
- }
- geocoderTimeout(
- () =>
- geocoderRef.current.geocode({ location: { lat, lng } }, (results, status) => {
- let country;
- status === 'OK' &&
- results.find((place) =>
- place?.address_components?.find((component) => {
- if (component?.types?.includes?.('country')) {
- country = component.long_name;
- return true;
- }
- return false;
- }),
- );
- setValue(GRID_POINTS, { lat, lng }, { shouldValidate: true });
- setValue(COUNTRY, country, { shouldValidate: true });
- callback?.();
- }),
- isGettingLocation ? 0 : 500,
- );
- };
-
- const parseLatLng = (latLngString) => {
- const coordRegex = /^(-?\d+(?:\.\d+)?)[,\s]\s*(-?\d+(\.\d+)?)$/;
- const matches = coordRegex.exec(latLngString);
- if (!matches) return null;
-
- const result = { lat: parseFloat(matches[1]), lng: parseFloat(matches[2]) };
- return Number.isNaN(result.lat) ||
- Number.isNaN(result.lng) ||
- result.lat < -90 ||
- result.lat > 90 ||
- result.lng < -180 ||
- result.lng > 180
- ? null
- : result;
- };
-
- const handleAddressChange = (e) => {
- const latlng = parseLatLng(e.target.value);
- if (latlng) {
- setCountryFromLatLng(latlng);
- } else {
- /**
- * GOOGLE MAP listener handlePlaceChanged is delayed, so gridPoints and country will be cleared before handlePlaceChanged is called.
- * Since forced validation is delayed by 100ms, clearing GRID_POINTS and COUNTRY would not trigger error before handlePlaceChanged is called.
- */
- setValue(GRID_POINTS, undefined);
- setValue(COUNTRY, undefined);
- }
- };
-
- const handleAddressBlur = () => {
- setTimeout(() => {
- trigger([GRID_POINTS, COUNTRY]);
- }, 100);
- };
-
- const handlePlaceChanged = () => {
- const place = placesAutocompleteRef.current.getPlace();
- if (place?.geometry?.location) {
- const countryLookup = place.address_components.find((component) =>
- component.types.includes('country'),
- ).long_name;
-
- setValue(
- GRID_POINTS,
- {
- lat: place.geometry.location.lat(),
- lng: place.geometry.location.lng(),
- },
- { shouldValidate: true },
- );
- setValue(COUNTRY, countryLookup, { shouldValidate: true });
- setValue(ADDRESS, place.formatted_address, { shouldValidate: true });
- }
- };
-
- const handleGetGeoError = () => {
- setIsGettingLocation(false);
- setError(ADDRESS, {
- type: 'geolocationDisabled',
- });
- };
-
- const getGeoOptions = {
- enableHighAccuracy: true,
- timeout: 5000,
- maximumAge: 10000,
- };
-
- const handleGetGeoSuccess = (position) => {
- const lat = position.coords.latitude;
- const lng = position.coords.longitude;
- setValue(ADDRESS, `${lat}, ${lng}`, { shouldValidate: true });
- setCountryFromLatLng({ lat, lng }, () => {
- setIsGettingLocation(false);
- });
- };
-
- const getGeoLocation = () => {
- setIsGettingLocation(true);
- navigator.geolocation.getCurrentPosition(handleGetGeoSuccess, handleGetGeoError, getGeoOptions);
- };
- return (
- <>
-
- {t('ADD_FARM.LOCATING')}
- ) : (
-
- ),
- hookFormRegister: addressRegister,
- id: 'autocomplete',
- name: ADDRESS,
- errors: addressErrors,
- onBlur: handleAddressBlur,
- onChange: handleAddressChange,
- },
- ]}
- map={
-
- }
- />
- >
- );
-};
-
-function Map({ gridPoints, errors, isGettingLocation }) {
- return (
-
- {(!isGettingLocation && gridPoints && gridPoints.lat && (
-
({
- mapTypeId: maps.MapTypeId.SATELLITE,
- disableDoubleClickZoom: true,
- zoomControl: true,
- streetViewControl: false,
- scaleControl: true,
- fullscreenControl: false,
- })}
- >
-
-
- )) || (
-
- {(!!errors && ) || (isGettingLocation ? : )}
-
- )}
-
- );
-}
-
-function MapPinWrapper() {
- return ;
-}
-
-export default AddFarm;
-
-/* global google */
diff --git a/packages/webapp/src/containers/AddFarm/index.jsx b/packages/webapp/src/containers/AddFarm/index.jsx
new file mode 100644
index 0000000000..ec9113d450
--- /dev/null
+++ b/packages/webapp/src/containers/AddFarm/index.jsx
@@ -0,0 +1,333 @@
+import { useForm } from 'react-hook-form';
+import React, { useRef, useState } from 'react';
+import Script from 'react-load-script';
+import GoogleMap from 'google-map-react';
+import { VscLocation } from 'react-icons/vsc';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ userFarmReducerSelector,
+ userFarmsByUserSelector,
+ userFarmSelector,
+} from '../userFarmSlice';
+
+import PureAddFarm from '../../components/AddFarm';
+import { patchFarm, postFarm } from './saga';
+import { ReactComponent as MapPin } from '../../assets/images/signUp/map_pin.svg';
+import { ReactComponent as MapErrorPin } from '../../assets/images/signUp/map_error_pin.svg';
+import { ReactComponent as LoadingAnimation } from '../../assets/images/signUp/animated_loading_farm.svg';
+import { useTranslation } from 'react-i18next';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+import history from '../../history';
+import { useThrottle } from '../hooks/useThrottle';
+import { pick } from '../../util/pick';
+
+const AddFarm = () => {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const farm = useSelector(userFarmSelector);
+ const farms = useSelector(userFarmsByUserSelector);
+ const isFirstFarm = !farms.length;
+ const mainUserFarmSelector = useSelector(userFarmReducerSelector);
+ const FARMNAME = 'farm_name';
+ const ADDRESS = 'address';
+ const GRID_POINTS = 'grid_points';
+ const COUNTRY = 'country';
+ const {
+ register,
+ handleSubmit,
+ getValues,
+ setValue,
+ setError,
+ watch,
+ trigger,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onBlur',
+ defaultValues: pick(farm, [FARMNAME, ADDRESS, GRID_POINTS, COUNTRY]),
+ });
+
+ const gridPoints = watch(GRID_POINTS);
+ const disabled = !isValid;
+ const [isGettingLocation, setIsGettingLocation] = useState(false);
+ const farmNameRegister = register(FARMNAME, {
+ required: { value: true, message: t('ADD_FARM.FARM_IS_REQUIRED') },
+ });
+ const addressRegister = register(ADDRESS, {
+ required: { value: true, message: t('ADD_FARM.ADDRESS_IS_REQUIRED') },
+ });
+ const gridPointsRegister = register(GRID_POINTS, {
+ required: { value: true, message: t('ADD_FARM.ENTER_A_VALID_ADDRESS') },
+ });
+ const countryRegister = register(COUNTRY, {
+ required: { value: true, message: t('ADD_FARM.INVALID_FARM_LOCATION') },
+ });
+ const errorMessage = {
+ geolocationDisabled: t('ADD_FARM.DISABLE_GEO_LOCATION'),
+ };
+
+ const addressErrors =
+ errors[ADDRESS]?.message ||
+ errors[GRID_POINTS]?.message ||
+ errors[COUNTRY]?.message ||
+ errorMessage[errors[ADDRESS]?.type];
+
+ const showFarmNameCharacterLimitExceededError = () => {
+ setError(FARMNAME, {
+ type: 'manual',
+ message: t('ADD_FARM.FARM_NAME_ERROR'),
+ });
+ };
+
+ const onSubmit = (data) => {
+ const farmInfo = {
+ ...data,
+ gridPoints,
+ farm_id: farm ? farm.farm_id : undefined,
+ showFarmNameCharacterLimitExceededError: showFarmNameCharacterLimitExceededError,
+ };
+ farm.farm_id ? dispatch(patchFarm(farmInfo)) : dispatch(postFarm(farmInfo));
+ };
+
+ const onGoBack = () => {
+ history.push('/farm_selection');
+ };
+
+ const placesAutocompleteRef = useRef();
+ const handleScriptLoad = () => {
+ const options = {
+ types: ['address'],
+ language: getLanguageFromLocalStorage(),
+ };
+
+ // Initialize Google Autocomplete
+ placesAutocompleteRef.current = new google.maps.places.Autocomplete(
+ document.getElementById('autocomplete'),
+ options,
+ );
+
+ // Avoid paying for data that you don't need by restricting the set of
+ // place fields that are returned to just the address components and formatted
+ // address.
+ placesAutocompleteRef.current.setFields(['geometry', 'formatted_address', 'address_component']);
+
+ // Fire Event when a suggested name is selected
+ placesAutocompleteRef.current.addListener('place_changed', handlePlaceChanged);
+ };
+
+ const geocoderRef = useRef();
+ const geocoderTimeout = useThrottle();
+ const setCountryFromLatLng = (latlng, callback) => {
+ const { lat, lng } = latlng;
+ if (!geocoderRef.current) {
+ geocoderRef.current = new google.maps.Geocoder();
+ }
+ geocoderTimeout(
+ () =>
+ geocoderRef.current.geocode({ location: { lat, lng } }, (results, status) => {
+ let country;
+ status === 'OK' &&
+ results.find((place) =>
+ place?.address_components?.find((component) => {
+ if (component?.types?.includes?.('country')) {
+ country = component.long_name;
+ return true;
+ }
+ return false;
+ }),
+ );
+ setValue(GRID_POINTS, { lat, lng }, { shouldValidate: true });
+ setValue(COUNTRY, country, { shouldValidate: true });
+ callback?.();
+ }),
+ isGettingLocation ? 0 : 500,
+ );
+ };
+
+ const parseLatLng = (latLngString) => {
+ const coordRegex = /^(-?\d+(?:\.\d+)?)[,\s]\s*(-?\d+(\.\d+)?)$/;
+ const matches = coordRegex.exec(latLngString);
+ if (!matches) return null;
+
+ const result = { lat: parseFloat(matches[1]), lng: parseFloat(matches[2]) };
+ return Number.isNaN(result.lat) ||
+ Number.isNaN(result.lng) ||
+ result.lat < -90 ||
+ result.lat > 90 ||
+ result.lng < -180 ||
+ result.lng > 180
+ ? null
+ : result;
+ };
+
+ const handleAddressChange = (e) => {
+ const latlng = parseLatLng(e.target.value);
+ if (latlng) {
+ setCountryFromLatLng(latlng);
+ } else {
+ /**
+ * GOOGLE MAP listener handlePlaceChanged is delayed, so gridPoints and country will be cleared before handlePlaceChanged is called.
+ * Since forced validation is delayed by 100ms, clearing GRID_POINTS and COUNTRY would not trigger error before handlePlaceChanged is called.
+ */
+ setValue(GRID_POINTS, undefined);
+ setValue(COUNTRY, undefined);
+ }
+ };
+
+ const handleAddressBlur = () => {
+ setTimeout(() => {
+ trigger([GRID_POINTS, COUNTRY]);
+ }, 100);
+ };
+
+ const handlePlaceChanged = () => {
+ const place = placesAutocompleteRef.current.getPlace();
+ if (place?.geometry?.location) {
+ const countryLookup = place.address_components.find((component) =>
+ component.types.includes('country'),
+ )?.long_name;
+
+ setValue(
+ GRID_POINTS,
+ {
+ lat: place.geometry.location.lat(),
+ lng: place.geometry.location.lng(),
+ },
+ { shouldValidate: true },
+ );
+ setValue(COUNTRY, countryLookup, { shouldValidate: true });
+ setValue(ADDRESS, place.formatted_address, { shouldValidate: true });
+ }
+ };
+
+ const handleGetGeoError = () => {
+ setIsGettingLocation(false);
+ setError(ADDRESS, {
+ type: 'geolocationDisabled',
+ });
+ };
+
+ const getGeoOptions = {
+ enableHighAccuracy: true,
+ timeout: 5000,
+ maximumAge: 10000,
+ };
+
+ const handleGetGeoSuccess = (position) => {
+ const lat = position.coords.latitude;
+ const lng = position.coords.longitude;
+ setValue(ADDRESS, `${lat}, ${lng}`, { shouldValidate: true });
+ setCountryFromLatLng({ lat, lng }, () => {
+ setIsGettingLocation(false);
+ });
+ };
+
+ const getGeoLocation = () => {
+ setIsGettingLocation(true);
+ navigator.geolocation.getCurrentPosition(handleGetGeoSuccess, handleGetGeoError, getGeoOptions);
+ };
+ return (
+ <>
+
+ {t('ADD_FARM.LOCATING')}
+ ) : (
+
+ ),
+ hookFormRegister: addressRegister,
+ id: 'autocomplete',
+ name: ADDRESS,
+ errors: addressErrors,
+ onBlur: handleAddressBlur,
+ onChange: handleAddressChange,
+ },
+ ]}
+ map={
+
+ }
+ />
+ >
+ );
+};
+
+function Map({ gridPoints, errors, isGettingLocation }) {
+ return (
+
+ {(!isGettingLocation && gridPoints && gridPoints.lat && (
+
({
+ mapTypeId: maps.MapTypeId.SATELLITE,
+ disableDoubleClickZoom: true,
+ zoomControl: true,
+ streetViewControl: false,
+ scaleControl: true,
+ fullscreenControl: false,
+ })}
+ >
+
+
+ )) || (
+
+ {(!!errors && ) || (isGettingLocation ? : )}
+
+ )}
+
+ );
+}
+
+function MapPinWrapper() {
+ return ;
+}
+
+export default AddFarm;
+
+/* global google */
diff --git a/packages/webapp/src/containers/AddFarm/saga.js b/packages/webapp/src/containers/AddFarm/saga.js
index c5dd8fd47a..bd6fced137 100644
--- a/packages/webapp/src/containers/AddFarm/saga.js
+++ b/packages/webapp/src/containers/AddFarm/saga.js
@@ -35,7 +35,7 @@ const patchFarmUrl = (farm_id) => `${farmUrl}/owner_operated/${farm_id}`;
const patchStepUrl = (farm_id, user_id) =>
`${userFarmUrl}/onboarding/farm/${farm_id}/user/${user_id}`;
export const postFarm = createAction('postFarmSaga');
-export function* postFarmSaga({ payload: farm }) {
+export function* postFarmSaga({ payload: { showFarmNameCharacterLimitExceededError, ...farm } }) {
const { user_id } = yield select(loginSelector);
yield put(setLoadingStart());
let addFarmData = {
@@ -75,13 +75,21 @@ export function* postFarmSaga({ payload: farm }) {
localStorage.setItem('farm_token', farm_token);
} catch (e) {
yield put(setLoadingEnd());
- console.log(e);
- yield put(enqueueErrorSnackbar(i18n.t('message:FARM.ERROR.ADD')));
+ const isFarmNameError =
+ e?.response?.status === 400 &&
+ e?.response?.data?.name === 'ValidationError' &&
+ !!e?.response?.data?.data?.farm_name?.length;
+ if (isFarmNameError) {
+ showFarmNameCharacterLimitExceededError();
+ } else {
+ console.log(e);
+ yield put(enqueueErrorSnackbar(i18n.t('message:FARM.ERROR.ADD')));
+ }
}
}
export const patchFarm = createAction('patchFarmSaga');
-export function* patchFarmSaga({ payload: farm }) {
+export function* patchFarmSaga({ payload: { showFarmNameCharacterLimitExceededError, ...farm } }) {
const { user_id, farm_id, step_one } = yield select(userFarmSelector);
const header = getHeader(user_id, farm_id);
@@ -105,8 +113,16 @@ export function* patchFarmSaga({ payload: farm }) {
yield put(patchFarmSuccess({ ...farm, user_id, step_one: true }));
history.push('/role_selection');
} catch (e) {
- console.error(e);
- yield put(enqueueErrorSnackbar(i18n.t('message:FARM.ERROR.ADD')));
+ const isFarmNameError =
+ e?.response?.status === 400 &&
+ typeof e?.response?.data?.error === 'string' &&
+ e?.response?.data?.error?.includes('farm_name:');
+ if (isFarmNameError) {
+ showFarmNameCharacterLimitExceededError();
+ } else {
+ console.error(e);
+ yield put(enqueueErrorSnackbar(i18n.t('message:FARM.ERROR.ADD')));
+ }
}
}
diff --git a/packages/webapp/src/containers/AddNewCrop/index.js b/packages/webapp/src/containers/AddNewCrop/index.js
deleted file mode 100644
index bcbdbf0ba7..0000000000
--- a/packages/webapp/src/containers/AddNewCrop/index.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import PureAddNewCrop from '../../components/AddNewCrop';
-import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
-
-function AddNewCrop({ history }) {
- const onError = (error) => {
- console.log(error);
- };
-
- return (
-
- history.push(`/crop/new/add_crop_variety`)}
- handleGoBack={() => history.goBack()}
- handleError={onError}
- />
-
- );
-}
-
-export default AddNewCrop;
diff --git a/packages/webapp/src/containers/AddNewCrop/index.jsx b/packages/webapp/src/containers/AddNewCrop/index.jsx
new file mode 100644
index 0000000000..0a2558abe8
--- /dev/null
+++ b/packages/webapp/src/containers/AddNewCrop/index.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import PureAddNewCrop from '../../components/AddNewCrop';
+import { HookFormPersistProvider } from '../hooks/useHookFormPersist/HookFormPersistProvider';
+
+function AddNewCrop({ history }) {
+ const onError = (error) => {
+ console.log(error);
+ };
+
+ return (
+
+ history.push(`/crop/new/add_crop_variety`)}
+ handleGoBack={() => history.back()}
+ handleError={onError}
+ />
+
+ );
+}
+
+export default AddNewCrop;
diff --git a/packages/webapp/src/containers/Callback/index.js b/packages/webapp/src/containers/Callback/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Callback/index.js
rename to packages/webapp/src/containers/Callback/index.jsx
diff --git a/packages/webapp/src/containers/Callback/saga.js b/packages/webapp/src/containers/Callback/saga.js
index 903a2846e9..6442fcd20d 100644
--- a/packages/webapp/src/containers/Callback/saga.js
+++ b/packages/webapp/src/containers/Callback/saga.js
@@ -18,8 +18,7 @@ import { call, put, select, takeLeading } from 'redux-saga/effects';
import { url } from '../../apiConfig';
import history from '../../history';
import { acceptInvitationSuccess, userFarmSelector } from '../userFarmSlice';
-import { purgeState } from '../../index';
-import jwt from 'jsonwebtoken';
+import jwt from '@tsndr/cloudflare-worker-jwt';
import i18n from '../../locales/i18n';
import { logout } from '../../util/jwt';
import { axios } from '../saga';
@@ -27,6 +26,7 @@ import { axios } from '../saga';
import { startInvitationFlow } from '../ChooseFarm/chooseFarmFlowSlice';
import { enqueueErrorSnackbar } from '../Snackbar/snackbarSlice';
import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+import { purgeState } from '../../store/store';
const validateResetTokenUrl = () => `${url}/password_reset/validate`;
const patchUserFarmStatusUrl = () => `${url}/user_farm/accept_invitation`;
diff --git a/packages/webapp/src/containers/Certifications/ReportingPeriod/index.js b/packages/webapp/src/containers/Certifications/ReportingPeriod/index.js
deleted file mode 100644
index 357b1069de..0000000000
--- a/packages/webapp/src/containers/Certifications/ReportingPeriod/index.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, { useEffect } from 'react';
-import PureCertificationReportingPeriod from '../../../components/CertificationReportingPeriod';
-import { useSelector } from 'react-redux';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { userFarmSelector } from '../../userFarmSlice';
-import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
-
-function CertificationReportingPeriod({ history, match }) {
- const { email } = useSelector(userFarmSelector);
- const { interested } = useSelector(certifierSurveySelector);
- const onError = (error) => {
- console.log(error);
- };
- const onContinue = (data) => {
- history.push('/certification/survey');
- };
-
- useEffect(() => {
- if (!interested) history.push('/certification');
- }, []); //TODO: create check in routes file?
-
- return (
-
- history.goBack()}
- defaultEmail={email}
- />
-
- );
-}
-
-export default CertificationReportingPeriod;
diff --git a/packages/webapp/src/containers/Certifications/ReportingPeriod/index.jsx b/packages/webapp/src/containers/Certifications/ReportingPeriod/index.jsx
new file mode 100644
index 0000000000..b7ec8d77e9
--- /dev/null
+++ b/packages/webapp/src/containers/Certifications/ReportingPeriod/index.jsx
@@ -0,0 +1,34 @@
+import React, { useEffect } from 'react';
+import PureCertificationReportingPeriod from '../../../components/CertificationReportingPeriod';
+import { useSelector } from 'react-redux';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { userFarmSelector } from '../../userFarmSlice';
+import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
+
+function CertificationReportingPeriod({ history, match }) {
+ const { email } = useSelector(userFarmSelector);
+ const { interested } = useSelector(certifierSurveySelector);
+ const onError = (error) => {
+ console.log(error);
+ };
+ const onContinue = (data) => {
+ history.push('/certification/survey');
+ };
+
+ useEffect(() => {
+ if (!interested) history.push('/certification');
+ }, []); //TODO: create check in routes file?
+
+ return (
+
+ history.back()}
+ defaultEmail={email}
+ />
+
+ );
+}
+
+export default CertificationReportingPeriod;
diff --git a/packages/webapp/src/containers/Certifications/Survey/index.js b/packages/webapp/src/containers/Certifications/Survey/index.js
deleted file mode 100644
index 3dbd3b55fa..0000000000
--- a/packages/webapp/src/containers/Certifications/Survey/index.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import React from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { useTranslation } from 'react-i18next';
-import PureCertificationSurveyPage from '../../../components/CertificationSurvey';
-import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
-import { certifierSelector } from '../../OrganicCertifierSurvey/certifierSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { exportCertificationData } from '../saga';
-import { setSubmissionIdCertificationFormData } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { userFarmSelector } from '../../userFarmSlice';
-
-function CertificationSurveyPage({ history, match }) {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const onExport = (exportData) => {
- dispatch(exportCertificationData(exportData));
- };
-
- const onSurveyComplete = (submissionId) => {
- dispatch(setSubmissionIdCertificationFormData(submissionId));
- };
-
- const certifierSurvey = useSelector(certifierSurveySelector);
- const certifier = useSelector(certifierSelector);
- const { interested, requested_certifier } = certifierSurvey;
-
- const { email } = useSelector(userFarmSelector);
-
- return (
-
- history.goBack()}
- handleCancel={() => history.push('/certification')}
- certifierSurvey={certifierSurvey}
- interested={interested}
- certifier={certifier}
- requested_certifier={requested_certifier}
- onSurveyComplete={onSurveyComplete}
- email={email}
- />
-
- );
-}
-
-export default CertificationSurveyPage;
diff --git a/packages/webapp/src/containers/Certifications/Survey/index.jsx b/packages/webapp/src/containers/Certifications/Survey/index.jsx
new file mode 100644
index 0000000000..3f9aed146a
--- /dev/null
+++ b/packages/webapp/src/containers/Certifications/Survey/index.jsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import PureCertificationSurveyPage from '../../../components/CertificationSurvey';
+import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
+import { certifierSelector } from '../../OrganicCertifierSurvey/certifierSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { exportCertificationData } from '../saga';
+import { setSubmissionIdCertificationFormData } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { userFarmSelector } from '../../userFarmSlice';
+
+function CertificationSurveyPage({ history, match }) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const onExport = (exportData) => {
+ dispatch(exportCertificationData(exportData));
+ };
+
+ const onSurveyComplete = (submissionId) => {
+ dispatch(setSubmissionIdCertificationFormData(submissionId));
+ };
+
+ const certifierSurvey = useSelector(certifierSurveySelector);
+ const certifier = useSelector(certifierSelector);
+ const { interested, requested_certifier } = certifierSurvey;
+
+ const { email } = useSelector(userFarmSelector);
+
+ return (
+
+ history.back()}
+ handleCancel={() => history.push('/certification')}
+ certifierSurvey={certifierSurvey}
+ interested={interested}
+ certifier={certifier}
+ requested_certifier={requested_certifier}
+ onSurveyComplete={onSurveyComplete}
+ email={email}
+ />
+
+ );
+}
+
+export default CertificationSurveyPage;
diff --git a/packages/webapp/src/containers/ChooseFarm/index.js b/packages/webapp/src/containers/ChooseFarm/index.js
deleted file mode 100644
index 49eadf6b59..0000000000
--- a/packages/webapp/src/containers/ChooseFarm/index.js
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { useEffect, useState } from 'react';
-import history from '../../history';
-import {
- deselectFarmSuccess,
- loginSelector,
- userFarmEntitiesSelector,
- userFarmsByUserSelector,
- userFarmStatusSelector,
-} from '../userFarmSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import PureChooseFarmScreen from '../../components/ChooseFarm';
-import { getSpotlightFlags, getUserFarms, patchUserFarmStatusWithIDToken } from './saga';
-import { useTranslation } from 'react-i18next';
-import Spinner from '../../components/Spinner';
-import { startSwitchFarmModal } from './chooseFarmFlowSlice';
-import { selectFarmAndFetchAll } from '../saga';
-
-function ChooseFarm() {
- const { t } = useTranslation();
- const dispatch = useDispatch();
-
- const [selectedFarmId, setFarmId] = useState();
- const { farm_id: currentFarmId, user_id } = useSelector(loginSelector);
- const [filter, setFilter] = useState();
- const userFarmEntities = useSelector(userFarmEntitiesSelector);
-
- useEffect(() => {
- dispatch(getUserFarms());
- dispatch(getSpotlightFlags());
- }, []);
-
- const farms = useSelector(userFarmsByUserSelector);
- useEffect(() => {
- if (farms?.length === 1 && ['Invited', 'Active'].includes(farms[0].status)) {
- setFarmId(farms[0].farm_id);
- }
- }, [farms]);
- // TODO: move redirect to login with google saga
- const { loaded } = useSelector(userFarmStatusSelector);
- useEffect(() => {
- loaded && farms.length === 0 && history.push('/welcome');
- }, [farms, loaded]);
-
- const onGoBack = () => {
- history.goBack();
- };
-
- const onProceed = () => {
- const farm = userFarmEntities[selectedFarmId][user_id];
- if (farm.status === 'Active') {
- if (currentFarmId) {
- dispatch(startSwitchFarmModal(selectedFarmId));
- }
- dispatch(selectFarmAndFetchAll({ farm_id: selectedFarmId }));
- } else {
- dispatch(patchUserFarmStatusWithIDToken(farm));
- }
- };
-
- const onSelectFarm = (farm_id) => {
- setFarmId(farm_id);
- };
-
- const onCreateFarm = () => {
- dispatch(deselectFarmSuccess());
- history.push('/add_farm');
- };
-
- const onFilterChange = (e) => {
- setFilter(e.target.value.toLowerCase());
- };
-
- useEffect(() => {
- const { farm_id } = history.location.state || {};
- if (farm_id) {
- setFarmId(farm_id);
- }
- }, []);
-
- return loaded && farms.length ? (
- 5}
- disabled={!selectedFarmId}
- title={currentFarmId ? t('CHOOSE_FARM.SWITCH_TITLE') : t('CHOOSE_FARM.CHOOSE_TITLE')}
- />
- ) : (
-
- );
-}
-
-const getFormattedFarms = ({ filter, farms, currentFarmId, selectedFarmId }) => {
- const farmOrderByStatus = {
- Active: 1,
- Invited: 2,
- Inactive: 3,
- };
- const filteredFarms = filter
- ? farms.filter(
- (farm) =>
- (farm.owner_name && farm.owner_name.toLowerCase().includes(filter)) ||
- farm.farm_name.toLowerCase().includes(filter) ||
- farm.address.toLowerCase().includes(filter) ||
- farm.farm_id === currentFarmId,
- )
- : farms;
-
- const sortedFarm = filteredFarms.sort((farm1, farm2) => {
- if (farm1.status !== farm2.status) {
- return farmOrderByStatus[farm1.status] - farmOrderByStatus[farm2.status];
- } else if (farm1.farm_id !== currentFarmId && farm2.farm_id !== currentFarmId) {
- return farm1.farm_name.localeCompare(farm2.farm_name);
- } else {
- return farm1.farm_id === currentFarmId ? -1 : 1;
- }
- });
-
- return sortedFarm.map((farm) => {
- const newFarm = {};
- newFarm.farm_id = farm.farm_id;
- newFarm.address = getAddress(farm, newFarm);
- newFarm.farmName = farm.farm_name;
- newFarm.ownerName = farm.owner_name;
- newFarm.color = getColor(farm, selectedFarmId, currentFarmId);
- return newFarm;
- });
-};
-
-const getAddress = (farm, newFarm) => {
- const { address } = farm;
- const isCoordinate = /-?\d*\.\d*, -?\d*\.\d*/.test(address);
- if (isCoordinate) {
- return [farm.grid_points.lat.toFixed(5), farm.grid_points.lng.toFixed(5)];
- } else {
- newFarm.fullAddress = address?.replace(/(.*), .*/, '$1');
- const addressArray = address?.split(', ');
- return addressArray?.splice(0, addressArray.length - 1);
- }
-};
-
-const getColor = (farm, selectedFarmId, currentFarmId) => {
- if (farm.farm_id === currentFarmId || farm.status === 'Inactive') {
- return 'disabled';
- } else if (farm.farm_id === selectedFarmId) {
- return farm.status === 'Invited' ? 'blueActive' : 'active';
- } else if (farm.status === 'Invited') {
- return 'blue';
- } else return 'secondary';
-};
-
-export default ChooseFarm;
diff --git a/packages/webapp/src/containers/ChooseFarm/index.jsx b/packages/webapp/src/containers/ChooseFarm/index.jsx
new file mode 100644
index 0000000000..f4c4df8601
--- /dev/null
+++ b/packages/webapp/src/containers/ChooseFarm/index.jsx
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (index.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { useEffect, useState } from 'react';
+import history from '../../history';
+import {
+ deselectFarmSuccess,
+ loginSelector,
+ userFarmEntitiesSelector,
+ userFarmsByUserSelector,
+ userFarmStatusSelector,
+} from '../userFarmSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import PureChooseFarmScreen from '../../components/ChooseFarm';
+import { getSpotlightFlags, getUserFarms, patchUserFarmStatusWithIDToken } from './saga';
+import { useTranslation } from 'react-i18next';
+import Spinner from '../../components/Spinner';
+import { startSwitchFarmModal } from './chooseFarmFlowSlice';
+import { selectFarmAndFetchAll } from '../saga';
+
+function ChooseFarm() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const [selectedFarmId, setFarmId] = useState();
+ const { farm_id: currentFarmId, user_id } = useSelector(loginSelector);
+ const [filter, setFilter] = useState();
+ const userFarmEntities = useSelector(userFarmEntitiesSelector);
+
+ useEffect(() => {
+ dispatch(getUserFarms());
+ dispatch(getSpotlightFlags());
+ }, []);
+
+ const farms = useSelector(userFarmsByUserSelector);
+ useEffect(() => {
+ if (farms?.length === 1 && ['Invited', 'Active'].includes(farms[0].status)) {
+ setFarmId(farms[0].farm_id);
+ }
+ }, [farms]);
+ // TODO: move redirect to login with google saga
+ const { loaded } = useSelector(userFarmStatusSelector);
+ useEffect(() => {
+ loaded && farms.length === 0 && history.push('/welcome');
+ }, [farms, loaded]);
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ const onProceed = () => {
+ const farm = userFarmEntities[selectedFarmId][user_id];
+ if (farm.status === 'Active') {
+ if (currentFarmId) {
+ dispatch(startSwitchFarmModal(selectedFarmId));
+ }
+ dispatch(selectFarmAndFetchAll({ farm_id: selectedFarmId }));
+ } else {
+ dispatch(patchUserFarmStatusWithIDToken(farm));
+ }
+ };
+
+ const onSelectFarm = (farm_id) => {
+ setFarmId(farm_id);
+ };
+
+ const onCreateFarm = () => {
+ dispatch(deselectFarmSuccess());
+ history.push('/add_farm');
+ };
+
+ const onFilterChange = (e) => {
+ setFilter(e.target.value.toLowerCase());
+ };
+
+ useEffect(() => {
+ const { farm_id } = history.location.state || {};
+ if (farm_id) {
+ setFarmId(farm_id);
+ }
+ }, []);
+
+ return loaded && farms.length ? (
+ 5}
+ disabled={!selectedFarmId}
+ title={currentFarmId ? t('CHOOSE_FARM.SWITCH_TITLE') : t('CHOOSE_FARM.CHOOSE_TITLE')}
+ />
+ ) : (
+
+ );
+}
+
+const getFormattedFarms = ({ filter, farms, currentFarmId, selectedFarmId }) => {
+ const farmOrderByStatus = {
+ Active: 1,
+ Invited: 2,
+ Inactive: 3,
+ };
+ const filteredFarms = filter
+ ? farms.filter(
+ (farm) =>
+ (farm.owner_name && farm.owner_name.toLowerCase().includes(filter)) ||
+ farm.farm_name.toLowerCase().includes(filter) ||
+ farm.address.toLowerCase().includes(filter) ||
+ farm.farm_id === currentFarmId,
+ )
+ : farms;
+
+ const sortedFarm = filteredFarms.sort((farm1, farm2) => {
+ if (farm1.status !== farm2.status) {
+ return farmOrderByStatus[farm1.status] - farmOrderByStatus[farm2.status];
+ } else if (farm1.farm_id !== currentFarmId && farm2.farm_id !== currentFarmId) {
+ return farm1.farm_name.localeCompare(farm2.farm_name);
+ } else {
+ return farm1.farm_id === currentFarmId ? -1 : 1;
+ }
+ });
+
+ return sortedFarm.map((farm) => {
+ const newFarm = {};
+ newFarm.farm_id = farm.farm_id;
+ newFarm.address = getAddress(farm, newFarm);
+ newFarm.farmName = farm.farm_name;
+ newFarm.ownerName = farm.owner_name;
+ newFarm.color = getColor(farm, selectedFarmId, currentFarmId);
+ return newFarm;
+ });
+};
+
+const getAddress = (farm, newFarm) => {
+ const { address } = farm;
+ const isCoordinate = /-?\d*\.\d*, -?\d*\.\d*/.test(address);
+ if (isCoordinate) {
+ return [farm.grid_points.lat.toFixed(5), farm.grid_points.lng.toFixed(5)];
+ } else {
+ newFarm.fullAddress = address?.replace(/(.*), .*/, '$1');
+ const addressArray = address?.split(', ');
+ return addressArray?.splice(0, addressArray.length - 1);
+ }
+};
+
+const getColor = (farm, selectedFarmId, currentFarmId) => {
+ if (farm.farm_id === currentFarmId || farm.status === 'Inactive') {
+ return 'disabled';
+ } else if (farm.farm_id === selectedFarmId) {
+ return farm.status === 'Invited' ? 'blueActive' : 'active';
+ } else if (farm.status === 'Invited') {
+ return 'blue';
+ } else return 'secondary';
+};
+
+export default ChooseFarm;
diff --git a/packages/webapp/src/containers/Consent/consent.test.js b/packages/webapp/src/containers/Consent/consent.test.js
deleted file mode 100644
index 58d36ab1ba..0000000000
--- a/packages/webapp/src/containers/Consent/consent.test.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-import { fireEvent, render, screen } from '../../tests/utils';
-import ConsentForm from './index';
-import '@testing-library/jest-dom';
-import { createStore } from 'redux';
-import { act } from '@testing-library/react';
-import { UPDATE_AGREEMENT } from '../constants';
-
-const baseReducer = {
- users: {},
- farm: { role_id: 1 },
-};
-
-describe('Consent Container', () => {
- it('should render properly given correct store', () => {
- render( , { initialState: { baseReducer } });
- expect(screen.getByText(/i agree/i)).toBeDefined();
- });
-
- it('should show disabled continue button at 1st render', () => {
- render( , { initialState: { baseReducer } });
- expect(screen.getByText(/continue/i)).toHaveAttribute('disabled');
- });
-
- it('should enable button upon selecting checkbox', () => {
- render( , { initialState: { baseReducer } });
- expect(screen.getByText(/continue/i)).toHaveAttribute('disabled');
- fireEvent.click(screen.getByRole('checkbox'));
- expect(screen.getByText(/continue/i)).not.toHaveAttribute('disabled');
- });
-
- it('should dispatch action when clicking continue', async () => {
- let store = createStore((state) => ({ ...state }), { baseReducer });
- store.dispatch = jest.fn();
- act(() => {
- render( , { store });
- });
- act(() => {
- fireEvent.click(screen.getByRole('checkbox'));
- });
- await act(() => {
- fireEvent.submit(screen.getByText(/continue/i));
- });
-
- expect(store.dispatch).toHaveBeenCalled();
- expect(store.dispatch).toHaveBeenCalledWith({
- type: UPDATE_AGREEMENT,
- consent_bool: { consent: true },
- consent_version: '3.0',
- });
- });
-});
diff --git a/packages/webapp/src/containers/Consent/index.js b/packages/webapp/src/containers/Consent/index.js
deleted file mode 100644
index 54786c4995..0000000000
--- a/packages/webapp/src/containers/Consent/index.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { useForm } from 'react-hook-form';
-import React, { useEffect, useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import PureConsent from '../../components/Consent';
-import { userFarmSelector } from '../userFarmSlice';
-import { patchConsent } from './saga';
-import { useTranslation } from 'react-i18next';
-import PropTypes from 'prop-types';
-import englishOwnerConsent from './locales/en/Owner.Consent.md';
-import englishWorkerConsent from './locales/en/Worker.Consent.md';
-import portugueseOwnerConsent from './locales/pt/Owner.Consent.md';
-import portugueseWorkerConsent from './locales/pt/Worker.Consent.md';
-import spanishOwnerConsent from './locales/es/Owner.Consent.md';
-import spanishWorkerConsent from './locales/es/Worker.Consent.md';
-import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
-
-const languageConsent = {
- en: { worker: englishWorkerConsent, owner: englishOwnerConsent },
- es: { worker: spanishWorkerConsent, owner: spanishOwnerConsent },
- pt: { worker: portugueseWorkerConsent, owner: portugueseOwnerConsent },
-};
-
-const getLanguageConsent = (language) => languageConsent[language] || languageConsent.en;
-
-function ConsentForm({
- goBackTo = '/role_selection',
- goForwardTo = '/certification/interested_in_organic',
- history,
-}) {
- const { t, i18n } = useTranslation();
- const language = getLanguageFromLocalStorage();
- const role = useSelector(userFarmSelector);
- const dispatch = useDispatch();
- const {
- register,
- handleSubmit,
- watch,
- setValue,
-
- formState: { errors },
- } = useForm();
- const [consentVersion] = useState('3.0');
- const [consent, setConsentText] = useState('');
- const checkboxName = 'consentCheckbox';
- const hasConsent = watch(checkboxName, false);
- const checkBoxRegister = register(checkboxName, {
- required: {
- value: true,
- message: 'You must accept terms and conditions to use the app',
- },
- });
- const goBack = () => {
- history.push(goBackTo);
- };
-
- const updateConsent = (data) => {
- dispatch(patchConsent({ has_consent: true, consent_version: consentVersion, goForwardTo }));
- };
-
- useEffect(() => {
- setValue(checkboxName, role.has_consent ?? false);
- const consent =
- role.role_id === 3 ? getLanguageConsent(language).worker : getLanguageConsent(language).owner;
- fetch(consent)
- .then((r) => r.text())
- .then((text) => {
- setConsentText(text);
- });
- }, []);
-
- return (
-
- );
-}
-
-export default ConsentForm;
-
-ConsentForm.prototype = {
- goBackTo: PropTypes.string,
- goForwardTo: PropTypes.string,
- history: PropTypes.object,
-};
diff --git a/packages/webapp/src/containers/Consent/index.jsx b/packages/webapp/src/containers/Consent/index.jsx
new file mode 100644
index 0000000000..dafd21ff36
--- /dev/null
+++ b/packages/webapp/src/containers/Consent/index.jsx
@@ -0,0 +1,85 @@
+import { useForm } from 'react-hook-form';
+import React, { useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import PureConsent from '../../components/Consent';
+import { userFarmSelector } from '../userFarmSlice';
+import { patchConsent } from './saga';
+import { useTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+import EnglishOwnerConsent from './locales/en/Owner.Consent.md';
+import EnglishWorkerConsent from './locales/en/Worker.Consent.md';
+import FrenchOwnerConsent from './locales/fr/Owner.Consent.md';
+import FrenchWorkerConsent from './locales/fr/Worker.Consent.md';
+import PortugueseOwnerConsent from './locales/pt/Owner.Consent.md';
+import PortugueseWorkerConsent from './locales/pt/Worker.Consent.md';
+import SpanishOwnerConsent from './locales/es/Owner.Consent.md';
+import SpanishWorkerConsent from './locales/es/Worker.Consent.md';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+
+const languageConsent = {
+ en: { worker: , owner: },
+ fr: { worker: , owner: },
+ es: { worker: , owner: },
+ pt: { worker: , owner: },
+};
+
+const getLanguageConsent = (language) => languageConsent[language] || languageConsent.en;
+
+function ConsentForm({
+ goBackTo = '/role_selection',
+ goForwardTo = '/certification/interested_in_organic',
+ history,
+}) {
+ const { t, i18n } = useTranslation();
+ const language = getLanguageFromLocalStorage();
+ const role = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+ const {
+ register,
+ handleSubmit,
+ watch,
+ setValue,
+
+ formState: { errors },
+ } = useForm();
+ const [consentVersion] = useState('4.0');
+ const consent =
+ role.role_id === 3 ? getLanguageConsent(language).worker : getLanguageConsent(language).owner;
+ const checkboxName = 'consentCheckbox';
+ const hasConsent = watch(checkboxName, false);
+ const checkBoxRegister = register(checkboxName, {
+ required: {
+ value: true,
+ message: 'You must accept terms and conditions to use the app',
+ },
+ });
+ const goBack = () => {
+ history.push(goBackTo);
+ };
+
+ const updateConsent = (data) => {
+ dispatch(patchConsent({ has_consent: true, consent_version: consentVersion, goForwardTo }));
+ };
+
+ return (
+
+ );
+}
+
+export default ConsentForm;
+
+ConsentForm.prototype = {
+ goBackTo: PropTypes.string,
+ goForwardTo: PropTypes.string,
+ history: PropTypes.object,
+};
diff --git a/packages/webapp/src/containers/Consent/locales/fr/Owner.Consent.md b/packages/webapp/src/containers/Consent/locales/fr/Owner.Consent.md
new file mode 100644
index 0000000000..e80d547949
--- /dev/null
+++ b/packages/webapp/src/containers/Consent/locales/fr/Owner.Consent.md
@@ -0,0 +1,317 @@
+##### Version 4.0:
+
+
+
+#### Formulaire de consentement éclairé et politique de confidentialité (version pour ouvrières et ouvriers)
+
+
+
+Bienvenue à LiteFarm !
+Nous comprenons que la confidentialité et la protection de vos données sont importantes. Nous avons créé ce formulaire de consentement éclairé et cette politique de confidentialité pour vous aider à comprendre comment et quand nous collectons, utilisons, et partageons vos données et pour d'assurer que nous avons votre consentement pour le faire. Votre compréhension est essentielle pour le consentement.
+Veuillez garder à l'esprit que vous devrez consentir aux protocoles décrits dans ce formulaire de consentement éclairé et cette politique de confidentialité pour chaque ferme à laquelle vous êtes associé avec par un compte sur l’application LiteFarm. Sans votre consentement vous ne pourrez pas utiliser l’application LiteFarm.
+
+
+
+#### C’est quoi l’application LiteFarm?
+
+
+
+L’application LiteFarm est le produit d’un projet de science participative développé pour améliorer l'accès à la technologie agricole numérique pour les communautés agricoles. L’application LiteFarm vise à aider les agriculteurs à gérer leurs fermes de manière plus rentable et plus durables du point de vue écologique et social.
+
+Le code source de l'application LiteFarm est gratuit et « open source » (GPLv3) afin que les chercheurs, experts, et développeurs à l'échelle mondiale peut contribuer à améliorer les services offerts à la communauté agricole. LiteFarm est une entité non commerciale. Notre objectif est de servir la communauté agricole en améliorant les connaissances et les outils pour la gestion des fermes et la recherche à propos du système alimentaire.
+
+
+
+#### Qui fait partie de l'équipe LiteFarm?
+
+
+
+L'équipe LiteFarm est un groupe interdisciplinaire de scientifiques, de chercheurs, d'agriculteurs, de concepteurs et de professionnels en informatique de logiciels. L'équipe a été initialement formée à l'Université de la Colombie-Britannique [University of British Columbia] (UBC) et s'est développée pour inclure un réseau mondial participatif d'individus et d'organisations. Les chercheurs principaux sont Dr. Zia Mehrabi (University of Colorado) and Dr. Hannah Wittman (UBC, hannah.wittman@ubc.ca).
+
+
+
+#### Qui finance LiteFarm ?
+
+
+
+LiteFarm est financé par le Centre pour les systèmes alimentaires durable [Center for Sustainable Food Systems] à UBC et d'autres subventions. Pour une liste complète, veuillez visiter : https://www.litefarm.org/partners.
+
+Nos bailleurs de fonds n'ont pas leur mot à dire dans le fonctionnement et la gestion de LiteFarm et ne peuvent accéder à aucune des informations personnelles hébergées sur la plateforme. Présentement, les donateurs et bourses de recherche fournissent le financement pour le logiciel et l'équipe LiteFarm.
+
+
+
+#### Pourquoi menons-nous ce projet ?
+
+
+
+Nous reconnaissons les lacunes dans l'accès des agriculteurs aux services de technologie numérique, les faibles taux d'adoption et le besoin exprimé par les agriculteurs de combiner une gamme de services de conseil dans une seule plateforme non commerciale. Nous voulons développer une solution qui aide à la fois les agriculteurs à exploiter leur entreprise de manière plus durable sur le plan financier et écologique, et contribuer également à faire progresser la science de la durabilité pour les systèmes alimentaires.
+
+
+
+#### Quelles données collectons-nous ?
+
+
+
+Selon les parties de l’application LiteFarm que vous utilisez, nous pouvons collecter différents types d'informations :
+
+
+
+
+**Informations personnelles**
+
+
+
+
+« Informations personnelles » décrit toute information qui peut être utilisée pour vous identifier ou identifier vos employés. LiteFarm ne divulgue jamais d'informations personnelles à des tiers parties sans votre consentement.
+
+Ceci comprend :
+
+- Les coordonnées (nom, adresse, numéro de téléphone, adresse courriel)
+
+- Les informations démographiques (sexe, année de naissance, préférence linguistique, pays, devise)
+
+- Les informations sur l'entreprise (nom de la ferme, adresse de la ferme, coordonnées de la ferme)
+
+- Les photos
+
+- L’adresse de protocole Internet (IP)
+
+- Les informations sur le travailleur (nom, rôle dans la ferme, adresse e-mail)
+
+- La géolocalisation (par exemple, coordonnées GPS des emplacements des fermes, limites des emplacements, etc.)
+
+
+
+
+
+**Informations sur la gestion de la ferme:**
+
+
+
+
+LiteFarm utilise les informations de gestion que vous entrez dans l'application pour générer des informations sur les avantages ou les impacts financiers, environnementaux et sociaux de vos décisions de gestion. Nous avons rendu ces données anonymes pour mener des recherches universitaires non commerciales sur les systèmes alimentaires durables. Car ces données sont anonymisées lorsqu'elles sont utilisées dans nos recherches, elles ne peuvent pas être retracées jusqu'à vous ou votre ferme.
+
+Ces données comprennent:
+
+- Les informations sur l'emplacement de la ferme : différents types de données à propos de la ferme, y compris la taille ; des noms; les endroits de cultures plantées; statut biologique; et d'autres attributs spécifiques au type d'emplacement;
+
+- Les informations sur les cultures : type de culture, variété, fournisseur, noms communs, espèces, genre, groupe de cultures, statut de certification biologique et informations complémentaires;
+
+- Les informations sur la gestion des cultures : y compris les dates de début et de fin de la culture; méthode de plantation ; méthode de repiquage ; âge de la culture ; tâches associées au plan; prix estimé des cultures ; rendement estimé des cultures, etc.;
+
+- Les informations sur les tâches effectuées sur la ferme : cessionnaire, créateur, durée, emplacement(s), culture(s) impactée(s), intrants, notes, dates, état d'achèvement, etc.;
+
+- Les informations sur la lutte antiparasitaire : nom du produit ; quantité de produit appliqué ; cible de l'application (c'est-à-dire, le nom de l'organisme nuisible ou de la maladie), nom commun, nom scientifique, groupe; nom de l'ingrédient actif ; concentration en ingrédient actif; intervalle de récolte; intervalle d'entrée ; type de contrôle; emplacement(s) et culture(s) ciblé(s);
+
+- Les informations sur la récolte : champ récolté ; culture récoltée; quantité récoltée, utilisations des récoltes;
+
+- Les informations sur l’ensemencement : emplacement(s) classé(s) ; culture(s) ensemencée(s); profondeur, longueur, largeur et taux d'espacement;
+
+- Les informations sur le travail sur le terrain : emplacement(s), culture(s) ; type de travail, notes;
+
+- Les informations sur l'analyse du sol : emplacement ; profondeur ; texture ; pourcentage de potassium, phosphore, azote, matière organique, carbone organique, carbone inorganique, carbone total, soufre, calcium, magnésium, sodium, zinc, manganèse, fer, cuivre, bore ; capacité d'échange cationique (CEC); pH; densité apparente;
+
+- Les informations sur l'irrigation : emplacement(s), culture(s) ; type d'irrigation, débit ; temps total qui s'écoule;
+
+- Les informations sur le scoutisme : lieu(x) ; récolte (s ); type ; action nécessaire (oui/non);
+
+- Autres informations : lieu(x) ; récolte(s); remarques;
+
+- Les informations relatives à l'achèvement des tâches: date ; durée du travail; humeur (heureuse, très heureuse, triste, très triste, neutre); notes sur le travail;
+
+- Les informations sur les dépenses : date ; type ; nom; montant des dépenses;
+
+- Les informations sur les ventes : date ; nom de l'acheteur/du marché ; culture ; quantité vendue (kg) ; revenu;
+
+- Les détails sur les travailleurs : nombre de travailleurs enregistrés ; salaire horaire ; adresse courriel, rôle, nom, etc.;
+
+- Les détails spécifiques à la ferme : unités préférées (par exemple, métrique ou impériale) ; devise; si la ferme cherche à obtenir une certification ; certificateur ; attributs de lit ; attributs de rangées.
+
+**Données d'utilisation**
+
+
+
+
+Nous recueillons des données d'utilisation (c'est-à-dire des statistiques générales sur les utilisateurs, les modèles de trafic et la façon dont les utilisateurs réagissent aux diverses fonctionnalités du site) pour améliorer la qualité des services que nous vous fournissons. Ce type de données comprend : le temps de la journée où vous vous connectez à l’application LiteFarm, les pages que vous demandez, la durée de votre visite sur le site, la façon dont vous interagissez avec l'application et les détails techniques concernant votre appareil (par exemple, le navigateur, le type d'écran et le processeur).
+
+Ces données seront soit associées à votre nom d'utilisateur avec LiteFarm (si vous êtes connecté à l'application) ou à votre adresse IP (si vous n'êtes pas connecté). Nous pouvons utiliser des logiciels tels que Google Analytics pour collecter ces données, mais dans ces cas, toutes les informations personnelles seront anonymisées.
+
+
+
+
+
+**Comment utilisons-nous les données?**
+
+
+
+Nous utilisons vos données de trois manières principales :
+
+- Pour améliorer les services que nous vous fournissons : comme décrit ci-dessus, nous utilisons vos données d'utilisation (c'est-à-dire des informations générales sur la façon dont vous interagissez avec la plate-forme LiteFarm) pour améliorer la plateforme LiteFarm et les services qu'elle fournit.
+
+- Pour générer des informations sur les avantages ou les impacts financiers, environnementaux et sociaux de vos décisions de gestion : l’application LiteFarm utilise les données de gestion que vous saisissez dans l'application (voir la section «Informations sur la gestion de la ferme » ci-dessus pour une liste complète), ainsi que les données de gestion intégrées dans les algorithmes et certaines données publiques (par exemple, les informations sur les stations météorologiques locales, les coefficients de culture, la teneur en éléments nutritifs des cultures et des engrais, les données d'occurrence des espèces et les données topographiques) pour générer des informations sur les avantages/impacts financiers, environnementaux et sociaux de vos décisions de gestion.
+
+- Pour mener des recherches universitaires non commerciales sur les systèmes alimentaires durables : avec nos collaborateurs universitaires, nous utiliserons vos données anonymisées de gestion agricole (voir la section « Informations sur la gestion de la ferme » ci-dessus pour une liste complète) pour mener des recherches académiques sur les systèmes agronomiques, écologiques et alimentaires. Certaines de ces recherches seront menées par des doctorants dans le cadre de leurs exigences de diplôme. Nous évaluerons rigoureusement chaque proposition de projet pour nous assurer que vos données sont utilisées efficacement pour faire progresser les connaissances sur les systèmes alimentaires durables, aider les agriculteurs à prendre des décisions de gestion durable et avoir un impact sur les politiques publiques au profit des agriculteurs. Nous vous tiendrons au courant des projets de recherche par courriel (sauf si vous préférez vous désinscrire), et vous pouvez toujours nous contacter pour en savoir plus sur la recherche que vos données contribuent à rendre possible.
+
+**Que partageons-nous?**
+
+
+
+
+Nous ne partagerons vos données avec des tierces personnes que si elles sont à la fois anonymisées (c'est-à-dire qu'elles ne contiennent aucune information personnelle) et nécessaires pour atteindre nos objectifs de recherche ou valider des découvertes scientifiques. Plus précisément, nous pouvons partager des données anonymisées à un moment donné à l'avenir avec d'autres chercheurs à des fins de recherche universitaire non commerciale. Tout chercheur universitaire externe qui demande l'utilisation des données de LiteFarm sera soumis à un examen interne et sera évalué selon nos normes d'éthique et de sécurité existantes. En raison des normes de publication en matière de reproductibilité scientifique, les données anonymisées utilisées pour la recherche universitaire peuvent être déposées dans des référentiels publics.
+
+Des copies de diffusions non publiques de données anonymisées peuvent être partagées avec des chercheurs universitaires à des fins de recherche non commerciales, dans le cadre de licences à usage unique confidentielles et limitées dans le temps. Si une utilisation de recherche universitaire inclut l'utilisation de photos téléchargées sur LiteFarm, toutes les caractéristiques identifiables qui divulguent des informations personnelles (par exemple, les visages des personnes) seront estompées des photos avant qu'elles ne soient partagées. Nous ne partageons aucune information personnelle avec des services d'analyse tiers, tels que Google Analytics. Grâce à nos protocoles de sécurité, nous protégeons la vulnérabilité des informations personnelles sur le site web LiteFarm et nous utilisons des protocoles d'anonymisation IP pour empêcher l'identification et la géolocalisation par des tierces parties.
+
+LiteFarm ne louera ni ne vendra vos informations personnelles ou toute donnée collectée via le site web de LiteFarm à qui que ce soit sans votre consentement.
+
+
+
+
+
+**Comment nous utilisons les « cookies »?**
+
+
+
+
+Dans certaines sections de notre site, un cookie peut être placé sur votre ordinateur ou appareil. Un cookie est un petit fichier qui réside sur le disque dur de votre ordinateur ou de votre appareil et qui nous permet d'améliorer la qualité de votre visite sur nos sites web. Nous utilisons des cookies pour identifier les pages qui sont utilisées et pour améliorer notre site web. Nous n'utilisons ces informations qu'à des fins d'analyses statistiques. Elles ne sont pas partagées avec d'autres sites et ne sont pas utilisées à des fins publicitaires. Vous pouvez choisir d'accepter ou de refuser les cookies.
+
+La plupart des navigateurs web acceptent automatiquement les cookies, mais vous pouvez généralement modifier les paramètres de votre navigateur pour refuser les cookies si vous le préférez. Cependant, si vous choisissez de refuser les cookies de LiteFarm, la fonctionnalité, y compris votre capacité à vous connecter et à utiliser l'application, peut être altérée. L'acceptation des cookies est implicite si vous continuez à accéder à notre site web sans ajuster les paramètres de votre navigateur.
+
+
+
+
+
+**Où stockons-nous vos données?**
+
+
+
+
+Notre application est hébergée sur Digital Ocean pour servir rapidement et de manière fiable notre site web à un nombre imprévisible de personnes. Cela signifie que vos données seront potentiellement stockées dans plusieurs centres de données et emplacements au Canada et aux États-Unis d'Amérique.
+
+Bien que notre application ne soit pas commerciale, nous notons que Digital Ocean participe au programme « Privacy Shield » développé par le Département du commerce des États-Unis et l'Union Européenne (UE) et offre des services de conformité au Règlement général sur la protection des données (RGPD) de l'UE.
+
+En plus de notre stockage en nuage, une copie locale de la base de données LiteFarm est hébergée sur un serveur crypté et protégé par mot de passe à l'Université de la Colombie-Britannique (UBC). Des copies anonymisées de la base de données LiteFarm peuvent être stockées sur des référentiels publics conformément aux normes de publication pour la reproductibilité scientifique.
+
+
+
+
+**Comment protégeons-nous vos données?**
+
+
+
+
+Nous suivons les meilleures pratiques de l'industrie pour sécuriser les données des utilisateurs, et nous avons construit et continuons à maintenir notre application conformément à la norme de vérification de la sécurité des applications annotées de niveau 2 du projet Open Web Application Security.
+
+L'accès à la base de données est limité aux membres de l'équipe LiteFarm qui ont suivi une formation en éthique (Énoncé de politique des trois Conseils : Éthique de la recherche avec des êtres humains, EPTC2) et ont signé des ententes de confidentialité. Cependant, nous ne pouvons pas garantir que les données transmises sur Internet seront toujours sécurisées. Malgré le fait que nous nous efforçons de protéger vos informations personnelles, l’utilisation des applications et des données infonuagiques présente toujours une certaine mesure de risque de piratage.
+
+
+
+
+**Quels autres risques sont liés à l'utilisation de LiteFarm?**
+
+
+
+
+Nous avons fait tous les efforts raisonnables pour nous assurer que notre application est sécurisée et fournit des informations aussi précises que possible pour vous aider à gérer votre ferme. Cependant, nous reconnaissons que l'utilisation de l’application LiteFarm comporte des risques pour vous et votre ferme lors de l’entrée des données et peut résulter en erreurs ou inexactitudes du contenu. Les risques associés peuvent contribuer à la perte potentielle de production, de revenus ou de bénéfices, l'interruption ou le retard des services, la perte, les dommages, la corruption ou la récupération de données, ou la violation de la sécurité des données ou du système, qui peuvent résulter de l'utilisation de l’application LiteFarm.
+
+Nous déclinons toute responsabilité légale pour ces risques. Si vous avez des inquiétudes et que vous n'êtes pas en mesure de consentir à la possibilité que cela se produise, veuillez ne pas signer le formulaire de consentement à la fin de cette page ou ne vous inscrivez pas à ce produit. Dans les cas de risques imminents connus (tels que des dates connues de perte de services), nous ferons tout notre possible pour vous avertir en tant qu'utilisateur afin que vous puissiez prendre les précautions nécessaires pour atténuer le risque (par exemple, pour sauvegarder vos données).
+
+
+
+
+
+**Combien de temps conservons-nous vos données?**
+
+
+
+
+Nous visons à conserver vos données indéfiniment dans un souci de reproductibilité scientifique, mais pour un minimum de 5 ans.
+
+
+
+
+**Quels sont vos droits concernant vos informations personnelles?**
+
+
+
+
+Vous avez le droit de savoir quelles données nous avons à propos de vous, d'en demander une copie, de mettre à jour et de corriger vos données, de demander que nous arrêtions de collecter vos données, de demander un transfert de vos données ou de poser des questions sur toute analyse utilisant vos données. Pour toute information ou demande de ce type, contactez data@litefarm.org.
+
+Votre utilisation de LiteFarm est entièrement volontaire. Si vous décidez d'utiliser LiteFarm, vous pouvez choisir de désactiver votre compte à tout moment sans donner de raison et sans autre action de la part du chercheur. Si vous souhaitez supprimer toutes vos données de la base de données LiteFarm, vous pouvez le faire en envoyant un courriel à data@litefarm.org avec votre demande.
+
+
+
+
+**Que se passe-t-il si vous retirez votre consentement?**
+
+
+
+Si vous retirez votre consentement en envoyant un courriel à data@litefarm.org, votre ou vos comptes sur l’application LiteFarm seront marqués comme inactifs et vous ne pourrez pas utiliser l’application LiteFarm. Cependant, vos informations ne seront pas supprimées dans le cas où vous souhaiteriez revenir plus tard. Vous pouvez demander que vos données soient définitivement et irrévocablement supprimées en envoyant une demande à data@litefarm.org. Si vous envisagez de retirer votre consentement et souhaitez obtenir une copie de vos données, veuillez en faire la demande lorsque vous retirez votre consentement.
+
+
+
+
+**Comment apportons-nous des modifications à la politique de confidentialité?**
+
+
+
+
+Bien que la plupart des changements soient probablement mineurs, LiteFarm peut occasionnellement modifier sa politique de confidentialité. Nous publierons une version mise à jour et révisée de la politique de confidentialité sur le site web de LiteFarm (www.litefarm.org) et vous informerons via l'application lorsque nous apporterons des modifications.
+
+Vous devrez accepter le nouveau formulaire de consentement pour continuer à utiliser l’application. Si vous n'acceptez pas les modifications, vous pourrez télécharger vos données, mais vous ne pourrez pas saisir de nouvelles données dans l'application. Les révisions entrent en vigueur dès leur publication. Votre utilisation continue de ce site après toute modification de cette politique de confidentialité constitue votre acceptation de cette modification.
+
+
+
+
+**Quand allons-nous vous contacter?**
+
+
+
+
+Si vous créez un compte LiteFarm, nous enverrons occasionnellement des courriels pour annoncer de nouvelles fonctionnalités dans LiteFarm, pour expliquer toute modification apportée à l'application, vous inviter à des événements spéciaux ou vous informer des projets de recherche que les données de LiteFarm contribuent à rendre possibles. Nous pouvons également vous envoyer occasionnellement des courriels pour vous demander votre avis sur l’application ou le site web. Votre participation à une telle demande est entièrement volontaire et n'affectera pas votre utilisation de la plateforme.
+
+
+
+
+**Licence**
+
+
+
+
+Présentement, l'application LiteFarm est gratuite. Le logiciel lui-même est sous licence GNU Public License v3, qui est une licence gratuite et open-source (https://www.gnu.org/licenses/quick-guide-gplv3.en.html).
+
+
+
+
+**Pour plus d'informations**
+Concernant de la plateforme, merci de contacter :
+
+- Chef de produit: Kevin Cussen (kcussen@litefarm.org)
+
+Concernant la recherche universitaire, merci de contacter :
+
+- Chercheure principale: Dr. Hannah Wittman (hannah.wittman@ubc.ca)
+
+
+
+
+**Si vous avez des préoccupations ou des plaintes concernant vos droits en tant que participant à la recherche et/ou vos expériences lors de votre participation à cette étude:**
+
+
+
+
+Communiquez avec la ligne de plainte des participants à la recherche du Bureau d'éthique de la recherche de UBC au 604-822-8598 ou, en cas d'interurbain, envoyez un courriel à RSIL@ors.ubc.ca ou appelez sans frais le 1-877-822-8598.
+
+
+
+
+**Consentement**
+
+
+
+
+En appuyant sur « Accepter » ci-dessous, cela indique que vous avez téléchargé une copie de ce formulaire de consentement et de la politique de confidentialité pour vos propres dossiers et que vous consentez à participer à cette étude.
+
+Éthique de l'étude à UBC - Identification de l’étude: H19-01482
+
+
+
diff --git a/packages/webapp/src/containers/Consent/locales/fr/Worker.Consent.md b/packages/webapp/src/containers/Consent/locales/fr/Worker.Consent.md
new file mode 100644
index 0000000000..782787f6a8
--- /dev/null
+++ b/packages/webapp/src/containers/Consent/locales/fr/Worker.Consent.md
@@ -0,0 +1,285 @@
+##### Version 4.0:
+
+
+
+#### Formulaire de consentement éclairé et politique de confidentialité (version pour ouvrières et ouvriers)
+
+
+
+Bienvenue à LiteFarm !
+Nous comprenons que la confidentialité et la protection de vos données sont importantes. Nous avons créé ce formulaire de consentement éclairé et cette politique de confidentialité pour vous aider à comprendre comment et quand nous collectons, utilisons, et partageons vos données et pour d'assurer que nous avons votre consentement pour le faire. Votre compréhension est essentielle pour le consentement.
+
+Veuillez garder à l'esprit que vous devrez consentir aux protocoles décrits dans ce formulaire de consentement éclairé et cette politique de confidentialité pour chaque ferme à laquelle vous êtes associé avec un compte sur l’application LiteFarm. Sans votre consentement vous ne pourrez pas utiliser l’application LiteFarm.
+
+
+
+#### C’est quoi l’application LiteFarm?
+
+
+
+L’application LiteFarm est le produit d’un projet de science participative développé pour améliorer l'accès à la technologie agricole numérique pour les communautés agricoles. L’application LiteFarm vise à aider les agriculteurs à gérer leurs fermes de manière plus rentable et plus durables du point de vue écologique et social.
+
+Le code source pour LiteFarm est gratuit et « open source » (GPLv3) afin que les chercheurs, experts, et développeurs à l'échelle mondiale peut contribuer à améliorer les services offerts à la communauté agricole. LiteFarm est une entité non commerciale. Notre objectif est de servir la communauté agricole en améliorant les connaissances et les outils pour la gestion des fermes et la recherche à propos du système alimentaire.
+
+
+
+#### Qui fait partie de l'équipe LiteFarm?
+
+
+
+L'équipe LiteFarm est un groupe interdisciplinaire de scientifiques, de chercheurs, d'agriculteurs, de concepteurs et de professionnels en informatique de logiciels. L'équipe a été initialement formée à l'Université de la Colombie-Britannique [University of British Columbia] (UBC) et s'est développée pour inclure un réseau mondial participatif d'individus et d'organisations. Les chercheurs principaux sont Dr. Zia Mehrabi (University of Colorado) and Dr. Hannah Wittman (UBC, hannah.wittman@ubc.ca).
+
+
+
+#### Qui finance LiteFarm ?
+
+
+LiteFarm est financé par le Centre pour les systèmes alimentaires durable [Center for Sustainable Food Systems] à UBC et d'autres subventions. Pour une liste complète, veuillez visiter : https://www.litefarm.org/partners.
+Nos bailleurs de fonds n'ont pas leur mot à dire dans le fonctionnement et la gestion de LiteFarm et ne peuvent accéder à aucune des informations personnelles hébergées sur la plateforme. Présentement, les donateurs et bourses de recherche fournissent le financement pour le logiciel et l'équipe LiteFarm.
+
+
+
+#### Pourquoi menons-nous ce projet ?
+
+
+
+Nous reconnaissons les lacunes dans l'accès des agriculteurs aux services de technologie numérique, les faibles taux d'adoption et le besoin exprimé par les agriculteurs de combiner une gamme de services de conseil dans une seule plateforme non commerciale. Nous voulons développer une solution qui aide à la fois les agriculteurs à exploiter leur entreprise de manière plus durable sur le plan financier et écologique, et contribuer également à faire progresser la science de la durabilité pour les systèmes alimentaires.
+
+
+
+#### Quelles données collectons-nous ?
+
+
+
+Selon les parties de l’application LiteFarm que vous utilisez, nous pouvons collecter différents types d'informations :
+
+
+
+
+**Informations personnelles**
+
+
+
+
+« Informations personnelles » décrit toute information pouvant être utilisée pour vous identifier ou identifier vos employés. LiteFarm ne divulgue jamais d'informations personnelles à des tiers parties sans votre consentement.
+Ceci comprend :
+
+- Les coordonnées (nom, adresse, numéro de téléphone, adresse courriel)
+
+- Les informations démographiques (sexe, année de naissance, préférence linguistique, pays, devise)
+
+- Les informations sur l'entreprise (nom de la ferme, adresse de la ferme, coordonnées de la ferme)
+
+- Les photos
+
+- L’adresse de protocole Internet (IP)
+
+- La géolocalisation (par exemple, coordonnées GPS des emplacements des fermes, limites des emplacements, etc.)
+
+
+
+
+
+**Informations sur la gestion de la ferme:**
+
+
+
+
+LiteFarm utilise les informations de gestion que vous entrez dans l'application pour générer des informations sur les avantages ou les impacts financiers, environnementaux et sociaux de vos décisions de gestion. Nous avons rendu ces données anonymes pour mener des recherches universitaires non commerciales sur les systèmes alimentaires durables. Car ces données sont anonymisées lorsqu'elles sont utilisées dans nos recherches, elles ne peuvent pas être retracées jusqu'à vous ou votre ferme.
+Ces données comprennent:
+
+- Les informations sur les tâches que vous avez performé à votre poste : la duration, les dates, l’endroit, les cultures affectées, les pratiques agricoles, l'état d'achèvement, etc.
+
+- Les informations sur la lutte antiparasitaire : nom du produit ; quantité de produit appliqué ; cible de l'application (c'est-à-dire, le nom de l'organisme nuisible ou de la maladie), nom commun, nom scientifique, groupe; nom de l'ingrédient actif ; concentration en ingrédient actif; intervalle de récolte; intervalle d'entrée ; type de contrôle; emplacement(s) et culture(s) ciblé(s);
+
+- Les informations sur la récolte : champ récolté ; culture récoltée; quantité récoltée, utilisations des récoltes;
+
+- Les informations sur l’ensemencement : emplacement(s) classé(s) ; culture(s) ensemencée(s); profondeur, longueur, largeur et taux d'espacement;
+
+- Les informations sur le travail sur le terrain : emplacement(s), culture(s) ; type de travail, notes;
+
+- Les informations sur l'analyse du sol : emplacement ; profondeur ; texture ; pourcentage de potassium, phosphore, azote, matière organique, carbone organique, carbone inorganique, carbone total, soufre, calcium, magnésium, sodium, zinc, manganèse, fer, cuivre, bore ; capacité d'échange cationique (CEC); pH; densité apparente;
+
+- Les informations sur l'irrigation : emplacement(s), culture(s) ; type d'irrigation, débit ; temps total qui s'écoule;
+
+- Les informations sur le scoutisme : lieu(x) ; récolte (s ); type ; action nécessaire (oui/non);
+ Autres informations : lieu(x) ; récolte(s); remarques;
+
+- Les informations relatives à l'achèvement des tâches: date ; durée du travail; humeur (heureuse, très heureuse, triste, très triste, neutre); notes sur le travail
+
+**Données d'utilisation**
+
+
+
+
+Nous recueillons des données d'utilisation (c'est-à-dire des statistiques générales sur les utilisateurs, les modèles de trafic et la façon dont les utilisateurs réagissent aux diverses fonctionnalités du site) pour améliorer la qualité des services que nous vous fournissons. Ce type de données comprend : le temps de la journée où vous vous connectez à l’application LiteFarm, les pages que vous demandez, la durée de votre visite sur le site, la façon dont vous interagissez avec l'application et les détails techniques concernant votre appareil (par exemple, le navigateur, le type d'écran et le processeur).
+Ces données seront soit associées à votre nom d'utilisateur avec LiteFarm (si vous êtes connecté à l'application) ou à votre adresse IP (si vous n'êtes pas connecté). Nous pouvons utiliser des logiciels tels que Google Analytics pour collecter ces données, mais dans ces cas, toutes les informations personnelles seront anonymisées.
+
+
+
+
+**Comment utilisons-nous les données?**
+
+
+
+Nous utilisons vos données d'utilisation (c'est-à-dire des informations générales sur la façon dont vous interagissez avec LiteFarm) pour améliorer l’application LiteFarm et les services qu'elle fournit.
+Les informations que vous fournissez sur l'achèvement des tâches sont affichées sous forme agrégée (sans aucune information personnellement identifiable) aux gestionnaires de ferme et à des fins de recherche.
+
+**Que partageons-nous?**
+
+
+
+
+Nous ne partagerons vos données avec des tierces personnes que si elles sont à la fois anonymisées (c'est-à-dire qu'elles ne contiennent aucune information personnelle) et nécessaires pour atteindre nos objectifs de recherche ou valider des découvertes scientifiques. Plus précisément, nous pouvons partager des données anonymisées à un moment donné dans le futur avec d'autres chercheurs à des fins de recherche universitaire non commerciale. Tout chercheur universitaire externe qui demande l'utilisation des données de LiteFarm sera soumis à un examen interne et sera évalué selon nos normes d'éthique et de sécurité existantes. En raison des normes de publication en matière de reproductibilité scientifique, les données anonymisées utilisées pour la recherche universitaire peuvent être déposées dans des référentiels publics.
+
+Des copies de diffusions non publiques de données anonymisées peuvent être partagées avec des chercheurs universitaires à des fins de recherche non commerciales, dans le cadre de licences à usage unique confidentielles et limitées dans le temps. Si une utilisation de recherche universitaire inclut l'utilisation de photos téléchargées sur LiteFarm, toutes les caractéristiques identifiables qui divulguent des informations personnelles (par exemple, les visages des personnes) seront estompées des photos avant qu'elles ne soient partagées. Nous ne partageons aucune information personnelle avec des services d'analyse tiers, tels que Google Analytics. Grâce à nos protocoles de sécurité, nous protégeons la vulnérabilité des informations personnelles sur le site web LiteFarm et nous utilisons des protocoles d'anonymisation IP pour empêcher l'identification et la géolocalisation par des tierces parties.
+
+LiteFarm ne louera ni ne vendra vos informations personnelles ou toute donnée collectée via le site web de LiteFarm à qui que ce soit sans votre consentement.
+
+
+
+
+**Comment nous utilisons les « cookies »?**
+
+
+
+
+Dans certaines sections de notre site, un cookie peut être placé sur votre ordinateur ou appareil. Un cookie est un petit fichier qui réside sur le disque dur de votre ordinateur ou de votre appareil et qui nous permet d'améliorer la qualité de votre visite sur nos sites web. Nous utilisons des cookies pour identifier les pages qui sont utilisées et pour améliorer notre site web. Nous n'utilisons ces informations qu'à des fins d'analyses statistiques. Elles ne sont pas partagées avec d'autres sites et ne sont pas utilisées à des fins publicitaires. Vous pouvez choisir d'accepter ou de refuser les cookies.
+
+La plupart des navigateurs web acceptent automatiquement les cookies, mais vous pouvez généralement modifier les paramètres de votre navigateur pour refuser les cookies si vous le préférez. Cependant, si vous choisissez de refuser les cookies de LiteFarm, la fonctionnalité, y compris votre capacité à vous connecter et à utiliser l'application, peut être altérée. L'acceptation des cookies est implicite si vous continuez à accéder à notre site web sans ajuster les paramètres de votre navigateur.
+
+
+
+
+**Où stockons-nous vos données?**
+
+
+
+
+Notre application est hébergée sur Digital Ocean pour servir rapidement et de manière fiable notre site web à un nombre imprévisible de personnes. Cela signifie que vos données seront potentiellement stockées dans plusieurs centres de données et emplacements au Canada et aux États-Unis d'Amérique.
+
+Bien que notre application ne soit pas commerciale, nous notons que Digital Ocean participe au programme « Privacy Shield » développé par le Département du commerce des États-Unis et l'Union Européenne (UE) et offre des services de conformité au Règlement général sur la protection des données (RGPD) de l'UE.
+
+En plus de notre stockage en nuage, une copie locale de la base de données LiteFarm est hébergée sur un serveur crypté et protégé par mot de passe à l'Université de la Colombie-Britannique (UBC). Des copies anonymisées de la base de données LiteFarm peuvent être stockées sur des référentiels publics conformément aux normes de publication pour la reproductibilité scientifique.
+
+
+
+
+**Comment protégeons-nous vos données?**
+
+
+
+
+Nous suivons les meilleures pratiques de l'industrie pour sécuriser les données des utilisateurs, et nous avons construit et continuons à maintenir notre application conformément à la norme de vérification de la sécurité des applications annotées de niveau 2 du projet Open Web Application Security.
+
+L'accès à la base de données est limité aux membres de l'équipe LiteFarm qui ont suivi une formation en éthique (Énoncé de politique des trois Conseils : Éthique de la recherche avec des êtres humains, EPTC2) et ont signé des ententes de confidentialité. Cependant, nous ne pouvons pas garantir que les données transmises sur Internet seront toujours sécurisées. Malgré le fait que nous nous efforçons de protéger vos informations personnelles, l’utilisation des applications et des données infonuagiques présente toujours une certaine mesure de risque de piratage.
+
+
+
+
+**Quels autres risques sont liés à l'utilisation de LiteFarm?**
+
+
+
+
+Bien que nous ayons déployé tous les efforts raisonnables pour garantir la sécurité de notre application, nous reconnaissons que votre utilisation de LiteFarm comporte certains risques pour la confidentialité de vos informations personnelles (telles que définies ci-dessus). Nous déclinons toute responsabilité légale pour ces risques. Si vous avez des inquiétudes et que vous n'êtes pas en mesure de consentir à la possibilité que cela se produise, veuillez ne pas signer le formulaire de consentement à la fin de cette page ou ne vous inscrivez pas à ce produit.
+
+
+
+
+**Combien de temps conservons-nous vos données?**
+
+
+
+
+Nous visons à conserver vos données indéfiniment dans un souci de reproductibilité scientifique, mais pour un minimum de 5 ans.
+
+
+
+
+**Quels sont vos droits concernant vos informations personnelles?**
+
+
+
+
+Vous avez le droit de savoir quelles données nous avons à propos de vous, d'en demander une copie, de mettre à jour et de corriger vos données, de demander que nous arrêtions de collecter vos données, de demander un transfert de vos données ou de poser des questions sur toute analyse utilisant vos données. Pour toute information ou demande de ce type, contactez data@litefarm.org.
+
+Votre utilisation de LiteFarm est entièrement volontaire. Si vous décidez d'utiliser LiteFarm, vous pouvez choisir de désactiver votre compte à tout moment sans donner de raison et sans autre action de la part du chercheur. Si vous souhaitez supprimer toutes vos données de la base de données LiteFarm, vous pouvez le faire en envoyant un courriel à data@litefarm.org avec votre demande.
+
+
+
+
+**Que se passe-t-il si vous retirez votre consentement?**
+
+
+
+Si vous retirez votre consentement en envoyant un courriel à data@litefarm.org, votre ou vos comptes sur l’application LiteFarm seront marqués comme inactifs et vous ne pourrez pas utiliser l’application LiteFarm. Cependant, vos informations ne seront pas supprimées dans le cas où vous souhaiteriez revenir plus tard. Vous pouvez demander que vos données soient définitivement et irrévocablement supprimées en envoyant une demande à data@litefarm.org. Si vous envisagez de retirer votre consentement et souhaitez obtenir une copie de vos données, veuillez en faire la demande lorsque vous retirez votre consentement.
+
+
+
+
+**Comment apportons-nous des modifications à la politique de confidentialité?**
+
+
+
+
+Bien que la plupart des changements soient probablement mineurs, LiteFarm peut occasionnellement modifier sa politique de confidentialité. Nous publierons une version mise à jour et révisée de la politique de confidentialité sur le site web de LiteFarm (www.litefarm.org) et vous informerons via l'application lorsque nous apporterons des modifications.
+
+Vous devrez accepter le nouveau formulaire de consentement pour continuer à utiliser l’application. Si vous n'acceptez pas les modifications, vous pourrez télécharger vos données, mais vous ne pourrez pas saisir de nouvelles données dans l'application. Les révisions entrent en vigueur dès leur publication. Votre utilisation continue de ce site après toute modification de cette politique de confidentialité constitue votre acceptation de cette modification.
+
+
+
+
+**Quand allons-nous vous contacter?**
+
+
+
+
+Si vous créez un compte LiteFarm, nous enverrons occasionnellement des courriels pour annoncer de nouvelles fonctionnalités dans LiteFarm, pour expliquer toute modification apportée à l'application, vous inviter à des événements spéciaux ou vous informer des projets de recherche que les données de LiteFarm contribuent à rendre possibles. Nous pouvons également vous envoyer occasionnellement des courriels pour vous demander votre avis sur l’application ou le site web. Votre participation à une telle demande est entièrement volontaire et n'affectera pas votre utilisation de la plateforme.
+
+
+
+
+**Licence**
+
+
+
+
+Présentement, l'application LiteFarm est gratuite. Le logiciel lui-même est sous licence GNU Public License v3, qui est une licence gratuite et open-source (https://www.gnu.org/licenses/quick-guide-gplv3.en.html).
+
+
+
+
+**Pour plus d'informations**
+Concernant de la plateforme, merci de contacter :
+
+- Chef de produit: Kevin Cussen (kcussen@litefarm.org)
+
+Concernant la recherche universitaire, merci de contacter :
+
+- Chercheure principale: Dr. Hannah Wittman (hannah.wittman@ubc.ca)
+
+
+
+
+**Si vous avez des préoccupations ou des plaintes concernant vos droits en tant que participant à la recherche et/ou vos expériences lors de votre participation à cette étude:**
+
+
+
+
+Communiquez avec la ligne de plainte des participants à la recherche du Bureau d'éthique de la recherche de UBC au 604-822-8598 ou, en cas d'interurbain, envoyez un courriel à RSIL@ors.ubc.ca ou appelez sans frais le 1-877-822-8598.
+
+
+
+
+**Consentement**
+
+
+
+
+En appuyant sur « Accepter » ci-dessous, cela indique que vous avez téléchargé une copie de ce formulaire de consentement et de la politique de confidentialité pour vos propres dossiers et que vous consentez à participer à cette étude.
+
+Éthique de l'étude à UBC - Identification de l’étude: H19-01482
+
+
+
diff --git a/packages/webapp/src/containers/Consent/locales/pt/Owner.Consent.md b/packages/webapp/src/containers/Consent/locales/pt/Owner.Consent.md
index 1aa68bfda9..3d1cbf24b7 100644
--- a/packages/webapp/src/containers/Consent/locales/pt/Owner.Consent.md
+++ b/packages/webapp/src/containers/Consent/locales/pt/Owner.Consent.md
@@ -142,6 +142,7 @@ Coletamos dados de uso (ou seja, estatísticas gerais sobre usuários, padrões
Existem três formas principais de usarmos seus dados:
- Para melhorar os serviços que prestamos a você: Como descrito acima, usamos seus dados de uso (ex.: informações gerais sobre como você interage com a plataforma LiteFarm) para melhorar a plataforma LiteFarm e os serviços que ela oferece.
+
- Para gerar ideias sobre os benefícios financeiros, ambientais e sociais, ou sobre os impactos de suas decisões de gestão: A plataforma LiteFarm usa os dados de gestão que você insere no aplicativo (consulte a seção “Informações de gestão agrícola” acima para ver uma lista completa), juntamente com algoritmos integrados e alguns dados públicos (ex.: informações da estação meteorológica local, coeficientes de culturas, conteúdo de nutrientes de culturas e fertilizantes, dados de ocorrência de espécies e dados topográficos) para gerar informações sobre benefícios/impactos financeiros, ambientais e sociais de suas decisões de gestão.
- Para realizar pesquisas acadêmicas não comerciais sobre sistemas alimentares sustentáveis: Juntamente com nossos colaboradores acadêmicos, usaremos seus dados de gestão agrícola anonimizados (consulte a seção “Informações de gestão agrícola” acima para ver uma lista completa) para conduzir pesquisas acadêmicas agronômicas, ecológicas e sobre sistemas alimentares. Algumas dessas pesquisas serão conduzidas por alunos de doutorado como parte de seus estudos de pós-graduação. Avaliaremos rigorosamente cada proposta de projeto para garantir que seus dados sejam usados efetivamente para fazer avançar o conhecimento sobre sistemas alimentares sustentáveis, ajudar agricultores a tomar decisões sustentáveis de gestão e impactar políticas públicas que beneficiem agricultores. Manteremos você informado sobre os projetos de pesquisa por meio de e-mails (a menos que você prefira não recebê-los) e você também poderá sempre nos contatar para saber mais sobre as pesquisas que seus dados estão tornando possíveis.
diff --git a/packages/webapp/src/containers/Consent/saga.js b/packages/webapp/src/containers/Consent/saga.js
index d0733e67d5..ee7f5bd9e6 100644
--- a/packages/webapp/src/containers/Consent/saga.js
+++ b/packages/webapp/src/containers/Consent/saga.js
@@ -59,6 +59,10 @@ export function* patchConsentSaga({ payload }) {
yield put(patchStatusConsentSuccess({ ...userFarm, ...data, status: 'Active' }));
yield call(fetchAllSaga);
history.push('/outro', { farm_id, farm_name });
+ } else if (payload.goForwardTo === '/') {
+ yield put(patchStatusConsentSuccess({ ...userFarm, ...data, status: 'Active' }));
+ yield call(fetchAllSaga);
+ history.push(payload.goForwardTo);
} else {
yield put(patchConsentStepThreeSuccess({ ...userFarm, ...step, ...data }));
history.push(payload.goForwardTo);
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.js b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.js
deleted file mode 100644
index 26c129ca64..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import PureBedPlan from '../../../../components/Crop/BedPlan/PureBedPlan';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { cropVarietySelector } from '../../../cropVarietySlice';
-import { useMemo } from 'react';
-import { getBedMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
-
-export default function BedPlan({ history, match }) {
- const system = useSelector(measurementSelector);
- const crop_variety = useSelector(cropVarietySelector(match.params.variety_id));
- const isFinalPage = match.path === '/crop/:variety_id/add_management_plan/bed_method';
- const { submitPath } = useMemo(
- () => getBedMethodPaths(crop_variety.crop_variety_id, isFinalPage),
- [],
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.jsx
new file mode 100644
index 0000000000..766cb8825b
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlan.jsx
@@ -0,0 +1,30 @@
+import PureBedPlan from '../../../../components/Crop/BedPlan/PureBedPlan';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { cropVarietySelector } from '../../../cropVarietySlice';
+import { useMemo } from 'react';
+import { getBedMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
+
+export default function BedPlan({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const crop_variety = useSelector(cropVarietySelector(match.params.variety_id));
+ const isFinalPage = match.path === '/crop/:variety_id/add_management_plan/bed_method';
+ const { submitPath } = useMemo(
+ () => getBedMethodPaths(crop_variety.crop_variety_id, isFinalPage),
+ [],
+ );
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.js b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.js
deleted file mode 100644
index 743ec3927d..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import PurePlanGuidance from '../../../../components/Crop/BedPlan/PurePlanGuidance';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useMemo } from 'react';
-import { getBedGuidancePaths } from '../../../../components/Crop/getAddManagementPlanPath';
-
-export default function BedPlan({ history, match }) {
- const variety_id = match.params.variety_id;
- const system = useSelector(measurementSelector);
- const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/bed_guidance';
- const { submitPath } = useMemo(
- () => getBedGuidancePaths(variety_id, isFinalPage),
- [],
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.jsx
new file mode 100644
index 0000000000..ec63dca798
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/BedPlan/BedPlanGuidance.jsx
@@ -0,0 +1,26 @@
+import PurePlanGuidance from '../../../../components/Crop/BedPlan/PurePlanGuidance';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useMemo } from 'react';
+import { getBedGuidancePaths } from '../../../../components/Crop/getAddManagementPlanPath';
+
+export default function BedPlan({ history, match, location }) {
+ const variety_id = match.params.variety_id;
+ const system = useSelector(measurementSelector);
+ const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/bed_guidance';
+ const { submitPath } = useMemo(() => getBedGuidancePaths(variety_id, isFinalPage), []);
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.js
deleted file mode 100644
index 0fe7626d9f..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-import PureBroadcastPlan from '../../../../components/Crop/BroadcastPlan';
-import { useSelector } from 'react-redux';
-import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { measurementSelector } from '../../../userFarmSlice';
-import { cropLocationByIdSelector } from '../../../locationSlice';
-import { cropVarietySelector } from '../../../cropVarietySlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-
-function BroadcastPlan({ history, match }) {
- const persistedFormData = useSelector(hookFormPersistSelector);
- const variety_id = match.params.variety_id;
- const cropVariety = useSelector(cropVarietySelector(variety_id));
- const yieldPerArea = cropVariety.yield_per_area || 0;
- const system = useSelector(measurementSelector);
- const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/broadcast_method';
- const location = useSelector(
- cropLocationByIdSelector(
- persistedFormData.crop_management_plan.planting_management_plans[
- isFinalPage ? 'final' : 'initial'
- ].location_id,
- ),
- );
-
- return (
-
-
-
- );
-}
-
-export default BroadcastPlan;
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.jsx
new file mode 100644
index 0000000000..b391fea166
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/BroadcastPlan/index.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import PureBroadcastPlan from '../../../../components/Crop/BroadcastPlan';
+import { useSelector } from 'react-redux';
+import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { measurementSelector } from '../../../userFarmSlice';
+import { cropLocationByIdSelector } from '../../../locationSlice';
+import { cropVarietySelector } from '../../../cropVarietySlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+
+function BroadcastPlan({ history, match, location }) {
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const variety_id = match.params.variety_id;
+ const cropVariety = useSelector(cropVarietySelector(variety_id));
+ const yieldPerArea = cropVariety.yield_per_area || 0;
+ const system = useSelector(measurementSelector);
+ const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/broadcast_method';
+ const planLocation = useSelector(
+ cropLocationByIdSelector(
+ persistedFormData.crop_management_plan.planting_management_plans[
+ isFinalPage ? 'final' : 'initial'
+ ].location_id,
+ ),
+ );
+
+ return (
+
+
+
+ );
+}
+
+export default BroadcastPlan;
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/ManagementPlanName/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/ManagementPlanName/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/AddManagementPlan/ManagementPlanName/index.js
rename to packages/webapp/src/containers/Crop/AddManagementPlan/ManagementPlanName/index.jsx
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.js
deleted file mode 100644
index 07725be65e..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import PurePlantInContainer from '../../../../components/Crop/PlantInContainer';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { cropVarietySelector } from '../../../cropVarietySlice';
-import { useMemo } from 'react';
-import { getContainerMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
-import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
-
-export default function PlantInContainer({ history, match }) {
- const system = useSelector(measurementSelector);
- const crop_variety = useSelector(cropVarietySelector(match.params.variety_id));
- const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/container_method';
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { submitPath } = useMemo(
- () => getContainerMethodPaths(match.params.variety_id, persistedFormData, isFinalPage),
- [],
- );
- const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
- const isHistorical =
- already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.jsx
new file mode 100644
index 0000000000..4f7688a49b
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantInContainer/index.jsx
@@ -0,0 +1,36 @@
+import PurePlantInContainer from '../../../../components/Crop/PlantInContainer';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { cropVarietySelector } from '../../../cropVarietySlice';
+import { useMemo } from 'react';
+import { getContainerMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
+import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
+
+export default function PlantInContainer({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const crop_variety = useSelector(cropVarietySelector(match.params.variety_id));
+ const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/container_method';
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { submitPath } = useMemo(
+ () => getContainerMethodPaths(match.params.variety_id, persistedFormData, isFinalPage),
+ [],
+ );
+ const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
+ const isHistorical =
+ already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.js
deleted file mode 100644
index df8f376833..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { useSelector } from 'react-redux';
-import PurePlantedAlready from '../../../../components/Crop/PlantedAlready';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { measurementSelector } from '../../../userFarmSlice';
-import { cropVarietySelector } from '../../../cropVarietySlice';
-
-function PlantedAlready({ history, match }) {
- const system = useSelector(measurementSelector);
- const variety_id = match?.params?.variety_id;
- const cropVariety = useSelector(cropVarietySelector(variety_id));
-
- return (
-
-
-
- );
-}
-
-export default PlantedAlready;
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.jsx
new file mode 100644
index 0000000000..29984650fc
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantedAlready/index.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import PurePlantedAlready from '../../../../components/Crop/PlantedAlready';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { measurementSelector } from '../../../userFarmSlice';
+import { cropVarietySelector } from '../../../cropVarietySlice';
+
+function PlantedAlready({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const variety_id = match?.params?.variety_id;
+ const cropVariety = useSelector(cropVarietySelector(variety_id));
+
+ return (
+
+
+
+ );
+}
+
+export default PlantedAlready;
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingDate/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingDate/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/AddManagementPlan/PlantingDate/index.js
rename to packages/webapp/src/containers/Crop/AddManagementPlan/PlantingDate/index.jsx
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.js
deleted file mode 100644
index 948d27acb5..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import JoyrideWrapper from '../../../../components/JoyrideWrapper';
-import { Trans, useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../../../showedSpotlightSlice';
-import { setSpotlightToShown } from '../../../Map/saga';
-import React from 'react';
-import { LIFECYCLE } from 'react-joyride';
-import { ReactComponent as PlantIcon } from '../../../../assets/images/managementPlans/plant.svg';
-
-export default function TransplantSpotlight({ is_seed }) {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { transplant } = useSelector(showedSpotlightSelector);
- const callback = (data) => {
- const { lifecycle } = data;
- if (lifecycle === LIFECYCLE.COMPLETE) {
- dispatch(setSpotlightToShown('transplant'));
- }
- };
-
- const showSpotlight = !transplant;
-
- const titleFill =
- is_seed === false
- ? t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.TITLE.PLANTING')
- : t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.TITLE.SEEDING');
- const bodyFill =
- is_seed === true
- ? t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.PLANTED')
- : t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.SEEDED');
-
- // this is an unused variable, but it is required for the translation to work
- const spotlightText = t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.TEXT');
-
- return (
- <>
- {showSpotlight && (
-
- Please indicate where this crop will be initially
- {{ fill: bodyFill }} . We’ll ask about where you’ll transplant it
- to later.
- ,
- ],
- target: 'body',
- placement: 'center',
- disableCloseOnEsc: true,
- buttonText: t('common:GOT_IT'),
- icon: ,
- },
- ]}
- callback={callback}
- />
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.jsx
new file mode 100644
index 0000000000..415dc69cb5
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/TransplantSpotlight.jsx
@@ -0,0 +1,48 @@
+import { Trans, useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { showedSpotlightSelector } from '../../../showedSpotlightSlice';
+import { setSpotlightToShown } from '../../../Map/saga';
+import React from 'react';
+import { ReactComponent as PlantIcon } from '../../../../assets/images/managementPlans/plant.svg';
+import { TourProviderWrapper } from '../../../../components/TourProviderWrapper/TourProviderWrapper';
+
+export default function TransplantSpotlight({ is_seed }) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { transplant } = useSelector(showedSpotlightSelector);
+ const onFinish = (data) => dispatch(setSpotlightToShown('transplant'));
+
+ const showSpotlight = !transplant;
+
+ const titleFill =
+ is_seed === false
+ ? t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.TITLE.PLANTING')
+ : t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.TITLE.SEEDING');
+ const bodyFill =
+ is_seed === true
+ ? t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.PLANTED')
+ : t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.SEEDED');
+
+ // this is an unused variable, but it is required for the translation to work
+ const spotlightText = t('MANAGEMENT_PLAN.TRANSPLANT_SPOTLIGHT.BODY.TEXT');
+
+ return
+ Please indicate where this crop will be initially
+ {{ fill: bodyFill }} . We’ll ask about where you’ll transplant it
+ to later.
+ ,
+ ],
+ position: 'center',
+ icon: ,
+ },
+ ]}
+ open={showSpotlight}
+ onFinish={onFinish}
+ />;
+
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/index.js
rename to packages/webapp/src/containers/Crop/AddManagementPlan/PlantingLocation/index.jsx
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.js
deleted file mode 100644
index c3ce095f14..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import PureManagementPlanPlantingMethod from '../../../../components/Crop/PlantingMethod/PureManagementPlanPlantingMethod';
-import { useSelector } from 'react-redux';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { measurementSelector } from '../../../userFarmSlice';
-
-export default function PlantingMethod({ history, match }) {
- const system = useSelector(measurementSelector);
- const isFinalPlantingMethod =
- match.path === '/crop/:variety_id/add_management_plan/final_planting_method';
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.jsx
new file mode 100644
index 0000000000..c2cc874798
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/PlantingMethod/index.jsx
@@ -0,0 +1,21 @@
+import PureManagementPlanPlantingMethod
+ from '../../../../components/Crop/PlantingMethod/PureManagementPlanPlantingMethod';
+import { useSelector } from 'react-redux';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { measurementSelector } from '../../../userFarmSlice';
+
+export default function PlantingMethod({ history, match }) {
+ const system = useSelector(measurementSelector);
+ const isFinalPlantingMethod =
+ match.path === '/crop/:variety_id/add_management_plan/final_planting_method';
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.js b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.js
deleted file mode 100644
index e8060d3637..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import PurePlanGuidance from '../../../../components/Crop/BedPlan/PurePlanGuidance';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useMemo } from 'react';
-import { getRowGuidancePaths } from '../../../../components/Crop/getAddManagementPlanPath';
-
-export default function RowGuidance({ history, match }) {
- const variety_id = match.params.variety_id;
- const system = useSelector(measurementSelector);
- const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/row_guidance';
- const { submitPath } = useMemo(
- () => getRowGuidancePaths(variety_id, isFinalPage),
- [],
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.jsx
new file mode 100644
index 0000000000..08a2e2812b
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/RowGuidance.jsx
@@ -0,0 +1,26 @@
+import PurePlanGuidance from '../../../../components/Crop/BedPlan/PurePlanGuidance';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useMemo } from 'react';
+import { getRowGuidancePaths } from '../../../../components/Crop/getAddManagementPlanPath';
+
+export default function RowGuidance({ history, match, location }) {
+ const variety_id = match.params.variety_id;
+ const system = useSelector(measurementSelector);
+ const isFinalPage = match?.path === '/crop/:variety_id/add_management_plan/row_guidance';
+ const { submitPath } = useMemo(() => getRowGuidancePaths(variety_id, isFinalPage), []);
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.js b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.js
deleted file mode 100644
index eb3667c11e..0000000000
--- a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import PureRowMethod from '../../../../components/Crop/RowMethod';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { cropVarietySelector } from '../../../cropVarietySlice';
-import { useMemo } from 'react';
-import { getRowMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
-import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
-
-export default function RowMethod({ history, match }) {
- const system = useSelector(measurementSelector);
- const variety_id = match.params.variety_id;
- const crop_variety = useSelector(cropVarietySelector(variety_id));
- const persistedFormData = useSelector(hookFormPersistSelector);
- const isFinalPage = match.path === '/crop/:variety_id/add_management_plan/row_method';
- const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
- const isHistoricalPage =
- already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
- const { submitPath } = useMemo(
- () => getRowMethodPaths(crop_variety.crop_variety_id, isFinalPage),
- [],
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.jsx b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.jsx
new file mode 100644
index 0000000000..d72a6fe537
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/AddManagementPlan/RowMethod/index.jsx
@@ -0,0 +1,36 @@
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import PureRowMethod from '../../../../components/Crop/RowMethod';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { cropVarietySelector } from '../../../cropVarietySlice';
+import { useMemo } from 'react';
+import { getRowMethodPaths } from '../../../../components/Crop/getAddManagementPlanPath';
+import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
+
+export default function RowMethod({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const variety_id = match.params.variety_id;
+ const crop_variety = useSelector(cropVarietySelector(variety_id));
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const isFinalPage = match.path === '/crop/:variety_id/add_management_plan/row_method';
+ const { already_in_ground, needs_transplant } = persistedFormData.crop_management_plan;
+ const isHistoricalPage =
+ already_in_ground && ((needs_transplant && !isFinalPage) || !needs_transplant);
+ const { submitPath } = useMemo(
+ () => getRowMethodPaths(crop_variety.crop_variety_id, isFinalPage),
+ [],
+ );
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/AddManagementPlan/Transplant.js b/packages/webapp/src/containers/Crop/AddManagementPlan/Transplant.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/AddManagementPlan/Transplant.js
rename to packages/webapp/src/containers/Crop/AddManagementPlan/Transplant.jsx
diff --git a/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.js b/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.js
deleted file mode 100644
index 4d27c629e6..0000000000
--- a/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import {
- PureCompleteManagementPlan,
- SOMETHING_ELSE,
-} from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
-import { useDispatch, useSelector } from 'react-redux';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { abandonManagementPlan } from './saga';
-import { useAbandonReasonOptions } from './useAbandonReasonOptions';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function AbandonManagementPlan({ match, history }) {
- const management_plan_id = match.params.management_plan_id;
- const crop_variety_id = match.params.variety_id;
- const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
- const { start_date } = useSelector(managementPlanSelector(management_plan_id));
- const dispatch = useDispatch();
- const reasonOptions = useAbandonReasonOptions();
-
- const onGoBack = () => {
- history.push(`/crop/${crop_variety_id}/management_plan/${management_plan_id}/tasks`);
- };
- const onSubmit = (data) => {
- const reqBody = {
- crop_variety_id,
- management_plan_id,
- ...data,
- created_abandon_reason: undefined,
- abandon_reason:
- data.abandon_reason.value === SOMETHING_ELSE
- ? data.created_abandon_reason || SOMETHING_ELSE
- : data.abandon_reason.value,
- };
-
- dispatch(abandonManagementPlan(reqBody));
- };
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.jsx b/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.jsx
new file mode 100644
index 0000000000..ab36a62e14
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/CompleteManagementPlan/AbandonManagementPlan.jsx
@@ -0,0 +1,46 @@
+import {
+ PureCompleteManagementPlan,
+ SOMETHING_ELSE,
+} from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
+import { useDispatch, useSelector } from 'react-redux';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { abandonManagementPlan } from './saga';
+import { useAbandonReasonOptions } from './useAbandonReasonOptions';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function AbandonManagementPlan({ match, history, location }) {
+ const management_plan_id = match.params.management_plan_id;
+ const crop_variety_id = match.params.variety_id;
+ const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
+ const { start_date } = useSelector(managementPlanSelector(management_plan_id));
+ const dispatch = useDispatch();
+ const reasonOptions = useAbandonReasonOptions();
+
+ const onGoBack = () => {
+ history.push(`/crop/${crop_variety_id}/management`, location?.state);
+ };
+ const onSubmit = (data) => {
+ const reqBody = {
+ crop_variety_id,
+ management_plan_id,
+ ...data,
+ created_abandon_reason: undefined,
+ abandon_reason:
+ data.abandon_reason.value === SOMETHING_ELSE
+ ? data.created_abandon_reason || SOMETHING_ELSE
+ : data.abandon_reason.value,
+ };
+
+ dispatch(abandonManagementPlan(reqBody));
+ };
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.js b/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.js
deleted file mode 100644
index 9510b361ff..0000000000
--- a/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { PureCompleteManagementPlan } from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
-import { useDispatch, useSelector } from 'react-redux';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { completeManagementPlan } from './saga';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function CompleteManagementPlan({ match, history }) {
- const management_plan_id = match.params.management_plan_id;
- const crop_variety_id = match.params.variety_id;
- const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
- const { start_date } = useSelector(managementPlanSelector(management_plan_id));
- const dispatch = useDispatch();
-
- const onGoBack = () => {
- history.push(`/crop/${crop_variety_id}/management_plan/${management_plan_id}/tasks`);
- };
- const onSubmit = (data) => {
- dispatch(completeManagementPlan({ crop_variety_id, management_plan_id, ...data }));
- };
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.jsx b/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.jsx
new file mode 100644
index 0000000000..37274f9006
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/CompleteManagementPlan/CompleteManagementPlan.jsx
@@ -0,0 +1,32 @@
+import { PureCompleteManagementPlan } from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
+import { useDispatch, useSelector } from 'react-redux';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { completeManagementPlan } from './saga';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function CompleteManagementPlan({ match, history, location }) {
+ const management_plan_id = match.params.management_plan_id;
+ const crop_variety_id = match.params.variety_id;
+ const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
+ const { start_date } = useSelector(managementPlanSelector(management_plan_id));
+ const dispatch = useDispatch();
+
+ const onGoBack = () => {
+ history.push(
+ `/crop/${crop_variety_id}/management_plan/${management_plan_id}/tasks`,
+ location?.state,
+ );
+ };
+ const onSubmit = (data) => {
+ dispatch(completeManagementPlan({ crop_variety_id, management_plan_id, ...data }));
+ };
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/CropDetail/index.js b/packages/webapp/src/containers/Crop/CropDetail/index.js
deleted file mode 100644
index ba9de0b7c2..0000000000
--- a/packages/webapp/src/containers/Crop/CropDetail/index.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import { useDispatch, useSelector } from 'react-redux';
-import PureCropDetail from '../../../components/Crop/detail';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { useState } from 'react';
-import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
-import {
- currentAndPlannedManagementPlansByCropVarietySelector,
- currentManagementPlanByCropVarietyIdSelector,
- plannedManagementPlanByCropVarietyIdSelector,
-} from '../../managementPlanSlice';
-import CropVarietySpotlight from '../CropVarietySpotlight';
-import RetireCropWarning from '../../../components/Modals/CropModals/RetireCropWarningModal';
-import EditCropVarietyModal from '../../../components/Modals/EditCropVarietyModal';
-import UnableToRetireCropModal from '../../../components/Modals/CropModals/UnableToRetireCropModal';
-import { deleteVarietal } from '../../AddCropVariety/saga';
-import { isAdminSelector } from '../../userFarmSlice';
-
-function CropDetail({ history, match }) {
- const { variety_id } = match.params;
- const dispatch = useDispatch();
- const selectedVariety = useSelector(cropVarietySelector(variety_id));
- const { crop_id } = selectedVariety;
- const [showWarningBox, setShowWarningBox] = useState(false);
- const [showErrorBox, setShowErrorBox] = useState(false);
- const { interested } = useSelector(certifierSurveySelector);
- const [showEditModal, setShowEditModal] = useState(false);
- const activeOrPlannedManagementPlansOnVariety = useSelector(
- currentAndPlannedManagementPlansByCropVarietySelector(variety_id),
- );
- const currentMPs = useSelector(currentManagementPlanByCropVarietyIdSelector(variety_id));
- const plannedMPs = useSelector(plannedManagementPlanByCropVarietyIdSelector(variety_id));
- const hasNoManagementPlans = currentMPs.length < 1 && plannedMPs.length < 1;
-
- const goBack = () => {
- history.push(`/crop_varieties/crop/${crop_id}`);
- };
-
- const warningModal = () => {
- if (activeOrPlannedManagementPlansOnVariety.length === 0) {
- return setShowWarningBox(true);
- } else {
- return setShowErrorBox(true);
- }
- };
-
- const confirmRetire = () => {
- dispatch(deleteVarietal({ variety_id }));
- };
-
- const handleEdit = () => {
- if (hasNoManagementPlans) {
- history.push(`/crop/${variety_id}/edit_crop_variety`);
- } else {
- setShowEditModal(true);
- }
- };
-
- const isAdmin = useSelector(isAdminSelector);
-
- return (
- <>
- warningModal()}
- onEdit={handleEdit}
- isAdmin={isAdmin}
- />
-
- {showWarningBox && (
- setShowWarningBox(false)}
- />
- )}
- {showErrorBox && setShowErrorBox(false)} />}
- {showEditModal && (
- setShowEditModal(false)}
- handleEdit={() => history.push(`/crop/${variety_id}/edit_crop_variety`)}
- />
- )}
- >
- );
-}
-
-export default CropDetail;
diff --git a/packages/webapp/src/containers/Crop/CropDetail/index.jsx b/packages/webapp/src/containers/Crop/CropDetail/index.jsx
new file mode 100644
index 0000000000..aac2f2c4bd
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/CropDetail/index.jsx
@@ -0,0 +1,90 @@
+import { useDispatch, useSelector } from 'react-redux';
+import PureCropDetail from '../../../components/Crop/Detail';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { useState } from 'react';
+import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
+import {
+ currentAndPlannedManagementPlansByCropVarietySelector,
+ currentManagementPlanByCropVarietyIdSelector,
+ plannedManagementPlanByCropVarietyIdSelector,
+} from '../../managementPlanSlice';
+import CropVarietySpotlight from '../CropVarietySpotlight';
+import RetireCropWarning from '../../../components/Modals/CropModals/RetireCropWarningModal';
+import EditCropVarietyModal from '../../../components/Modals/EditCropVarietyModal';
+import UnableToRetireCropModal from '../../../components/Modals/CropModals/UnableToRetireCropModal';
+import { deleteVarietal } from '../../AddCropVariety/saga';
+import { isAdminSelector } from '../../userFarmSlice';
+
+function CropDetail({ history, match, location }) {
+ const { variety_id } = match.params;
+ const dispatch = useDispatch();
+ const selectedVariety = useSelector(cropVarietySelector(variety_id));
+ const { crop_id } = selectedVariety;
+ const [showWarningBox, setShowWarningBox] = useState(false);
+ const [showErrorBox, setShowErrorBox] = useState(false);
+ const { interested } = useSelector(certifierSurveySelector);
+ const [showEditModal, setShowEditModal] = useState(false);
+ const activeOrPlannedManagementPlansOnVariety = useSelector(
+ currentAndPlannedManagementPlansByCropVarietySelector(variety_id),
+ );
+ const currentMPs = useSelector(currentManagementPlanByCropVarietyIdSelector(variety_id));
+ const plannedMPs = useSelector(plannedManagementPlanByCropVarietyIdSelector(variety_id));
+ const hasNoManagementPlans = currentMPs.length < 1 && plannedMPs.length < 1;
+
+ const goBack = () => {
+ history.push(location?.state?.returnPath ?? `/crop_varieties/crop/${crop_id}`, location.state);
+ };
+
+ const warningModal = () => {
+ if (activeOrPlannedManagementPlansOnVariety.length === 0) {
+ return setShowWarningBox(true);
+ } else {
+ return setShowErrorBox(true);
+ }
+ };
+
+ const confirmRetire = () => {
+ dispatch(deleteVarietal({ variety_id }));
+ };
+
+ const handleEdit = () => {
+ if (hasNoManagementPlans) {
+ history.push(`/crop/${variety_id}/edit_crop_variety`);
+ } else {
+ setShowEditModal(true);
+ }
+ };
+
+ const isAdmin = useSelector(isAdminSelector);
+
+ return (
+
+ warningModal()}
+ onEdit={handleEdit}
+ isAdmin={isAdmin}
+ location={location}
+ />
+ {showWarningBox && (
+ setShowWarningBox(false)}
+ />
+ )}
+ {showErrorBox && setShowErrorBox(false)} />}
+ {showEditModal && (
+ setShowEditModal(false)}
+ handleEdit={() => history.push(`/crop/${variety_id}/edit_crop_variety`)}
+ />
+ )}
+
+ );
+}
+
+export default CropDetail;
diff --git a/packages/webapp/src/containers/Crop/CropManagement/index.js b/packages/webapp/src/containers/Crop/CropManagement/index.js
deleted file mode 100644
index 153df44f29..0000000000
--- a/packages/webapp/src/containers/Crop/CropManagement/index.js
+++ /dev/null
@@ -1,130 +0,0 @@
-import { useDispatch, useSelector } from 'react-redux';
-import PureCropManagement from '../../../components/Crop/management';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import CropVarietySpotlight from '../CropVarietySpotlight';
-import {
- setFormData,
- setPersistedPaths,
-} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import {
- addManagementPlanNamePath,
- finalBedGuidancePath,
- finalBedPath,
- finalBroadcastPath,
- finalContainerPath,
- finalLocationPath,
- finalPlantingMethodPath,
- finalRowGuidancePath,
- finalRowPath,
- initialBedGuidancePath,
- initialBedPath,
- initialBroadcastPath,
- initialContainerPath,
- initialLocationPath,
- initialPlantingMethodPath,
- initialRowGuidancePath,
- initialRowPath,
- needsTransplantPath,
- plantedAlreadyPath,
- plantingDatePath,
-} from '../../../components/Crop/addManagementPlanPaths';
-import { useManagementPlanCardContents } from './useManagementPlanCardContents';
-import { useEffect } from 'react';
-import { getManagementPlans } from '../../saga';
-import { getTasks, getTaskTypes } from '../../Task/saga';
-import { isAdminSelector } from '../../userFarmSlice';
-
-const seedingTypeIsSeedMap = {
- SEED: true,
- SEEDLING_OR_PLANTING_STOCK: false,
-};
-
-function CropManagement({ history, match }) {
- const dispatch = useDispatch();
- const variety_id = match.params.variety_id;
- const selectedVariety = useSelector(cropVarietySelector(variety_id));
-
- const managementPlanCardContents = useManagementPlanCardContents(variety_id);
- const goBack = () => {
- history.push(`/crop_varieties/crop/${selectedVariety.crop_id}`);
- };
- const onAddManagementPlan = () => {
- const estimated_seeds_unit = { value: 'kg', label: 'kg' };
- dispatch(
- setFormData({
- crop_management_plan: {
- for_cover: selectedVariety.can_be_cover_crop ? undefined : false,
- is_seed: seedingTypeIsSeedMap[selectedVariety.seeding_type],
- needs_transplant: selectedVariety.needs_transplant,
-
- planting_management_plans: {
- final: {
- estimated_seeds_unit,
- planting_method: selectedVariety.planting_method,
- bed_method: {
- plant_spacing: selectedVariety.plant_spacing,
- planting_depth: selectedVariety.planting_depth,
- },
- row_method: {
- plant_spacing: selectedVariety.plant_spacing,
- planting_depth: selectedVariety.planting_depth,
- },
- broadcast_method: { seeding_rate: selectedVariety.seeding_rate },
- container_method: { planting_depth: selectedVariety.planting_depth },
- },
- initial: { estimated_seeds_unit },
- },
- },
- }),
- );
- dispatch(
- setPersistedPaths([
- plantedAlreadyPath(variety_id),
- needsTransplantPath(variety_id),
- plantingDatePath(variety_id),
- initialLocationPath(variety_id),
- finalLocationPath(variety_id),
- finalPlantingMethodPath(variety_id),
- initialPlantingMethodPath(variety_id),
- initialBroadcastPath(variety_id),
- initialContainerPath(variety_id),
- initialBedPath(variety_id),
- initialBedGuidancePath(variety_id),
- initialRowPath(variety_id),
- initialRowGuidancePath(variety_id),
- finalBroadcastPath(variety_id),
- finalContainerPath(variety_id),
- finalBedPath(variety_id),
- finalBedGuidancePath(variety_id),
- finalRowPath(variety_id),
- finalRowGuidancePath(variety_id),
- addManagementPlanNamePath(variety_id),
- ]),
- );
- history.push(plantedAlreadyPath(variety_id));
- };
-
- useEffect(() => {
- dispatch(getTaskTypes());
- dispatch(getManagementPlans());
- dispatch(getTasks());
- }, []);
-
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
-
- >
- );
-}
-
-export default CropManagement;
diff --git a/packages/webapp/src/containers/Crop/CropManagement/index.jsx b/packages/webapp/src/containers/Crop/CropManagement/index.jsx
new file mode 100644
index 0000000000..b25360572e
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/CropManagement/index.jsx
@@ -0,0 +1,130 @@
+import { useDispatch, useSelector } from 'react-redux';
+import PureCropManagement from '../../../components/Crop/Management';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import CropVarietySpotlight from '../CropVarietySpotlight';
+import {
+ setFormData,
+ setPersistedPaths,
+} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import {
+ addManagementPlanNamePath,
+ finalBedGuidancePath,
+ finalBedPath,
+ finalBroadcastPath,
+ finalContainerPath,
+ finalLocationPath,
+ finalPlantingMethodPath,
+ finalRowGuidancePath,
+ finalRowPath,
+ initialBedGuidancePath,
+ initialBedPath,
+ initialBroadcastPath,
+ initialContainerPath,
+ initialLocationPath,
+ initialPlantingMethodPath,
+ initialRowGuidancePath,
+ initialRowPath,
+ needsTransplantPath,
+ plantedAlreadyPath,
+ plantingDatePath,
+} from '../../../components/Crop/addManagementPlanPaths';
+import { useManagementPlanCardContents } from './useManagementPlanCardContents';
+import { useEffect } from 'react';
+import { getManagementPlans } from '../../saga';
+import { getTasks, getTaskTypes } from '../../Task/saga';
+import { isAdminSelector } from '../../userFarmSlice';
+
+const seedingTypeIsSeedMap = {
+ SEED: true,
+ SEEDLING_OR_PLANTING_STOCK: false,
+};
+
+function CropManagement({ history, match, location }) {
+ const dispatch = useDispatch();
+ const variety_id = match.params.variety_id;
+ const selectedVariety = useSelector(cropVarietySelector(variety_id));
+
+ const managementPlanCardContents = useManagementPlanCardContents(variety_id);
+ const goBack = () => {
+ history.push(location?.state?.returnPath ?? `/crop_varieties/crop/${selectedVariety.crop_id}`);
+ };
+ const onAddManagementPlan = () => {
+ const estimated_seeds_unit = { value: 'kg', label: 'kg' };
+ dispatch(
+ setFormData({
+ crop_management_plan: {
+ for_cover: selectedVariety.can_be_cover_crop ? undefined : false,
+ is_seed: seedingTypeIsSeedMap[selectedVariety.seeding_type],
+ needs_transplant: selectedVariety.needs_transplant,
+
+ planting_management_plans: {
+ final: {
+ estimated_seeds_unit,
+ planting_method: selectedVariety.planting_method,
+ bed_method: {
+ plant_spacing: selectedVariety.plant_spacing,
+ planting_depth: selectedVariety.planting_depth,
+ },
+ row_method: {
+ plant_spacing: selectedVariety.plant_spacing,
+ planting_depth: selectedVariety.planting_depth,
+ },
+ broadcast_method: { seeding_rate: selectedVariety.seeding_rate },
+ container_method: { planting_depth: selectedVariety.planting_depth },
+ },
+ initial: { estimated_seeds_unit },
+ },
+ },
+ }),
+ );
+ dispatch(
+ setPersistedPaths([
+ plantedAlreadyPath(variety_id),
+ needsTransplantPath(variety_id),
+ plantingDatePath(variety_id),
+ initialLocationPath(variety_id),
+ finalLocationPath(variety_id),
+ finalPlantingMethodPath(variety_id),
+ initialPlantingMethodPath(variety_id),
+ initialBroadcastPath(variety_id),
+ initialContainerPath(variety_id),
+ initialBedPath(variety_id),
+ initialBedGuidancePath(variety_id),
+ initialRowPath(variety_id),
+ initialRowGuidancePath(variety_id),
+ finalBroadcastPath(variety_id),
+ finalContainerPath(variety_id),
+ finalBedPath(variety_id),
+ finalBedGuidancePath(variety_id),
+ finalRowPath(variety_id),
+ finalRowGuidancePath(variety_id),
+ addManagementPlanNamePath(variety_id),
+ ]),
+ );
+ history.push(plantedAlreadyPath(variety_id));
+ };
+
+ useEffect(() => {
+ dispatch(getTaskTypes());
+ dispatch(getManagementPlans());
+ dispatch(getTasks());
+ }, []);
+
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+
+
+
+ );
+}
+
+export default CropManagement;
diff --git a/packages/webapp/src/containers/Crop/CropManagement/useManagementPlanCardContents.js b/packages/webapp/src/containers/Crop/CropManagement/useManagementPlanCardContents.js
index 688df620a8..b2c2746257 100644
--- a/packages/webapp/src/containers/Crop/CropManagement/useManagementPlanCardContents.js
+++ b/packages/webapp/src/containers/Crop/CropManagement/useManagementPlanCardContents.js
@@ -9,7 +9,9 @@ import {
import { useMemo } from 'react';
import { lastActiveDatetimeSelector } from '../../userLogSlice';
import { getTasksMinMaxDate } from '../../Task/getTasksMinMaxDate';
-import { managementPlanWithCurrentLocationEntitiesSelector } from '../../Task/TaskCrops/managementPlansWithLocationSelector';
+import {
+ managementPlanWithCurrentLocationEntitiesSelector,
+} from '../../Task/TaskCrops/managementPlansWithLocationSelector';
export const useManagementPlanCardContents = (crop_variety_id) => {
const tasksByManagementPlanId = useSelector(taskEntitiesByManagementPlanIdSelector);
@@ -32,7 +34,7 @@ export const useManagementPlanCardContents = (crop_variety_id) => {
notes: getNotes(planting_management_plan),
...getManagementPlanStartEndDate(management_plan, tasks),
numberOfPendingTask: tasks.filter(
- (task) => task.abandoned_time === null && task.completed_time === null,
+ (task) => task.abandon_date === null && task.complete_date === null,
).length,
status,
score: management_plan.rating,
diff --git a/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.js b/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.js
deleted file mode 100644
index e6053bcb70..0000000000
--- a/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import JoyrideWrapper from '../../../components/JoyrideWrapper';
-import { useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../../showedSpotlightSlice';
-import { setSpotlightToShown } from '../../Map/saga';
-import React from 'react';
-
-export default function CropVarietySpotlight() {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { crop_variety_detail } = useSelector(showedSpotlightSelector);
- const onFinish = () => dispatch(setSpotlightToShown('crop_variety_detail'));
- const managementId = `#${t('CROP_DETAIL.MANAGEMENT_TAB')}0`
- const detailId = `#${t('CROP_DETAIL.DETAIL_TAB')}1`
-
- return (
- <>
- { !crop_variety_detail && (
- <>
-
- >
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.jsx b/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.jsx
new file mode 100644
index 0000000000..b5accd2b04
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/CropVarietySpotlight/index.jsx
@@ -0,0 +1,40 @@
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { showedSpotlightSelector } from '../../showedSpotlightSlice';
+import { setSpotlightToShown } from '../../Map/saga';
+import React from 'react';
+import { TourProviderWrapper } from '../../../components/TourProviderWrapper/TourProviderWrapper';
+
+export default function CropVarietySpotlight({ children }) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { crop_variety_detail } = useSelector(showedSpotlightSelector);
+ const onFinish = () => dispatch(setSpotlightToShown('crop_variety_detail'));
+ const managementId = `#${t('CROP_DETAIL.MANAGEMENT_TAB')}0`;
+ const detailId = `#${t('CROP_DETAIL.DETAIL_TAB')}1`;
+
+ return {children} ;
+}
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/EditManagementDetails.js b/packages/webapp/src/containers/Crop/ManagementDetail/EditManagementDetails.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/ManagementDetail/EditManagementDetails.js
rename to packages/webapp/src/containers/Crop/ManagementDetail/EditManagementDetails.jsx
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.js b/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.js
deleted file mode 100644
index 0f6fa65e54..0000000000
--- a/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import JoyrideWrapper from '../../../components/JoyrideWrapper';
-import { useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../../showedSpotlightSlice';
-import { setSpotlightToShown } from '../../Map/saga';
-import React from 'react';
-import { LIFECYCLE } from 'react-joyride';
-
-export default function FirstManagementPlanSpotlight() {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { management_plan_creation } = useSelector(showedSpotlightSelector);
- const callback = (data) => {
- const { lifecycle } = data;
- if (lifecycle === LIFECYCLE.COMPLETE) {
- dispatch(setSpotlightToShown('management_plan_creation'));
- }
- };
-
- const showSpotlight = !management_plan_creation;
-
- return (
- <>
- {showSpotlight && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.jsx b/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.jsx
new file mode 100644
index 0000000000..24bccdf92b
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/ManagementDetail/FirstManagementPlanSpotlight.jsx
@@ -0,0 +1,36 @@
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { showedSpotlightSelector } from '../../showedSpotlightSlice';
+import { setSpotlightToShown } from '../../Map/saga';
+import React from 'react';
+import { TourProviderWrapper } from '../../../components/TourProviderWrapper/TourProviderWrapper';
+
+export default function FirstManagementPlanSpotlight() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { management_plan_creation } = useSelector(showedSpotlightSelector);
+ const onFinish = () => {
+ dispatch(setSpotlightToShown('management_plan_creation'));
+ };
+
+ const showSpotlight = !management_plan_creation;
+
+ return (
+ <>
+ {showSpotlight && (
+
+ )}
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/ManagementDetails.js b/packages/webapp/src/containers/Crop/ManagementDetail/ManagementDetails.jsx
similarity index 100%
rename from packages/webapp/src/containers/Crop/ManagementDetail/ManagementDetails.js
rename to packages/webapp/src/containers/Crop/ManagementDetail/ManagementDetails.jsx
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.js b/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.js
deleted file mode 100644
index 32ddf0daa3..0000000000
--- a/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import PureManagementTasks from '../../../components/Crop/ManagementDetail/ManagementPlanTasks';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-import { isAdminSelector } from '../../userFarmSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import FirstManagementPlanSpotlight from './FirstManagementPlanSpotlight';
-import { pendingTasksByManagementPlanIdSelector } from '../../taskSlice';
-import TaskCard from '../../Task/TaskCard';
-import React from 'react';
-import { taskCardContentByManagementPlanSelector } from '../../Task/taskCardContentSelector';
-import { onAddTask } from '../../Task/onAddTask';
-
-export default function ManagementTasks({ history, match }) {
- const dispatch = useDispatch();
- const variety_id = match.params.variety_id;
- const variety = useSelector(cropVarietySelector(variety_id));
-
- const management_plan_id = match.params.management_plan_id;
- const plan = useSelector(managementPlanSelector(management_plan_id));
- const isAdmin = useSelector(isAdminSelector);
-
- const onBack = () => {
- history.push(`/crop/${variety_id}/management`);
- };
-
- const onCompleted = () => {
- history.push(`/crop/${variety_id}/${management_plan_id}/complete_management_plan`);
- };
- const onAbandon = () =>
- history.push(`/crop/${variety_id}/${management_plan_id}/abandon_management_plan`);
-
- const showSpotlight = history.location.state?.fromCreation;
-
- const pendingTasks = useSelector(pendingTasksByManagementPlanIdSelector(management_plan_id));
- const taskCardContents = useSelector(taskCardContentByManagementPlanSelector(management_plan_id));
- return (
- <>
-
- {taskCardContents.map((task) => (
- history.push(`/tasks/${task.task_id}/read_only`)}
- style={{ marginBottom: '14px' }}
- {...task}
- />
- ))}
-
- {showSpotlight && }
- >
- );
-}
diff --git a/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.jsx b/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.jsx
new file mode 100644
index 0000000000..caac6a4a06
--- /dev/null
+++ b/packages/webapp/src/containers/Crop/ManagementDetail/ManagementTasks.jsx
@@ -0,0 +1,83 @@
+import PureManagementTasks from '../../../components/Crop/ManagementDetail/ManagementPlanTasks';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+import { isAdminSelector } from '../../userFarmSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import FirstManagementPlanSpotlight from './FirstManagementPlanSpotlight';
+import {
+ pendingTasksByManagementPlanIdSelector,
+ tasksByManagementPlanIdSelector,
+} from '../../taskSlice';
+import TaskCard from '../../Task/TaskCard';
+import React, { useEffect } from 'react';
+import { taskCardContentByManagementPlanSelector } from '../../Task/taskCardContentSelector';
+import { onAddTask } from '../../Task/onAddTask';
+import { getManagementPlansAndTasks } from '../../saga';
+
+export default function ManagementTasks({ history, match, location }) {
+ const dispatch = useDispatch();
+ const variety_id = match.params.variety_id;
+ const variety = useSelector(cropVarietySelector(variety_id));
+
+ const management_plan_id = match.params.management_plan_id;
+ const plan = useSelector(managementPlanSelector(management_plan_id));
+ const isAdmin = useSelector(isAdminSelector);
+
+ useEffect(() => {
+ dispatch(getManagementPlansAndTasks());
+ }, []);
+
+ const onBack = () => {
+ history.push(`/crop/${variety_id}/management`, location?.state);
+ };
+
+ const onCompleted = () => {
+ history.push(
+ `/crop/${variety_id}/${management_plan_id}/complete_management_plan`,
+ location?.state,
+ );
+ };
+ const onAbandon = () =>
+ history.push(
+ `/crop/${variety_id}/${management_plan_id}/abandon_management_plan`,
+ location?.state,
+ );
+
+ const showSpotlight = history.location.state?.fromCreation;
+
+ const pendingTasks = useSelector(pendingTasksByManagementPlanIdSelector(management_plan_id));
+ const taskCardContents = useSelector(taskCardContentByManagementPlanSelector(management_plan_id));
+
+ return (
+ <>
+
+ {taskCardContents.map((task) => (
+
+ history.push(`/tasks/${task.task_id}/read_only`, { pathname: location.pathname })
+ }
+ style={{ marginBottom: '14px' }}
+ {...task}
+ />
+ ))}
+
+ {showSpotlight && }
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Crop/saga.js b/packages/webapp/src/containers/Crop/saga.js
index 54869cd9e4..2e306111fc 100644
--- a/packages/webapp/src/containers/Crop/saga.js
+++ b/packages/webapp/src/containers/Crop/saga.js
@@ -16,7 +16,12 @@
import { call, put, select, takeLatest, takeLeading } from 'redux-saga/effects';
import apiConfig from '../../apiConfig';
import { loginSelector, patchFarmSuccess } from '../userFarmSlice';
-import { axios, getHeader, getManagementPlanAndPlantingMethodSuccessSaga, onReqSuccessSaga } from '../saga';
+import {
+ axios,
+ getHeader,
+ getManagementPlanAndPlantingMethodSuccessSaga,
+ onReqSuccessSaga,
+} from '../saga';
import { createAction } from '@reduxjs/toolkit';
import {
deleteManagementPlanSuccess,
@@ -85,8 +90,8 @@ export function* patchFarmDefaultInitialLocationSaga({ payload: farm }) {
header,
);
yield put(patchFarmSuccess({ ...farm, farm_id, user_id }));
- } catch (e) {
- }
+ // eslint-disable-next-line no-empty
+ } catch (e) {}
}
export const patchManagementPlan = createAction(`patchManagementPlanSaga`);
diff --git a/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.js b/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.js
deleted file mode 100644
index 6664298130..0000000000
--- a/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import JoyrideWrapper from '../../components/JoyrideWrapper';
-import { useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../showedSpotlightSlice';
-import { setSpotlightToShown } from '../Map/saga';
-import React from 'react';
-
-export default function CatalogSpotlight() {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { crop_catalog } = useSelector(showedSpotlightSelector);
- const onFinish = () => dispatch(setSpotlightToShown('crop_catalog'));
- return (
- <>
- {!crop_catalog && (
- <>
-
-
- >
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.jsx b/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.jsx
new file mode 100644
index 0000000000..1fd70e4408
--- /dev/null
+++ b/packages/webapp/src/containers/CropCatalogue/CatalogSpotlight.jsx
@@ -0,0 +1,43 @@
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { showedSpotlightSelector } from '../showedSpotlightSlice';
+import { setSpotlightToShown } from '../Map/saga';
+import React from 'react';
+import { TourProviderWrapper } from '../../components/TourProviderWrapper/TourProviderWrapper';
+
+export default function CatalogSpotlight() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { crop_catalog } = useSelector(showedSpotlightSelector);
+ const onFinish = () => dispatch(setSpotlightToShown('crop_catalog'));
+ return
+
+ ;
+
+}
diff --git a/packages/webapp/src/containers/CropCatalogue/index.js b/packages/webapp/src/containers/CropCatalogue/index.js
deleted file mode 100644
index 1d8daa2009..0000000000
--- a/packages/webapp/src/containers/CropCatalogue/index.js
+++ /dev/null
@@ -1,213 +0,0 @@
-import Layout from '../../components/Layout';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../../components/PageTitle/v2';
-import PageBreak from '../../components/PageBreak';
-import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
-import CropStatusInfoBox from '../../components/CropCatalogue/CropStatusInfoBox';
-import { AddLink, Semibold, Text } from '../../components/Typography';
-import { useDispatch, useSelector } from 'react-redux';
-import { cropsSelector } from '../cropSlice';
-import useCropTileListGap from '../../components/CropTile/useCropTileListGap';
-import PureCropTile from '../../components/CropTile';
-import PureCropTileContainer from '../../components/CropTile/CropTileContainer';
-import React, { useEffect, useState } from 'react';
-import { getCropsAndManagementPlans } from '../saga';
-import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
-import CropCatalogueFilterPage from '../Filter/CropCatalogue';
-import {
- cropCatalogueFilterDateSelector,
- cropCatalogueFilterSelector,
- isFilterCurrentlyActiveSelector,
- setCropCatalogueFilterDate,
-} from '../filterSlice';
-import { isAdminSelector } from '../userFarmSlice';
-import useCropCatalogue from './useCropCatalogue';
-import useStringFilteredCrops from './useStringFilteredCrops';
-import useSortByCropTranslation from './useSortByCropTranslation';
-import { resetAndUnLockFormData, setPersistedPaths } from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import CatalogSpotlight from './CatalogSpotlight';
-import ActiveFilterBox from '../../components/ActiveFilterBox';
-import { useStartAddCropVarietyFlow } from '../CropVarieties/useStartAddCropVarietyFlow';
-
-export default function CropCatalogue({ history }) {
- const { t } = useTranslation();
- const isAdmin = useSelector(isAdminSelector);
- const dispatch = useDispatch();
-
- const [filterString, setFilterString] = useState('');
- const filterStringOnChange = (e) => setFilterString(e.target.value);
- const {
- active,
- planned,
- past,
- sum,
- cropCatalogue,
- filteredCropsWithoutManagementPlan,
- } = useCropCatalogue(filterString);
- const crops = useStringFilteredCrops(
- useSortByCropTranslation(useSelector(cropsSelector)),
- filterString,
- );
- const { ref: containerRef, gap, padding, cardWidth } = useCropTileListGap([sum, crops.length]);
- useEffect(() => {
- dispatch(getCropsAndManagementPlans());
- }, []);
-
- const [isFilterOpen, setIsFilterOpen] = useState(false);
- const onFilterClose = () => {
- setIsFilterOpen(false);
- };
- const onFilterOpen = () => {
- setIsFilterOpen(true);
- };
-
- const date = useSelector(cropCatalogueFilterDateSelector);
- const setDate = (date) => dispatch(setCropCatalogueFilterDate(date));
-
- const cropCatalogueFilter = useSelector(cropCatalogueFilterSelector);
- const isFilterCurrentlyActive = useSelector(isFilterCurrentlyActiveSelector('cropCatalogue'));
-
- useEffect(() => {
- dispatch(resetAndUnLockFormData());
- }, []);
-
- const { onAddCropVariety } = useStartAddCropVarietyFlow();
- const onAddCrop = () => {
- dispatch(setPersistedPaths([
- '/crop/new',
- '/crop/new/add_crop_variety',
- '/crop/new/add_crop_variety/compliance',
- ]));
- history.push('/crop/new');
- };
- return (
-
-
-
-
-
-
-
-
- {isFilterCurrentlyActive && (
-
- )}
-
-
- {!!(sum + filteredCropsWithoutManagementPlan.length) ? (
- <>
-
-
-
- {filteredCropsWithoutManagementPlan.map((cropVariety) => {
- const { crop_translation_key, crop_photo_url, crop_id } = cropVariety;
- const imageKey = cropVariety.crop_translation_key?.toLowerCase();
-
- return (
- history.push(`/crop_varieties/crop/${cropVariety.crop_id}`)}
- needsPlan
- />
- );
- })}
- {cropCatalogue.map((cropCatalog) => {
- const {
- crop_translation_key,
- active,
- planned,
- past,
- imageKey,
- crop_photo_url,
- crop_id,
- needsPlan,
- } = cropCatalog;
-
- return (
- history.push(`/crop_varieties/crop/${cropCatalog.crop_id}`)}
- />
- );
- })}
-
- >
- ) : (
- isFilterCurrentlyActive && (
-
- {t('CROP_CATALOGUE.NO_RESULTS_FOUND')}
-
- )
- )}
- {isAdmin && !isFilterCurrentlyActive && (
- <>
- {!!crops?.length && (
- <>
-
-
- {crops.map((crop) => {
- const { crop_translation_key } = crop;
- const imageKey = crop_translation_key?.toLowerCase();
- return (
- {
- onAddCropVariety(crop.crop_id);
- }}
- />
- );
- })}
-
- >
- )}
-
{t('CROP_CATALOGUE.CAN_NOT_FIND')}
-
- {t('CROP_CATALOGUE.ADD_CROP')}
-
- >
- )}
-
-
- );
-}
diff --git a/packages/webapp/src/containers/CropCatalogue/index.jsx b/packages/webapp/src/containers/CropCatalogue/index.jsx
new file mode 100644
index 0000000000..103d9a1f3e
--- /dev/null
+++ b/packages/webapp/src/containers/CropCatalogue/index.jsx
@@ -0,0 +1,213 @@
+import Layout from '../../components/Layout';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../components/PageTitle/v2';
+import PageBreak from '../../components/PageBreak';
+import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
+import CropStatusInfoBox from '../../components/CropCatalogue/CropStatusInfoBox';
+import { AddLink, Semibold, Text } from '../../components/Typography';
+import { useDispatch, useSelector } from 'react-redux';
+import { cropsSelector } from '../cropSlice';
+import useCropTileListGap from '../../components/CropTile/useCropTileListGap';
+import PureCropTile from '../../components/CropTile';
+import PureCropTileContainer from '../../components/CropTile/CropTileContainer';
+import React, { useEffect, useState } from 'react';
+import { getCropsAndManagementPlans } from '../saga';
+import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
+import CropCatalogueFilterPage from '../Filter/CropCatalogue';
+import {
+ cropCatalogueFilterDateSelector,
+ cropCatalogueFilterSelector,
+ isFilterCurrentlyActiveSelector,
+ setCropCatalogueFilterDate,
+} from '../filterSlice';
+import { isAdminSelector } from '../userFarmSlice';
+import useCropCatalogue from './useCropCatalogue';
+import useStringFilteredCrops from './useStringFilteredCrops';
+import useSortByCropTranslation from './useSortByCropTranslation';
+import {
+ resetAndUnLockFormData,
+ setPersistedPaths,
+} from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import CatalogSpotlight from './CatalogSpotlight';
+import ActiveFilterBox from '../../components/ActiveFilterBox';
+import { useStartAddCropVarietyFlow } from '../CropVarieties/useStartAddCropVarietyFlow';
+
+export default function CropCatalogue({ history }) {
+ const { t } = useTranslation();
+ const isAdmin = useSelector(isAdminSelector);
+ const dispatch = useDispatch();
+
+ const [filterString, setFilterString] = useState('');
+ const filterStringOnChange = (e) => setFilterString(e.target.value);
+ const { active, planned, past, noPlans, sum, cropCatalogue, filteredCropsWithoutManagementPlan } =
+ useCropCatalogue(filterString);
+ const crops = useStringFilteredCrops(
+ useSortByCropTranslation(useSelector(cropsSelector)),
+ filterString,
+ );
+ const { ref: containerRef, gap, padding, cardWidth } = useCropTileListGap([sum, crops.length]);
+ useEffect(() => {
+ dispatch(getCropsAndManagementPlans());
+ }, []);
+
+ const [isFilterOpen, setIsFilterOpen] = useState(false);
+ const onFilterClose = () => {
+ setIsFilterOpen(false);
+ };
+ const onFilterOpen = () => {
+ setIsFilterOpen(true);
+ };
+
+ const date = useSelector(cropCatalogueFilterDateSelector);
+ const setDate = (date) => dispatch(setCropCatalogueFilterDate(date));
+
+ const cropCatalogueFilter = useSelector(cropCatalogueFilterSelector);
+ const isFilterCurrentlyActive = useSelector(isFilterCurrentlyActiveSelector('cropCatalogue'));
+
+ useEffect(() => {
+ dispatch(resetAndUnLockFormData());
+ }, []);
+
+ const { onAddCropVariety } = useStartAddCropVarietyFlow();
+ const onAddCrop = () => {
+ dispatch(
+ setPersistedPaths([
+ '/crop/new',
+ '/crop/new/add_crop_variety',
+ '/crop/new/add_crop_variety/compliance',
+ ]),
+ );
+ history.push('/crop/new');
+ };
+ return (
+
+
+
+
+
+
+
+
+ {isFilterCurrentlyActive && (
+
+ )}
+
+
+ {sum + filteredCropsWithoutManagementPlan.length ? (
+ <>
+
+
+
+ {filteredCropsWithoutManagementPlan.map((cropVariety) => {
+ const { crop_translation_key, crop_photo_url, crop_id, noPlansCount } = cropVariety;
+ const imageKey = cropVariety.crop_translation_key?.toLowerCase();
+
+ return (
+ history.push(`/crop_varieties/crop/${cropVariety.crop_id}`)}
+ cropCount={{
+ noPlans: noPlansCount,
+ }}
+ />
+ );
+ })}
+ {cropCatalogue.map((cropCatalog) => {
+ const {
+ crop_translation_key,
+ active,
+ planned,
+ past,
+ imageKey,
+ crop_photo_url,
+ crop_id,
+ needsPlan,
+ } = cropCatalog;
+
+ return (
+ history.push(`/crop_varieties/crop/${cropCatalog.crop_id}`)}
+ />
+ );
+ })}
+
+ >
+ ) : (
+ isFilterCurrentlyActive && (
+
+ {t('CROP_CATALOGUE.NO_RESULTS_FOUND')}
+
+ )
+ )}
+ {isAdmin && !isFilterCurrentlyActive && (
+ <>
+ {!!crops?.length && (
+ <>
+
+
+ {crops.map((crop) => {
+ const { crop_translation_key } = crop;
+ const imageKey = crop_translation_key?.toLowerCase();
+ return (
+ {
+ onAddCropVariety(crop.crop_id);
+ }}
+ />
+ );
+ })}
+
+ >
+ )}
+
{t('CROP_CATALOGUE.CAN_NOT_FIND')}
+
+ {t('CROP_CATALOGUE.ADD_CROP')}
+
+ >
+ )}
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/CropCatalogue/useCropCatalogue.js b/packages/webapp/src/containers/CropCatalogue/useCropCatalogue.js
index a745c95af9..874447e3b9 100644
--- a/packages/webapp/src/containers/CropCatalogue/useCropCatalogue.js
+++ b/packages/webapp/src/containers/CropCatalogue/useCropCatalogue.js
@@ -7,7 +7,15 @@ import { useSelector } from 'react-redux';
import { cropCatalogueFilterDateSelector, cropCatalogueFilterSelector } from '../filterSlice';
import { useMemo } from 'react';
import useStringFilteredCrops from './useStringFilteredCrops';
-import { ACTIVE, COMPLETE, LOCATION, PLANNED, STATUS, SUPPLIERS } from '../Filter/constants';
+import {
+ ACTIVE,
+ COMPLETE,
+ LOCATION,
+ PLANNED,
+ STATUS,
+ SUPPLIERS,
+ NEEDS_PLAN,
+} from '../Filter/constants';
import { useTranslation } from 'react-i18next';
import useFilterNoPlan from './useFilterNoPlan';
import useSortByCropTranslation from './useSortByCropTranslation';
@@ -24,6 +32,26 @@ export default function useCropCatalogue(filterString) {
filterString,
);
+ const filteredCropVarietiesWithoutManagementPlanByCropVariety = useSortByCropTranslation(
+ useFilterNoPlan(filterString, false),
+ );
+
+ // aggregates all crop varieties by crop id and counts the 'Need plans' count value.
+ const filteredCropVarietiesWithoutManagementPlan =
+ filteredCropVarietiesWithoutManagementPlanByCropVariety.reduce((acc, cropVariety) => {
+ if (acc.length === 0) {
+ acc.push({ ...cropVariety, noPlansCount: 1 });
+ } else {
+ let cropFound = acc.find((crop) => crop.crop_id === cropVariety.crop_id);
+ if (!cropFound) {
+ acc.push({ ...cropVariety, noPlansCount: 1 });
+ } else {
+ cropFound.noPlansCount += 1;
+ }
+ }
+ return acc;
+ }, []);
+
const managementPlansFilteredByLocations = useMemo(() => {
const locationFilter = cropCatalogueFilter[LOCATION];
const included = new Set();
@@ -74,7 +102,26 @@ export default function useCropCatalogue(filterString) {
managementPlansByCropId[managementPlan.crop_id][status].push(managementPlan);
}
}
- return Object.values(managementPlansByCropId);
+ // calcluates the needs plans values from crop varieties without management plan
+ // and merges it with the crop with the management plan
+ const managementPlansByCropIdWithNoPlans = Object.values(managementPlansByCropId).reduce(
+ (acc, currentValue) => {
+ const noPlanFoundCrop = filteredCropVarietiesWithoutManagementPlanByCropVariety.filter(
+ (np) => np.crop_id === currentValue.crop_id,
+ );
+ if (!noPlanFoundCrop) {
+ acc.push({ ...currentValue, noPlans: [] });
+ } else {
+ acc.push({
+ ...currentValue,
+ noPlans: noPlanFoundCrop.map((c) => ({ crop_variety_name: c.crop_variety_name })),
+ });
+ }
+ return acc;
+ },
+ [],
+ );
+ return managementPlansByCropIdWithNoPlans;
}, [managementPlansFilteredBySuppliers, cropCatalogFilterDate]);
const cropCatalogueFilteredByStatus = useMemo(() => {
@@ -89,25 +136,17 @@ export default function useCropCatalogue(filterString) {
active: statusFilter[ACTIVE].active ? catalogue.active : [],
planned: statusFilter[PLANNED].active ? catalogue.planned : [],
past: statusFilter[COMPLETE].active ? catalogue.past : [],
+ noPlans: statusFilter[NEEDS_PLAN].active ? catalogue.noPlans : [],
}));
return newCropCatalogue.filter(
- (catalog) => catalog.active.length || catalog.past.length || catalog.planned.length,
+ (catalog) =>
+ catalog.active.length ||
+ catalog.past.length ||
+ catalog.planned.length ||
+ catalog.noPlans.length,
);
}, [cropCatalogueFilter[STATUS], cropCatalogue]);
- const cropCataloguesStatus = useMemo(() => {
- const cropCataloguesStatus = { active: 0, planned: 0, past: 0 };
- for (const managementPlansByStatus of cropCatalogueFilteredByStatus) {
- for (const status in cropCataloguesStatus) {
- cropCataloguesStatus[status] += managementPlansByStatus[status].length;
- }
- }
- return {
- ...cropCataloguesStatus,
- sum: cropCataloguesStatus.active + cropCataloguesStatus.planned + cropCataloguesStatus.past,
- };
- }, [cropCatalogueFilteredByStatus]);
-
const { t } = useTranslation();
const onlyOneOfTwoNumberIsZero = (i, j) => i + j > 0 && i * j === 0;
const sortedCropCatalogue = useMemo(() => {
@@ -129,10 +168,6 @@ export default function useCropCatalogue(filterString) {
});
}, [cropCatalogueFilteredByStatus]);
- const filteredCropVarietiesWithoutManagementPlan = useSortByCropTranslation(
- useFilterNoPlan(filterString),
- );
-
const filteredCropsWithoutManagementPlan = useMemo(() => {
const cropIdsWithPlan = new Set(sortedCropCatalogue.map(({ crop_id }) => crop_id));
return filteredCropVarietiesWithoutManagementPlan.filter(
@@ -150,6 +185,30 @@ export default function useCropCatalogue(filterString) {
}));
}, [filteredCropVarietiesWithoutManagementPlan, sortedCropCatalogue]);
+ // this method is used to calculate the sum of active, planned, past, noPlans of all
+ // crop varieties for a particular crop.
+ // calculates the active, planned, past, noPlans for CropStatusInfoBox component.
+ const cropCataloguesStatus = useMemo(() => {
+ const cropCataloguesStatus = { active: 0, planned: 0, past: 0, noPlans: 0 };
+ for (const managementPlansByStatus of cropCatalogueFilteredByStatus) {
+ for (const status in cropCataloguesStatus) {
+ cropCataloguesStatus[status] += managementPlansByStatus[status].length;
+ }
+ }
+ cropCataloguesStatus.noPlans = filteredCropVarietiesWithoutManagementPlan.reduce((acc, c) => {
+ acc += c.noPlansCount;
+ return acc;
+ }, 0);
+ return {
+ ...cropCataloguesStatus,
+ sum:
+ cropCataloguesStatus.active +
+ cropCataloguesStatus.planned +
+ cropCataloguesStatus.past +
+ cropCataloguesStatus.noPlans,
+ };
+ }, [cropCatalogueFilteredByStatus, filteredCropVarietiesWithoutManagementPlan]);
+
return {
cropCatalogue: sortedCropCatalogueWithNeedsPlanProp,
filteredCropsWithoutManagementPlan,
diff --git a/packages/webapp/src/containers/CropCatalogue/useFilterNoPlan.js b/packages/webapp/src/containers/CropCatalogue/useFilterNoPlan.js
index 4837914fd6..8a80d7db2a 100644
--- a/packages/webapp/src/containers/CropCatalogue/useFilterNoPlan.js
+++ b/packages/webapp/src/containers/CropCatalogue/useFilterNoPlan.js
@@ -11,7 +11,7 @@ import {
} from '../managementPlanSlice';
import { cropVarietiesSelector } from '../cropVarietySlice';
-export default function useFilterNoPlan(filterString) {
+export default function useFilterNoPlan(filterString, isCropSpecific = true) {
const managementPlans = useSelector(managementPlansSelector);
const cropVarieties = useSelector(cropVarietiesSelector);
const cropCatalogueFilter = useSelector(cropCatalogueFilterSelector);
@@ -37,7 +37,7 @@ export default function useFilterNoPlan(filterString) {
varietiesFilteredByString.filter(
(cropVariety) => !cropVarietyIds.has(cropVariety.crop_variety_id),
),
- 'crop_id',
+ isCropSpecific ? 'crop_id' : 'crop_variety_id',
);
}, [managementPlans, varietiesFilteredByString]);
diff --git a/packages/webapp/src/containers/CropCatalogue/useSortByCropTranslation.js b/packages/webapp/src/containers/CropCatalogue/useSortByCropTranslation.js
index edbfe3b89d..cd2c621d46 100644
--- a/packages/webapp/src/containers/CropCatalogue/useSortByCropTranslation.js
+++ b/packages/webapp/src/containers/CropCatalogue/useSortByCropTranslation.js
@@ -5,8 +5,16 @@ export default function useSortByCropTranslation(crops) {
const { t } = useTranslation();
return useMemo(() => {
return crops.sort((crop_i, crop_j) =>
- t(`crop:${crop_i.crop_translation_key}`).toLowerCase() >
- t(`crop:${crop_j.crop_translation_key}`).toLowerCase()
+ t(`crop:${crop_i.crop_translation_key}`)
+ .toLowerCase()
+ .normalize('NFD')
+ .replace(/\W/g, '')
+ .trim() >
+ t(`crop:${crop_j.crop_translation_key}`)
+ .toLowerCase()
+ .normalize('NFD')
+ .replace(/\W/g, '')
+ .trim()
? 1
: -1,
);
diff --git a/packages/webapp/src/containers/CropCatalogue/useStringFilteredCrops.js b/packages/webapp/src/containers/CropCatalogue/useStringFilteredCrops.js
index 2f837648a2..db2514db82 100644
--- a/packages/webapp/src/containers/CropCatalogue/useStringFilteredCrops.js
+++ b/packages/webapp/src/containers/CropCatalogue/useStringFilteredCrops.js
@@ -4,19 +4,36 @@ import { useTranslation } from 'react-i18next';
export default function useStringFilteredCrops(crops, filterString) {
const { t } = useTranslation();
return useMemo(() => {
- const lowerCaseFilter = filterString?.toLowerCase() || '';
+ const lowerCaseFilter =
+ filterString
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .replace(/\W/g, '')
+ .replace(/_/g, '')
+ .trim() || '';
const check = (names) => {
for (const name of names) {
- if (name?.toLowerCase().includes(lowerCaseFilter)) return true;
+ if (
+ name
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .replace(/\W/g, '')
+ .replace(/_/g, '')
+ .trim()
+ .includes(lowerCaseFilter)
+ )
+ return true;
}
return false;
};
+ // These fields can be used in future.
+ // Hence, keeping it in the comments
+ // use it in the check function argument.
+ // crop?.crop_common_name,
return crops.filter((crop) =>
- check([
- crop?.crop_common_name,
- crop?.crop_variety_name,
- t(`crop:${crop.crop_translation_key}`),
- ]),
+ check([crop?.crop_variety_name, t(`crop:${crop.crop_translation_key}`)]),
);
}, [crops, filterString]);
}
diff --git a/packages/webapp/src/containers/CropVarieties/index.js b/packages/webapp/src/containers/CropVarieties/index.js
deleted file mode 100644
index 22b93ffcc2..0000000000
--- a/packages/webapp/src/containers/CropVarieties/index.js
+++ /dev/null
@@ -1,272 +0,0 @@
-import Layout from '../../components/Layout';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../../components/PageTitle/v2';
-import PageBreak from '../../components/PageBreak';
-import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
-import { AddLink, Semibold } from '../../components/Typography';
-import { useDispatch, useSelector } from 'react-redux';
-import { cropSelector } from '../cropSlice';
-import {
- cropVarietiesWithoutManagementPlanByCropIdSelector,
- currentCropVarietiesByCropIdSelector,
- expiredCropVarietiesByCropIdSelector,
- plannedCropVarietiesByCropIdSelector,
-} from '../managementPlanSlice';
-import useCropTileListGap from '../../components/CropTile/useCropTileListGap';
-import PureCropTile from '../../components/CropTile';
-import PureCropTileContainer from '../../components/CropTile/CropTileContainer';
-import { useEffect, useState } from 'react';
-import { getCropVarieties } from '../saga';
-import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
-import {
- cropCatalogueFilterDateSelector,
- cropVarietyFilterSelector,
- isFilterCurrentlyActiveSelector,
- setCropCatalogueFilterDate,
-} from '../filterSlice';
-import { isAdminSelector } from '../userFarmSlice';
-import useStringFilteredCrops from '../CropCatalogue/useStringFilteredCrops';
-import useSortByVarietyName from './useSortByVarietyName';
-import { resetAndUnLockFormData } from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import CropVarietyFilterPage from '../Filter/CropVariety';
-import ActiveFilterBox from '../../components/ActiveFilterBox';
-import useFilterVarieties from '../CropCatalogue/useFilterVarieties';
-import { ACTIVE, COMPLETE, NEEDS_PLAN, PLANNED } from '../Filter/constants';
-import { useStartAddCropVarietyFlow } from './useStartAddCropVarietyFlow';
-
-export default function CropVarieties({ history, match }) {
- const { t } = useTranslation();
- const isAdmin = useSelector(isAdminSelector);
- const dispatch = useDispatch();
- const crop_id = Number(match.params.crop_id);
- const crop = useSelector(cropSelector(crop_id));
-
- const [filterString, setFilterString] = useState('');
- const filterStringOnChange = (e) => setFilterString(e.target.value);
-
- const cropVarietiesWithoutManagementPlan = useFilterVarieties(
- useStringFilteredCrops(
- useSortByVarietyName(
- useSelector(cropVarietiesWithoutManagementPlanByCropIdSelector(crop_id)),
- ),
- filterString,
- ),
- crop_id,
- NEEDS_PLAN,
- );
- const currentCropVarieties = useFilterVarieties(
- useStringFilteredCrops(
- useSortByVarietyName(useSelector(currentCropVarietiesByCropIdSelector(crop_id))),
- filterString,
- ),
- crop_id,
- ACTIVE,
- );
- const plannedCropVarieties = useFilterVarieties(
- useStringFilteredCrops(
- useSortByVarietyName(useSelector(plannedCropVarietiesByCropIdSelector(crop_id))),
- filterString,
- ),
- crop_id,
- PLANNED,
- );
- const expiredCropVarieties = useFilterVarieties(
- useStringFilteredCrops(
- useSortByVarietyName(useSelector(expiredCropVarietiesByCropIdSelector(crop_id))),
- filterString,
- ),
- crop_id,
- COMPLETE,
- );
- const { ref: containerRef, gap, padding, cardWidth } = useCropTileListGap([
- currentCropVarieties.length,
- plannedCropVarieties.length,
- expiredCropVarieties.length,
- cropVarietiesWithoutManagementPlan.length,
- ]);
- useEffect(() => {
- dispatch(getCropVarieties());
- }, []);
-
- const [isFilterOpen, setIsFilterOpen] = useState(false);
- const onFilterClose = () => {
- setIsFilterOpen(false);
- };
- const onFilterOpen = () => {
- setIsFilterOpen(true);
- };
-
- const date = useSelector(cropCatalogueFilterDateSelector);
- const setDate = (date) => dispatch(setCropCatalogueFilterDate(date));
-
- const onGoBack = () => history.push('/crop_catalogue');
-
- const goToVarietyManagement = (varietyId) => {
- history.push(`/crop/${varietyId}/management`);
- };
-
- const { onAddCropVariety } = useStartAddCropVarietyFlow();
- const goToVarietyCreation = () => {
- onAddCropVariety(crop_id);
- };
-
- const cropVarietyFilter = useSelector(cropVarietyFilterSelector(crop_id));
- const isFilterCurrentlyActive = useSelector(isFilterCurrentlyActiveSelector(crop_id));
-
- useEffect(() => {
- dispatch(resetAndUnLockFormData());
- }, []);
-
- return (
-
-
-
-
-
-
-
- {isFilterCurrentlyActive && (
-
- )}
-
- {/* */}
-
-
- {!!cropVarietiesWithoutManagementPlan.length && (
- <>
-
-
- {cropVarietiesWithoutManagementPlan.map((cropVariety) => {
- const {
- crop_translation_key,
- crop_variety_name,
- crop_variety_id,
- crop_variety_photo_url,
- } = cropVariety;
- const imageKey = crop_translation_key.toLowerCase();
- return (
- goToVarietyManagement(crop_variety_id)}
- />
- );
- })}
-
- >
- )}
-
- {!!currentCropVarieties.length && (
- <>
-
-
- {currentCropVarieties.map((cropVariety) => {
- const {
- crop_translation_key,
- crop_variety_name,
- crop_variety_id,
- crop_variety_photo_url,
- } = cropVariety;
- const imageKey = crop_translation_key.toLowerCase();
- return (
- goToVarietyManagement(crop_variety_id)}
- />
- );
- })}
-
- >
- )}
-
- {!!plannedCropVarieties.length && (
- <>
-
-
- {plannedCropVarieties.map((cropVariety) => {
- const {
- crop_translation_key,
- crop_variety_name,
- crop_variety_id,
- crop_variety_photo_url,
- } = cropVariety;
- const imageKey = crop_translation_key.toLowerCase();
- return (
- goToVarietyManagement(crop_variety_id)}
- />
- );
- })}
-
- >
- )}
-
- {!!expiredCropVarieties.length && (
- <>
-
-
- {expiredCropVarieties.map((cropVariety) => {
- const {
- crop_translation_key,
- crop_variety_name,
- crop_variety_id,
- crop_variety_photo_url,
- } = cropVariety;
- const imageKey = crop_translation_key.toLowerCase();
- return (
- goToVarietyManagement(crop_variety_id)}
- isPastVariety
- />
- );
- })}
-
- >
- )}
-
- {!cropVarietiesWithoutManagementPlan.length &&
- !currentCropVarieties.length &&
- !plannedCropVarieties.length &&
- !expiredCropVarieties.length &&
- isFilterCurrentlyActive && (
-
- {t('CROP_CATALOGUE.NO_RESULTS_FOUND')}
-
- )}
-
-
- {isAdmin && !isFilterCurrentlyActive && (
- {t('CROP_VARIETIES.ADD_VARIETY')}
- )}
-
- );
-}
diff --git a/packages/webapp/src/containers/CropVarieties/index.jsx b/packages/webapp/src/containers/CropVarieties/index.jsx
new file mode 100644
index 0000000000..cae3a62818
--- /dev/null
+++ b/packages/webapp/src/containers/CropVarieties/index.jsx
@@ -0,0 +1,193 @@
+import Layout from '../../components/Layout';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../components/PageTitle/v2';
+import PageBreak from '../../components/PageBreak';
+import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
+import { AddLink, Semibold } from '../../components/Typography';
+import { useDispatch, useSelector } from 'react-redux';
+import { cropSelector } from '../cropSlice';
+import useCropTileListGap from '../../components/CropTile/useCropTileListGap';
+import PureCropTile from '../../components/CropTile';
+import PureCropTileContainer from '../../components/CropTile/CropTileContainer';
+import { useEffect, useState } from 'react';
+import { getCropVarieties } from '../saga';
+import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
+import {
+ cropCatalogueFilterDateSelector,
+ cropVarietyFilterSelector,
+ isFilterCurrentlyActiveSelector,
+ setCropCatalogueFilterDate,
+} from '../filterSlice';
+import { isAdminSelector } from '../userFarmSlice';
+import { resetAndUnLockFormData } from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import CropVarietyFilterPage from '../Filter/CropVariety';
+import ActiveFilterBox from '../../components/ActiveFilterBox';
+import { useStartAddCropVarietyFlow } from './useStartAddCropVarietyFlow';
+import useCropVarietyCatalogue from './useCropVarietyCatalogue';
+import CropStatusInfoBox from '../../components/CropCatalogue/CropStatusInfoBox';
+
+export default function CropVarieties({ history, match, location }) {
+ const { t } = useTranslation();
+ const isAdmin = useSelector(isAdminSelector);
+ const dispatch = useDispatch();
+ const crop_id = Number(match.params.crop_id);
+ const crop = useSelector(cropSelector(crop_id));
+
+ const [filterString, setFilterString] = useState('');
+ const filterStringOnChange = (e) => setFilterString(e.target.value);
+
+ const cropCatalogueFilter = useSelector(cropVarietyFilterSelector(crop_id));
+ const isFilterCurrentlyActive = useSelector(isFilterCurrentlyActiveSelector(crop_id));
+
+ useEffect(() => {
+ dispatch(resetAndUnLockFormData());
+ }, []);
+
+ const { active, planned, past, noPlans, sum, cropCatalogue, filteredCropsWithoutManagementPlan } =
+ useCropVarietyCatalogue(filterString, crop_id);
+
+ const {
+ ref: containerRef,
+ gap,
+ padding,
+ cardWidth,
+ } = useCropTileListGap([sum, cropCatalogue.length]);
+
+ useEffect(() => {
+ dispatch(getCropVarieties());
+ }, []);
+
+ const [isFilterOpen, setIsFilterOpen] = useState(false);
+ const onFilterClose = () => {
+ setIsFilterOpen(false);
+ };
+ const onFilterOpen = () => {
+ setIsFilterOpen(true);
+ };
+
+ const date = useSelector(cropCatalogueFilterDateSelector);
+ const setDate = (date) => dispatch(setCropCatalogueFilterDate(date));
+
+ const onGoBack = () => history.push('/crop_catalogue');
+
+ const goToVarietyManagement = (varietyId) => {
+ history.push(`/crop/${varietyId}/management`, { returnPath: location.pathname });
+ };
+
+ const { onAddCropVariety } = useStartAddCropVarietyFlow();
+ const goToVarietyCreation = () => {
+ onAddCropVariety(crop_id);
+ };
+
+ return (
+
+
+
+
+
+
+
+ {isFilterCurrentlyActive && (
+
+ )}
+
+ {/* */}
+
+
+ {!!(sum + filteredCropsWithoutManagementPlan.length) ? (
+ <>
+
+
+
+ {filteredCropsWithoutManagementPlan.map((cropVariety) => {
+ const {
+ crop_translation_key,
+ crop_photo_url,
+ crop_id,
+ crop_variety_name,
+ crop_variety_id,
+ noPlansCount,
+ } = cropVariety;
+ const imageKey = cropVariety.crop_translation_key?.toLowerCase();
+
+ return (
+ goToVarietyManagement(crop_variety_id)}
+ cropCount={{
+ noPlans: noPlansCount,
+ }}
+ />
+ );
+ })}
+ {cropCatalogue.map((cropCatalog) => {
+ const {
+ crop_translation_key,
+ active,
+ planned,
+ past,
+ imageKey,
+ crop_photo_url,
+ crop_id,
+ needsPlan,
+ noPlans,
+ noPlansCount,
+ crop_variety_name,
+ crop_variety_id,
+ } = cropCatalog;
+
+ return (
+ goToVarietyManagement(crop_variety_id)}
+ />
+ );
+ })}
+
+ >
+ ) : (
+ isFilterCurrentlyActive && (
+
+ {t('CROP_CATALOGUE.NO_RESULTS_FOUND')}
+
+ )
+ )}
+
+ {isAdmin && !isFilterCurrentlyActive && (
+ {t('CROP_VARIETIES.ADD_VARIETY')}
+ )}
+
+ );
+}
diff --git a/packages/webapp/src/containers/CropVarieties/useCropVarietyCatalogue.js b/packages/webapp/src/containers/CropVarieties/useCropVarietyCatalogue.js
new file mode 100644
index 0000000000..7b384e828d
--- /dev/null
+++ b/packages/webapp/src/containers/CropVarieties/useCropVarietyCatalogue.js
@@ -0,0 +1,268 @@
+import {
+ getCurrentManagementPlans,
+ getExpiredManagementPlans,
+ getPlannedManagementPlans,
+} from '../managementPlanSlice';
+import { useSelector } from 'react-redux';
+import { cropCatalogueFilterDateSelector, cropVarietyFilterSelector } from '../filterSlice';
+import { useMemo } from 'react';
+import useStringFilteredCrops from '../CropCatalogue/useStringFilteredCrops';
+import {
+ ACTIVE,
+ COMPLETE,
+ LOCATION,
+ PLANNED,
+ STATUS,
+ SUPPLIERS,
+ NEEDS_PLAN,
+} from '../Filter/constants';
+import { useTranslation } from 'react-i18next';
+import { useFilterNoPlanByCropId } from './useFilterNoPlan';
+import useSortByCropTranslation from '../CropCatalogue/useSortByCropTranslation';
+import { managementPlansWithCurrentLocationByCropIdSelector } from '../Task/TaskCrops/managementPlansWithLocationSelector';
+
+export default function useCropVarietyCatalogue(filterString, crop_id) {
+ const managementPlansWithCurrentLocationByCropId = useSelector(
+ managementPlansWithCurrentLocationByCropIdSelector(crop_id),
+ );
+
+ const cropCatalogFilterDate = useSelector(cropCatalogueFilterDateSelector);
+ let cropCatalogueFilter = useSelector(cropVarietyFilterSelector(crop_id));
+ const managementPlansFilteredByFilterString = useStringFilteredCrops(
+ managementPlansWithCurrentLocationByCropId,
+ filterString,
+ );
+ const withoutManagementPlanListByCropId = useSortByCropTranslation(
+ useFilterNoPlanByCropId(filterString, crop_id),
+ );
+
+ if (!cropCatalogueFilter) {
+ cropCatalogueFilter = {
+ [LOCATION]: {},
+ [SUPPLIERS]: {},
+ [STATUS]: {},
+ };
+ }
+
+ // location filter on management plan.
+ const managementPlansFilteredByLocations = useMemo(() => {
+ const locationFilter = cropCatalogueFilter[LOCATION];
+ const included = new Set();
+ for (const location_id in locationFilter) {
+ if (locationFilter[location_id].active) included.add(location_id);
+ }
+ if (included.size === 0) return managementPlansFilteredByFilterString;
+ return managementPlansFilteredByFilterString.filter((managementPlan) =>
+ included.has(managementPlan.location?.location_id),
+ );
+ }, [cropCatalogueFilter[LOCATION], managementPlansFilteredByFilterString]);
+
+ // suppliers filter on management plan.
+ const managementPlansFilteredBySuppliers = useMemo(() => {
+ const supplierFilter = cropCatalogueFilter[SUPPLIERS];
+ const included = new Set();
+ for (const supplier in supplierFilter) {
+ if (supplierFilter[supplier].active) included.add(supplier);
+ }
+ if (included.size === 0) return managementPlansFilteredByLocations;
+ return managementPlansFilteredByLocations.filter((managementPlan) =>
+ included.has(managementPlan.supplier),
+ );
+ }, [cropCatalogueFilter[SUPPLIERS], managementPlansFilteredByLocations]);
+
+ // crop varity list the contains active, planned, past and noPlans count.
+ const cropCatalogue = useMemo(() => {
+ const time = new Date(cropCatalogFilterDate).getTime();
+ const managementPlansByStatus = {
+ active: getCurrentManagementPlans(managementPlansFilteredBySuppliers, time),
+ planned: getPlannedManagementPlans(managementPlansFilteredBySuppliers, time),
+ past: getExpiredManagementPlans(managementPlansFilteredBySuppliers, time),
+ };
+ const managementPlansByCropId = {};
+ for (const status in managementPlansByStatus) {
+ for (const managementPlan of managementPlansByStatus[status]) {
+ if (!managementPlansByCropId.hasOwnProperty(managementPlan.crop_variety_id)) {
+ managementPlansByCropId[managementPlan.crop_variety_id] = {
+ active: [],
+ planned: [],
+ past: [],
+ crop_common_name: managementPlan.crop_common_name,
+ crop_translation_key: managementPlan.crop_translation_key,
+ imageKey: managementPlan.crop_translation_key?.toLowerCase(),
+ crop_id: managementPlan.crop_id,
+ crop_photo_url: managementPlan.crop_photo_url,
+ crop_variety_id: managementPlan.crop_variety_id,
+ crop_variety_name: managementPlan.crop_variety_name,
+ };
+ }
+
+ managementPlansByCropId[managementPlan.crop_variety_id][status].push(managementPlan);
+ }
+ }
+ // calcluates the needs plans values from crop varieties without management plan
+ // and merges it with the crop with the management plan
+ const managementPlansByCropIdWithNoPlans = Object.values(managementPlansByCropId).reduce(
+ (acc, currentValue) => {
+ const noPlanFoundCropVariety = withoutManagementPlanListByCropId.filter(
+ (np) => np.crop_variety_name.trim() === currentValue.crop_variety_name.trim(),
+ );
+ if (!noPlanFoundCropVariety) {
+ acc.push({ ...currentValue, noPlans: [] });
+ } else {
+ acc.push({ ...currentValue, noPlans: noPlanFoundCropVariety });
+ }
+ return acc;
+ },
+ [],
+ );
+ return managementPlansByCropIdWithNoPlans;
+ }, [managementPlansFilteredBySuppliers, cropCatalogFilterDate]);
+
+ // filter crop variety on the basis of active, planned, past and noPlan status.
+ const cropCatalogueFilteredByStatus = useMemo(() => {
+ const statusFilter = cropCatalogueFilter[STATUS];
+ const included = new Set();
+ for (const status in statusFilter) {
+ if (statusFilter[status].active) included.add(status);
+ }
+ if (included.size === 0) return cropCatalogue;
+ const newCropCatalogue = cropCatalogue.map((catalogue) => {
+ return {
+ ...catalogue,
+ active: statusFilter[ACTIVE].active ? catalogue.active : [],
+ planned: statusFilter[PLANNED].active ? catalogue.planned : [],
+ past: statusFilter[COMPLETE].active ? catalogue.past : [],
+ noPlans: statusFilter[NEEDS_PLAN].active ? catalogue.noPlans : [],
+ };
+ });
+ return newCropCatalogue.filter(
+ (catalog) =>
+ catalog.active.length ||
+ catalog.past.length ||
+ catalog.planned.length ||
+ catalog.noPlans.length,
+ );
+ }, [cropCatalogueFilter[STATUS], cropCatalogue]);
+
+ // sort the crop varieties on the basis of active, planned, past.
+ const { t } = useTranslation();
+ const onlyOneOfTwoNumberIsZero = (i, j) => i + j > 0 && i * j === 0;
+ const sortedCropCatalogue = useMemo(() => {
+ return cropCatalogueFilteredByStatus.sort((catalog_i, catalog_j) => {
+ if (onlyOneOfTwoNumberIsZero(catalog_i.active.length, catalog_j.active.length)) {
+ return catalog_j.active.length - catalog_i.active.length;
+ } else if (
+ onlyOneOfTwoNumberIsZero(catalog_i.planned.length, catalog_j.planned.length) &&
+ catalog_j.active.length === 0 &&
+ catalog_i.active.length === 0
+ ) {
+ return catalog_j.planned.length - catalog_i.planned.length;
+ } else {
+ return t(`crop:${catalog_i.crop_translation_key}`) >
+ t(`crop:${catalog_j.crop_translation_key}`)
+ ? 1
+ : -1;
+ }
+ });
+ }, [cropCatalogueFilteredByStatus]);
+
+ const filteredCropsWithoutManagementPlan = useMemo(() => {
+ const cropIdsWithPlan = new Set(
+ sortedCropCatalogue.map(({ crop_variety_id }) => crop_variety_id),
+ );
+ return withoutManagementPlanListByCropId.filter(
+ (cropVariety) => !cropIdsWithPlan.has(cropVariety.crop_variety_id),
+ );
+ }, [withoutManagementPlanListByCropId, sortedCropCatalogue]);
+
+ // used to create flag of no plans in the crop catalogue list.
+ const sortedCropCatalogueWithNeedsPlanProp = useMemo(() => {
+ const cropIdsWithoutPlan = new Set(
+ withoutManagementPlanListByCropId.map(({ crop_variety_id }) => crop_variety_id),
+ );
+ return sortedCropCatalogue.map((crop) => ({
+ ...crop,
+ needsPlan: cropIdsWithoutPlan.has(crop.crop_variety_id),
+ }));
+ }, [withoutManagementPlanListByCropId, sortedCropCatalogue]);
+
+ // to calculate no plans count for each crop that's not having any management plan.
+ const filteredCropsWithoutManagementPlanList = filteredCropsWithoutManagementPlan.reduce(
+ (acc, currentValue) => {
+ if (acc.length === 0) {
+ acc.push({ ...currentValue, noPlansCount: 1 });
+ } else {
+ let noPlanFoundCropVariety = acc.find((pre) => {
+ return pre.crop_variety_name === currentValue.crop_variety_name;
+ });
+ if (!noPlanFoundCropVariety) {
+ acc.push({ ...currentValue, noPlansCount: 1 });
+ } else {
+ const idx = acc.indexOf(noPlanFoundCropVariety);
+ acc[idx].noPlansCount += 1;
+ }
+ }
+ return acc;
+ },
+ [],
+ );
+
+ // aggregates the "with plan crop variety" list with the "no plan crop variety" list. this function takes the
+ // object from the "no plans crop variety" list and puts it into the "with plan crop variety" list if that crop
+ // variety is present in the "with plan crop variety" list along with the plans count.
+ const sortedCropCatalogueWithNeedsPlanPropList = sortedCropCatalogueWithNeedsPlanProp.reduce(
+ (acc, currentValue) => {
+ const noPlanFoundCropVariety = filteredCropsWithoutManagementPlanList.find(
+ (np) => np.crop_variety_name.trim() === currentValue.crop_variety_name.trim(),
+ );
+ const noPlanFoundCropVarietyIndex =
+ filteredCropsWithoutManagementPlanList.indexOf(noPlanFoundCropVariety);
+ if (!noPlanFoundCropVariety) {
+ acc.push({ ...currentValue, noPlansCount: 0 });
+ } else {
+ filteredCropsWithoutManagementPlanList.splice(noPlanFoundCropVarietyIndex, 1);
+ acc.push({ ...currentValue, noPlansCount: noPlanFoundCropVariety.noPlans });
+ }
+ return acc;
+ },
+ [],
+ );
+
+ // this method is used to calculate the sum of active, planned, past, noPlans of all
+ // crop varieties for a particular crop.
+ // Also, calculates the active, planned, past, noPlans for CropStatusInfoBox component
+ const cropCataloguesStatus = useMemo(() => {
+ const cropsWithoutManagementPlanCount = filteredCropsWithoutManagementPlanList.reduce(
+ (acc, c) => {
+ acc += c.noPlansCount;
+ return acc;
+ },
+ 0,
+ );
+ const cropCataloguesStatus = {
+ active: 0,
+ planned: 0,
+ past: 0,
+ noPlans: cropsWithoutManagementPlanCount,
+ };
+ for (const managementPlansByStatus of cropCatalogueFilteredByStatus) {
+ for (const status in cropCataloguesStatus) {
+ cropCataloguesStatus[status] += managementPlansByStatus[status].length;
+ }
+ }
+ return {
+ ...cropCataloguesStatus,
+ sum:
+ cropCataloguesStatus.active +
+ cropCataloguesStatus.planned +
+ cropCataloguesStatus.past +
+ cropCataloguesStatus.noPlans,
+ };
+ }, [cropCatalogueFilteredByStatus, filteredCropsWithoutManagementPlanList]);
+
+ return {
+ cropCatalogue: sortedCropCatalogueWithNeedsPlanPropList,
+ filteredCropsWithoutManagementPlan: filteredCropsWithoutManagementPlanList,
+ ...cropCataloguesStatus,
+ };
+}
diff --git a/packages/webapp/src/containers/CropVarieties/useFilterNoPlan.js b/packages/webapp/src/containers/CropVarieties/useFilterNoPlan.js
new file mode 100644
index 0000000000..df75fad31d
--- /dev/null
+++ b/packages/webapp/src/containers/CropVarieties/useFilterNoPlan.js
@@ -0,0 +1,73 @@
+import { useMemo } from 'react';
+import { useSelector } from 'react-redux';
+import { LOCATION, NEEDS_PLAN, STATUS, SUPPLIERS } from '../Filter/constants';
+import { cropVarietyFilterSelector } from '../filterSlice';
+import useStringFilteredCrops from '../CropCatalogue/useStringFilteredCrops';
+import useSortByCropTranslation from '../CropCatalogue/useSortByCropTranslation';
+import {
+ cropsWithVarietyWithoutManagementPlanSelector,
+ getUniqueEntities,
+ managementPlansSelector,
+} from '../managementPlanSlice';
+import { cropVarietiesSelector } from '../cropVarietySlice';
+
+export default function useFilterNoPlan(filterString, crop_id) {
+ const managementPlans = useSelector(managementPlansSelector);
+ const cropVarieties = useSelector(cropVarietiesSelector);
+ let cropCatalogueFilter = useSelector(cropVarietyFilterSelector(crop_id));
+
+ if (!cropCatalogueFilter) {
+ cropCatalogueFilter = {
+ [LOCATION]: {},
+ [SUPPLIERS]: {},
+ [STATUS]: {},
+ };
+ }
+
+ const varietiesFilteredBySupplier = useMemo(() => {
+ const supplierFilter = cropCatalogueFilter[SUPPLIERS];
+ const activeFilterSuppliers = new Set(
+ Object.keys(supplierFilter).filter((supplier) => supplierFilter[supplier].active),
+ );
+ return activeFilterSuppliers.size
+ ? cropVarieties.filter((crop) => activeFilterSuppliers.has(crop.supplier))
+ : cropVarieties;
+ }, [cropCatalogueFilter[SUPPLIERS], cropVarieties]);
+
+ const varietiesFilteredByString = useStringFilteredCrops(
+ useSortByCropTranslation(varietiesFilteredBySupplier),
+ filterString,
+ );
+
+ const cropsWithNoPlans = useMemo(() => {
+ const cropVarietyIds = new Set(managementPlans.map(({ crop_variety_id }) => crop_variety_id));
+ return getUniqueEntities(
+ varietiesFilteredByString.filter(
+ (cropVariety) => !cropVarietyIds.has(cropVariety.crop_variety_id),
+ ),
+ 'crop_variety_id',
+ );
+ }, [managementPlans, varietiesFilteredByString]);
+
+ const cropsFilteredByStatusAndLocation = useMemo(() => {
+ const locationFilter = cropCatalogueFilter[LOCATION];
+ for (const location in locationFilter) {
+ if (locationFilter[location].active) {
+ return [];
+ }
+ }
+
+ const statusFilter = cropCatalogueFilter[STATUS];
+ const activeFilterStatus = new Set(
+ Object.keys(statusFilter).filter((status) => statusFilter[status].active),
+ );
+ if (!statusFilter[NEEDS_PLAN]?.active && activeFilterStatus.size) return [];
+
+ return cropsWithNoPlans;
+ }, [cropsWithNoPlans, cropCatalogueFilter[STATUS], cropCatalogueFilter[LOCATION]]);
+
+ return cropsFilteredByStatusAndLocation;
+}
+
+export const useFilterNoPlanByCropId = (filterString, crop_id) =>
+ useFilterNoPlan(filterString, crop_id).filter((c) => c.crop_id === crop_id);
diff --git a/packages/webapp/src/containers/CustomSignUp/index.js b/packages/webapp/src/containers/CustomSignUp/index.js
deleted file mode 100644
index 4141ae1f2b..0000000000
--- a/packages/webapp/src/containers/CustomSignUp/index.js
+++ /dev/null
@@ -1,195 +0,0 @@
-import React, { Suspense, useEffect, useState } from 'react';
-import { useForm } from 'react-hook-form';
-import { useDispatch } from 'react-redux';
-import PureCustomSignUp from '../../components/CustomSignUp';
-import {
- customCreateUser,
- customLoginWithPassword,
- customSignUp,
- sendResetPasswordEmail,
-} from './saga';
-import history from '../../history';
-import Spinner from '../../components/Spinner';
-import { useTranslation } from 'react-i18next';
-import GoogleLoginButton from '../GoogleLoginButton';
-import {
- CREATE_USER_ACCOUNT,
- CUSTOM_SIGN_UP,
- ENTER_PASSWORD_PAGE,
- inlineErrors,
-} from './constants';
-import { isChrome } from '../../util';
-import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
-
-const ResetPassword = React.lazy(() => import('../ResetPassword'));
-const PureEnterPasswordPage = React.lazy(() => import('../../components/Signup/EnterPasswordPage'));
-const PureCreateUserAccount = React.lazy(() => import('../../components/CreateUserAccount'));
-
-const navbarCoverStyle = {
- backgroundColor: 'white',
- zIndex: 1,
- transform: 'translateY(-76px)',
- height: '76px',
- position: 'fixed',
- width: '100%',
-};
-
-const PureCustomSignUpStyle = {
- form: {
- zIndex: 2,
- },
-};
-
-function CustomSignUp() {
- const {
- register,
- handleSubmit,
- watch,
- setValue,
- setError,
-
- formState: { errors },
- } = useForm({
- mode: 'onTouched',
- });
- const { user, component: componentToShow } = history.location?.state || {};
- const validEmailRegex = RegExp(/^$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
- const EMAIL = 'email';
- const emailRegister = register(EMAIL, { pattern: validEmailRegex });
- const dispatch = useDispatch();
- const email = watch(EMAIL, undefined);
- const [showResetModal, setShowResetModal] = useState(false);
- const disabled = !email || !validEmailRegex.test(email);
- const showPureEnterPasswordPage = componentToShow === ENTER_PASSWORD_PAGE;
- const showPureCreateUserAccount = componentToShow === CREATE_USER_ACCOUNT;
- const showPureCustomSignUp = !showPureCreateUserAccount && !showPureEnterPasswordPage;
- const { t, i18n, ready } = useTranslation(['translation', 'common'], { useSuspense: false });
-
- const forgotPassword = () => {
- dispatch(sendResetPasswordEmail(email));
- setShowResetModal(true);
- };
- const dismissModal = () => {
- setShowResetModal(false);
- };
- useEffect(() => {
- const params = new URLSearchParams(history.location.search.substring(1));
- setValue(EMAIL, user?.email || params.get('email'));
- }, [user, setValue, ready]);
-
- useEffect(() => {
- if (
- componentToShow === ENTER_PASSWORD_PAGE &&
- i18n.language !== getLanguageFromLocalStorage()
- ) {
- i18n.changeLanguage(getLanguageFromLocalStorage());
- }
- }, [componentToShow]);
-
- const showSSOErrorAndRedirect = (error) => {
- //OC: Dynamically setting the error is not an option because of the need to reflect the key on the translation file
- const allMessages = {
- sso: t('SIGNUP.SSO_ERROR'),
- expired: t('SIGNUP.EXPIRED_ERROR'),
- invited: t('SIGNUP.INVITED_ERROR'),
- };
- const message = allMessages[error];
- setError(EMAIL, {
- type: 'manual',
- message,
- });
- if (error === inlineErrors.sso) {
- // TODO: Create custom google login button pass in React google login along with ref
- const googleLoginButton = document.getElementsByClassName('google-login-button')[0];
- googleLoginButton.click();
- }
- };
- const onSubmit = (data) => {
- const { email } = data;
- dispatch(customSignUp({ email: email?.toLowerCase(), showSSOError: showSSOErrorAndRedirect }));
- };
-
- const onSignUp = (user) => {
- dispatch(customCreateUser(user));
- };
-
- const onLogin = (password, showPasswordError) => {
- dispatch(customLoginWithPassword({ email, password, showPasswordError }));
- };
-
- const enterPasswordOnGoBack = () => {
- history.push({
- pathname: '/',
- component: CUSTOM_SIGN_UP,
- user: { email },
- });
- };
- const createUserAccountOnGoBack = () => {
- history.push({
- pathname: '/',
- component: CUSTOM_SIGN_UP,
- user: { email },
- });
- };
-
- const errorMessage = history.location.state?.error;
- return (
- <>
- }>
-
-
- {showResetModal && }
-
-
-
-
-
-
-
- }
- isChrome={isChrome()}
- errorMessage={errorMessage}
- inputs={[
- {
- label: t('SIGNUP.ENTER_EMAIL'),
- hookFormRegister: emailRegister,
- errors: errors[EMAIL] && (errors[EMAIL].message || t('SIGNUP.EMAIL_INVALID')),
- },
- ]}
- />
-
- >
- );
-}
-
-export default CustomSignUp;
-
-function Hidden({ children, isVisible }) {
- return (
-
- {children}
-
- );
-}
diff --git a/packages/webapp/src/containers/CustomSignUp/index.jsx b/packages/webapp/src/containers/CustomSignUp/index.jsx
new file mode 100644
index 0000000000..eed2873402
--- /dev/null
+++ b/packages/webapp/src/containers/CustomSignUp/index.jsx
@@ -0,0 +1,187 @@
+import React, { Suspense, useEffect, useState } from 'react';
+import { useForm } from 'react-hook-form';
+import { useDispatch } from 'react-redux';
+import PureCustomSignUp from '../../components/CustomSignUp';
+import { customCreateUser, customLoginWithPassword, customSignUp, sendResetPasswordEmail } from './saga';
+import history from '../../history';
+import Spinner from '../../components/Spinner';
+import { useTranslation } from 'react-i18next';
+import GoogleLoginButton from '../GoogleLoginButton';
+import { CREATE_USER_ACCOUNT, CUSTOM_SIGN_UP, ENTER_PASSWORD_PAGE, inlineErrors } from './constants';
+import { isChrome } from '../../util';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+
+const ResetPassword = React.lazy(() => import('../ResetPassword'));
+const PureEnterPasswordPage = React.lazy(() => import('../../components/Signup/EnterPasswordPage'));
+const PureCreateUserAccount = React.lazy(() => import('../../components/CreateUserAccount'));
+
+const navbarCoverStyle = {
+ backgroundColor: 'white',
+ zIndex: 1,
+ transform: 'translateY(-76px)',
+ height: '76px',
+ position: 'fixed',
+ width: '100%',
+};
+
+const PureCustomSignUpStyle = {
+ form: {
+ zIndex: 2,
+ },
+};
+
+function CustomSignUp() {
+ const {
+ register,
+ handleSubmit,
+ watch,
+ setValue,
+ setError,
+
+ formState: { errors },
+ } = useForm({
+ mode: 'onTouched',
+ });
+ const { user, component: componentToShow } = history.location?.state || {};
+ const validEmailRegex = RegExp(/^$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
+ const EMAIL = 'email';
+ const emailRegister = register(EMAIL, { pattern: validEmailRegex });
+ const dispatch = useDispatch();
+ const email = watch(EMAIL, undefined);
+ const [showResetModal, setShowResetModal] = useState(false);
+ const disabled = !email || !validEmailRegex.test(email);
+ const showPureEnterPasswordPage = componentToShow === ENTER_PASSWORD_PAGE;
+ const showPureCreateUserAccount = componentToShow === CREATE_USER_ACCOUNT;
+ const showPureCustomSignUp = !showPureCreateUserAccount && !showPureEnterPasswordPage;
+ const { t, i18n, ready } = useTranslation(['translation', 'common'], { useSuspense: false });
+
+ const forgotPassword = () => {
+ dispatch(sendResetPasswordEmail(email));
+ setShowResetModal(true);
+ };
+ const dismissModal = () => {
+ setShowResetModal(false);
+ };
+ useEffect(() => {
+ const params = new URLSearchParams(history.location.search.substring(1));
+ setValue(EMAIL, user?.email || params.get('email'));
+ }, [user, setValue, ready]);
+
+ useEffect(() => {
+ if (
+ componentToShow === ENTER_PASSWORD_PAGE &&
+ i18n.language !== getLanguageFromLocalStorage()
+ ) {
+ i18n.changeLanguage(getLanguageFromLocalStorage());
+ }
+ }, [componentToShow]);
+
+ const showSSOErrorAndRedirect = (error) => {
+ //OC: Dynamically setting the error is not an option because of the need to reflect the key on the translation file
+ const allMessages = {
+ sso: t('SIGNUP.SSO_ERROR'),
+ expired: t('SIGNUP.EXPIRED_ERROR'),
+ invited: t('SIGNUP.INVITED_ERROR'),
+ };
+ const message = allMessages[error];
+ setError(EMAIL, {
+ type: 'manual',
+ message,
+ });
+ if (error === inlineErrors.sso) {
+ // TODO: Create custom google login button pass in React google login along with ref
+ const googleLoginButton = document.getElementsByClassName('google-login-button')[0];
+ googleLoginButton.click();
+ }
+ };
+ const onSubmit = (data) => {
+ const { email } = data;
+ dispatch(customSignUp({ email: email?.toLowerCase(), showSSOError: showSSOErrorAndRedirect }));
+ };
+
+ const onSignUp = (user) => {
+ dispatch(customCreateUser(user));
+ };
+
+ const onLogin = (password, showPasswordError) => {
+ dispatch(customLoginWithPassword({ email, password, showPasswordError }));
+ };
+
+ const enterPasswordOnGoBack = () => {
+ history.push({
+ pathname: '/',
+
+
+ }, { user: { email }, component: CUSTOM_SIGN_UP });
+ };
+ const createUserAccountOnGoBack = () => {
+ history.push({
+ pathname: '/',
+
+ }, {
+ component: CUSTOM_SIGN_UP,
+ user: { email },
+ });
+ };
+
+ const errorMessage = history.location.state?.error;
+ return (
+ <>
+ }>
+
+
+ {showResetModal && }
+
+
+
+
+
+
+
+ }
+ isChrome={isChrome()}
+ errorMessage={errorMessage}
+ inputs={[
+ {
+ label: t('SIGNUP.ENTER_EMAIL'),
+ hookFormRegister: emailRegister,
+ errors: errors[EMAIL] && (errors[EMAIL].message || t('SIGNUP.EMAIL_INVALID')),
+ },
+ ]}
+ />
+
+ >
+ );
+}
+
+export default CustomSignUp;
+
+function Hidden({ children, isVisible }) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/webapp/src/containers/CustomSignUp/saga.js b/packages/webapp/src/containers/CustomSignUp/saga.js
index eca311467f..51eb007393 100644
--- a/packages/webapp/src/containers/CustomSignUp/saga.js
+++ b/packages/webapp/src/containers/CustomSignUp/saga.js
@@ -37,28 +37,32 @@ export function* customSignUpSaga({ payload: { email, showSSOError } }) {
const result = yield call(axios.get, loginUrl(email));
if (result.data.exists && !result.data.sso) {
localStorage.setItem('litefarm_lang', result.data.language);
- history.push({
- pathname: '/',
- state: {
+ history.push(
+ {
+ pathname: '/',
+ },
+ {
component: ENTER_PASSWORD_PAGE,
user: {
first_name: result.data.first_name,
email: result.data.email,
},
},
- });
+ );
} else if (result.data.invited) {
showSSOError(inlineErrors.invited);
} else if (result.data.expired) {
showSSOError(inlineErrors.expired);
} else if (!result.data.exists && !result.data.sso) {
- history.push({
- pathname: '/',
- state: {
+ history.push(
+ {
+ pathname: '/',
+ },
+ {
component: CREATE_USER_ACCOUNT,
user: { email },
},
- });
+ );
} else if (result.data.sso) {
showSSOError(inlineErrors.sso);
}
diff --git a/packages/webapp/src/containers/Documents/Add/index.js b/packages/webapp/src/containers/Documents/Add/index.js
deleted file mode 100644
index a2445c8311..0000000000
--- a/packages/webapp/src/containers/Documents/Add/index.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import PureDocumentDetailView from '../../../components/Documents/Add';
-import { useDispatch } from 'react-redux';
-import { deleteUploadedFile } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { postDocument } from '../saga';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { ImageWithAuthentication } from '../../ImageWithAuthentication';
-import { DocumentUploader } from '../DocumentUploader';
-
-function AddDocument({ history }) {
- const dispatch = useDispatch();
-
- const handleSubmit = (data) => {
- dispatch(postDocument(data));
- };
-
- const onBack = () => {
- history.goBack();
- };
-
-
- const deleteImage = (url) => {
- dispatch(deleteUploadedFile({ url }));
- };
-
- return (
- }
- documentUploader={(props) => }
- isEdit={false}
- persistedPath={[]}
- />
- );
-}
-
-export default AddDocument;
diff --git a/packages/webapp/src/containers/Documents/Add/index.jsx b/packages/webapp/src/containers/Documents/Add/index.jsx
new file mode 100644
index 0000000000..81f4e4b5ba
--- /dev/null
+++ b/packages/webapp/src/containers/Documents/Add/index.jsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import PureDocumentDetailView from '../../../components/Documents/Add';
+import { useDispatch } from 'react-redux';
+import { deleteUploadedFile } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { postDocument } from '../saga';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { ImageWithAuthentication } from '../../ImageWithAuthentication';
+import { DocumentUploader } from '../DocumentUploader';
+
+function AddDocument({ history }) {
+ const dispatch = useDispatch();
+
+ const handleSubmit = (data) => {
+ dispatch(postDocument(data));
+ };
+
+ const onBack = () => {
+ history.back();
+ };
+
+
+ const deleteImage = (url) => {
+ dispatch(deleteUploadedFile({ url }));
+ };
+
+ return (
+ }
+ documentUploader={(props) => }
+ isEdit={false}
+ persistedPath={[]}
+ />
+ );
+}
+
+export default AddDocument;
diff --git a/packages/webapp/src/containers/Documents/DocumentTile/DocumentTileContainer/index.js b/packages/webapp/src/containers/Documents/DocumentTile/DocumentTileContainer/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Documents/DocumentTile/DocumentTileContainer/index.js
rename to packages/webapp/src/containers/Documents/DocumentTile/DocumentTileContainer/index.jsx
diff --git a/packages/webapp/src/containers/Documents/DocumentTile/index.js b/packages/webapp/src/containers/Documents/DocumentTile/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Documents/DocumentTile/index.js
rename to packages/webapp/src/containers/Documents/DocumentTile/index.jsx
diff --git a/packages/webapp/src/containers/Documents/DocumentUploader/index.js b/packages/webapp/src/containers/Documents/DocumentUploader/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Documents/DocumentUploader/index.js
rename to packages/webapp/src/containers/Documents/DocumentUploader/index.jsx
diff --git a/packages/webapp/src/containers/Documents/DocumentsSpotlight.js b/packages/webapp/src/containers/Documents/DocumentsSpotlight.js
deleted file mode 100644
index 85f161d4b9..0000000000
--- a/packages/webapp/src/containers/Documents/DocumentsSpotlight.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import JoyrideWrapper from '../../components/JoyrideWrapper';
-import { useTranslation } from 'react-i18next';
-import { useDispatch, useSelector } from 'react-redux';
-import { showedSpotlightSelector } from '../showedSpotlightSlice';
-import { setSpotlightToShown } from '../Map/saga';
-import React, { useState } from 'react';
-import { certifierSurveySelector } from '../OrganicCertifierSurvey/slice';
-import { LIFECYCLE } from 'react-joyride';
-
-export default function DocumentsSpotlight() {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { documents, compliance_docs_and_certification } = useSelector(showedSpotlightSelector);
- const { interested } = useSelector(certifierSurveySelector);
- const callback = (data) => {
- const { lifecycle } = data;
- if (lifecycle === LIFECYCLE.COMPLETE) {
- dispatch(setSpotlightToShown(data.step.flag));
- }
- };
-
- let initSteps = [];
- if (!documents)
- initSteps.push({
- title: t('DOCUMENTS.DOCUMENTS'),
- contents: [t('DOCUMENTS.SPOTLIGHT.HERE_YOU_CAN')],
- list: [
- t('DOCUMENTS.SPOTLIGHT.YOU_CAN_ONE'),
- t('DOCUMENTS.SPOTLIGHT.YOU_CAN_TWO'),
- t('DOCUMENTS.SPOTLIGHT.YOU_CAN_THREE'),
- ],
- target: 'body',
- placement: 'center',
- disableCloseOnEsc: true,
- buttonText: interested ? t('common:NEXT') : t('common:GOT_IT'),
- flag: 'documents',
- });
- if (!compliance_docs_and_certification && interested)
- initSteps.push({
- title: t('DOCUMENTS.COMPLIANCE_DOCUMENTS_AND_CERTIFICATION'),
- contents: [t('DOCUMENTS.SPOTLIGHT.CDC')],
- target: 'body',
- placement: 'center',
- disableCloseOnEsc: true,
- buttonText: t('common:GOT_IT'),
- flag: 'compliance_docs_and_certification',
- });
- const [steps] = useState(initSteps);
-
- const showSpotlight = !documents || !compliance_docs_and_certification;
-
- return <>{showSpotlight && }>;
-}
diff --git a/packages/webapp/src/containers/Documents/DocumentsSpotlight.jsx b/packages/webapp/src/containers/Documents/DocumentsSpotlight.jsx
new file mode 100644
index 0000000000..e19abd6567
--- /dev/null
+++ b/packages/webapp/src/containers/Documents/DocumentsSpotlight.jsx
@@ -0,0 +1,55 @@
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import { showedSpotlightSelector } from '../showedSpotlightSlice';
+import { setSpotlightToShown } from '../Map/saga';
+import React, { useMemo } from 'react';
+import { certifierSurveySelector } from '../OrganicCertifierSurvey/slice';
+import { TourProviderWrapper } from '../../components/TourProviderWrapper/TourProviderWrapper';
+
+export default function DocumentsSpotlight() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { documents, compliance_docs_and_certification } = useSelector(showedSpotlightSelector);
+ const { interested } = useSelector(certifierSurveySelector);
+
+ const steps = useMemo(() => {
+ let steps = [];
+ if (!documents)
+ steps.push({
+ title: t('DOCUMENTS.DOCUMENTS'),
+ contents: [t('DOCUMENTS.SPOTLIGHT.HERE_YOU_CAN')],
+ list: [
+ t('DOCUMENTS.SPOTLIGHT.YOU_CAN_ONE'),
+ t('DOCUMENTS.SPOTLIGHT.YOU_CAN_TWO'),
+ t('DOCUMENTS.SPOTLIGHT.YOU_CAN_THREE'),
+ ],
+ position: 'center',
+ flag: 'documents',
+ onNext: () => dispatch(setSpotlightToShown('documents')),
+ });
+ if (!compliance_docs_and_certification && interested)
+ steps.push({
+ title: t('DOCUMENTS.COMPLIANCE_DOCUMENTS_AND_CERTIFICATION'),
+ contents: [t('DOCUMENTS.SPOTLIGHT.CDC')],
+ position: 'center',
+ flag: 'compliance_docs_and_certification',
+ onNext: () => dispatch(setSpotlightToShown('compliance_docs_and_certification')),
+ });
+ return steps;
+ }, []);
+
+
+ const showSpotlight = !documents || !compliance_docs_and_certification;
+
+ return <>{showSpotlight && {
+ if (currentStep === steps.length - 1) {
+ setIsOpen(false);
+ }
+ setCurrentStep(s => (s === steps.length - 1 ? 0 : s + 1));
+ dispatch(setSpotlightToShown(steps[currentStep].flag));
+ }}
+ steps={steps}><>>
+ }>;
+}
diff --git a/packages/webapp/src/containers/Documents/Edit/index.js b/packages/webapp/src/containers/Documents/Edit/index.js
deleted file mode 100644
index 78b01ba047..0000000000
--- a/packages/webapp/src/containers/Documents/Edit/index.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React, { useEffect } from 'react';
-import PureDocumentDetailView from '../../../components/Documents/Add';
-import { useDispatch, useSelector } from 'react-redux';
-import {
- deleteUploadedFile,
- hookFormPersistSelector,
- initEditDocument,
-} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { ImageWithAuthentication } from '../../ImageWithAuthentication';
-import { documentSelector } from '../../documentSlice';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { DocumentUploader } from '../DocumentUploader';
-import { updateDocument } from '../saga';
-
-export default function EditDocument({ history, match }) {
- const dispatch = useDispatch();
- const { document_id } = match.params;
-
- const document = useSelector(documentSelector(document_id));
- const { uploadedFiles } = useSelector(hookFormPersistSelector);
-
- useEffect(() => {
- if (!uploadedFiles) {
- dispatch(initEditDocument(document.files));
- }
- }, []);
- const onGoBack = () => {
- history.goBack();
- };
-
- const onSubmit = (data) => {
- dispatch(
- updateDocument({
- document_id: document_id,
- documentData: data,
- }),
- );
- };
-
- const deleteImage = (url) => {
- dispatch(deleteUploadedFile({ url }));
- };
-
- return (
- <>
- }
- documentUploader={(props) => }
- />
- >
- );
-}
diff --git a/packages/webapp/src/containers/Documents/Edit/index.jsx b/packages/webapp/src/containers/Documents/Edit/index.jsx
new file mode 100644
index 0000000000..d92d88099d
--- /dev/null
+++ b/packages/webapp/src/containers/Documents/Edit/index.jsx
@@ -0,0 +1,58 @@
+import React, { useEffect } from 'react';
+import PureDocumentDetailView from '../../../components/Documents/Add';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ deleteUploadedFile,
+ hookFormPersistSelector,
+ initEditDocument,
+} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { ImageWithAuthentication } from '../../ImageWithAuthentication';
+import { documentSelector } from '../../documentSlice';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { DocumentUploader } from '../DocumentUploader';
+import { updateDocument } from '../saga';
+
+export default function EditDocument({ history, match }) {
+ const dispatch = useDispatch();
+ const { document_id } = match.params;
+
+ const document = useSelector(documentSelector(document_id));
+ const { uploadedFiles } = useSelector(hookFormPersistSelector);
+
+ useEffect(() => {
+ if (!uploadedFiles) {
+ dispatch(initEditDocument(document.files));
+ }
+ }, []);
+ const onGoBack = () => {
+ history.back();
+ };
+
+ const onSubmit = (data) => {
+ dispatch(
+ updateDocument({
+ document_id: document_id,
+ documentData: data,
+ }),
+ );
+ };
+
+ const deleteImage = (url) => {
+ dispatch(deleteUploadedFile({ url }));
+ };
+
+ return (
+ <>
+ }
+ documentUploader={(props) => }
+ />
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Documents/Main/index.js b/packages/webapp/src/containers/Documents/Main/index.js
deleted file mode 100644
index 84d788422b..0000000000
--- a/packages/webapp/src/containers/Documents/Main/index.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React, { useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { ImageWithAuthentication } from '../../ImageWithAuthentication';
-import MainDocumentView from '../../../components/Documents/Main';
-import { documentSelector } from '../../documentSlice';
-import ArchiveDocumentModal from '../../../components/Modals/ArchiveDocumentModal';
-import { archiveDocument } from '../saga';
-
-export default function MainDocument({ history, match }) {
- const { document_id } = match.params;
- const [showArchiveModal, setShowArchiveModal] = useState(false);
- const dispatch = useDispatch();
- const document = useSelector(documentSelector(document_id));
- const onGoBack = () => {
- history.push('/documents');
- };
-
- const onRetire = () => {
- dispatch(archiveDocument(document_id));
- };
-
- const onUpdate = () => {
- history.push(`/documents/${document_id}/edit_document`);
- };
-
- return (
- <>
- }
- onUpdate={onUpdate}
- onRetire={() => setShowArchiveModal(true)}
- document={document}
- />
- {showArchiveModal && (
- setShowArchiveModal(false)}
- onArchive={onRetire}
- />
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/Documents/Main/index.jsx b/packages/webapp/src/containers/Documents/Main/index.jsx
new file mode 100644
index 0000000000..605fc2fb10
--- /dev/null
+++ b/packages/webapp/src/containers/Documents/Main/index.jsx
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import React, { useState } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { ImageWithAuthentication } from '../../ImageWithAuthentication';
+import MainDocumentView from '../../../components/Documents/Main';
+import { documentSelector } from '../../documentSlice';
+import ArchiveDocumentModal from '../../../components/Modals/ArchiveDocumentModal';
+import { archiveDocument } from '../saga';
+
+export default function MainDocument({ history, match }) {
+ const { document_id } = match.params;
+ const [showArchiveModal, setShowArchiveModal] = useState(false);
+ const dispatch = useDispatch();
+ const document = useSelector(documentSelector(document_id));
+ const onGoBack = () => {
+ history.push('/documents');
+ };
+
+ const onSetArchive = () => {
+ dispatch(archiveDocument({ document_id, archived: !document.archived }));
+ };
+
+ const onUpdate = () => {
+ history.push(`/documents/${document_id}/edit_document`);
+ };
+
+ return (
+ <>
+ }
+ onUpdate={onUpdate}
+ onRetire={() => setShowArchiveModal(true)}
+ document={document}
+ />
+ {showArchiveModal && (
+ setShowArchiveModal(false)}
+ onSetArchive={onSetArchive}
+ isForArchiving={!document.archived} // whether this is for archiving or for unarchiving
+ />
+ )}
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Documents/index.js b/packages/webapp/src/containers/Documents/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Documents/index.js
rename to packages/webapp/src/containers/Documents/index.jsx
diff --git a/packages/webapp/src/containers/Documents/saga.js b/packages/webapp/src/containers/Documents/saga.js
index 9cf32174c9..c6f6454c3b 100644
--- a/packages/webapp/src/containers/Documents/saga.js
+++ b/packages/webapp/src/containers/Documents/saga.js
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
import { call, put, select, takeLeading } from 'redux-saga/effects';
import { createAction } from '@reduxjs/toolkit';
import apiConfig from '../../apiConfig';
@@ -33,21 +48,29 @@ export function* postDocumentSaga({ payload: documentData }) {
export const archiveDocument = createAction(`archiveDocumentSaga`);
-export function* archiveDocumentSaga({ payload: document_id }) {
+export function* archiveDocumentSaga({ payload: { document_id, archived } }) {
const { documentUrl } = apiConfig;
let { user_id, farm_id } = yield select(loginSelector);
const header = getHeader(user_id, farm_id);
+ const archivedStr = archived ? 'ARCHIVE' : 'UNARCHIVE';
try {
- const result = yield call(axios.patch, `${documentUrl}/archive/${document_id}`, {}, header);
+ const result = yield call(
+ axios.patch,
+ `${documentUrl}/archive/${document_id}`,
+ { archived },
+ header,
+ );
if (result) {
yield put(archiveDocumentSuccess(document_id));
- yield put(enqueueSuccessSnackbar(i18n.t('message:ATTACHMENTS.SUCCESS.ARCHIVE')));
- history.goBack();
+ yield put(enqueueSuccessSnackbar(i18n.t(`message:ATTACHMENTS.SUCCESS.${archivedStr}`)));
+ history.back();
} else {
- yield put(enqueueErrorSnackbar(i18n.t('message:ATTACHMENTS.ERROR.FAILED_ARCHIVE')));
+ yield put(enqueueErrorSnackbar(i18n.t(`message:ATTACHMENTS.ERROR.FAILED_${archivedStr}`)));
+ history.go(0);
}
} catch (e) {
- yield put(enqueueErrorSnackbar(i18n.t('message:ATTACHMENTS.ERROR.FAILED_ARCHIVE')));
+ yield put(enqueueErrorSnackbar(i18n.t(`message:ATTACHMENTS.ERROR.FAILED_${archivedStr}`)));
+ history.go(0);
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/Documents/util.js b/packages/webapp/src/containers/Documents/util.js
index 8e3101fd94..7e53c454a3 100644
--- a/packages/webapp/src/containers/Documents/util.js
+++ b/packages/webapp/src/containers/Documents/util.js
@@ -19,10 +19,27 @@ export function useSortByName(documents) {
export function useStringFilteredDocuments(documents, filterString) {
return useMemo(() => {
- const lowerCaseFilter = filterString?.toLowerCase() || '';
+ const lowerCaseFilter =
+ filterString
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .replace(/\W/g, '')
+ .replace(/_/g, '')
+ .trim() || '';
const check = (names) => {
for (const name of names) {
- if (name?.toLowerCase().includes(lowerCaseFilter)) return true;
+ if (
+ name
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .replace(/\W/g, '')
+ .replace(/_/g, '')
+ .trim()
+ .includes(lowerCaseFilter)
+ )
+ return true;
}
return false;
};
diff --git a/packages/webapp/src/containers/EditCropVariety/index.js b/packages/webapp/src/containers/EditCropVariety/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/EditCropVariety/index.js
rename to packages/webapp/src/containers/EditCropVariety/index.jsx
diff --git a/packages/webapp/src/containers/EnterPasswordPage/index.js b/packages/webapp/src/containers/EnterPasswordPage/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/EnterPasswordPage/index.js
rename to packages/webapp/src/containers/EnterPasswordPage/index.jsx
diff --git a/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.js b/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.js
deleted file mode 100644
index 52a81e47dd..0000000000
--- a/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { useEffect } from 'react';
-import Spinner from '../../../components/Spinner';
-import { useDispatch } from 'react-redux';
-import { handle403 } from '../saga';
-
-export default function Forbidden({ history }) {
- const dispatch = useDispatch();
- useEffect(() => {
- if (history?.location?.state?.error?.response?.status === 403) {
- dispatch(handle403());
- } else if (history.length) {
- history.goBack();
- } else {
- history.replace('/');
- }
- }, []);
- return ;
-}
diff --git a/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.jsx b/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.jsx
new file mode 100644
index 0000000000..5dd6b25026
--- /dev/null
+++ b/packages/webapp/src/containers/ErrorHandler/Forbidden/Forbidden.jsx
@@ -0,0 +1,18 @@
+import { useEffect } from 'react';
+import Spinner from '../../../components/Spinner';
+import { useDispatch } from 'react-redux';
+import { handle403 } from '../saga';
+
+export default function Forbidden({ history }) {
+ const dispatch = useDispatch();
+ useEffect(() => {
+ if (history?.location?.state?.error?.response?.status === 403) {
+ dispatch(handle403());
+ } else if (history.length) {
+ history.back();
+ } else {
+ history.replace('/');
+ }
+ }, []);
+ return ;
+}
diff --git a/packages/webapp/src/containers/ExpiredTokenScreen/index.js b/packages/webapp/src/containers/ExpiredTokenScreen/index.js
deleted file mode 100644
index 00248cf06e..0000000000
--- a/packages/webapp/src/containers/ExpiredTokenScreen/index.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React, { useEffect, useLayoutEffect, useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import PureExpiredTokenScreen from '../../components/ExpiredTokenScreen';
-import ResetPassword from '../ResetPassword';
-import { sendResetPasswordEmail } from '../CustomSignUp/saga';
-import { useDispatch } from 'react-redux';
-
-export default function ExpiredTokenScreen({ history }) {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- const { translation_key, email } = history.location.state;
- const isInvalidPasswordResetToken = translation_key === 'RESET_PASSWORD';
- useLayoutEffect(() => {
- if (!isInvalidPasswordResetToken) {
- history.push('/');
- }
- }, []);
- const [showResetModal, setShowResetModal] = useState(false);
- const dismissModal = () => {
- setShowResetModal(false);
- };
- const forgotPassword = () => {
- dispatch(sendResetPasswordEmail(email));
- setShowResetModal(true);
- };
- return (
- <>
-
- {showResetModal && }
- >
- );
-}
-
-ExpiredTokenScreen.prototype = {
- history: PropTypes.object,
-};
diff --git a/packages/webapp/src/containers/ExpiredTokenScreen/index.jsx b/packages/webapp/src/containers/ExpiredTokenScreen/index.jsx
new file mode 100644
index 0000000000..6a75d4c717
--- /dev/null
+++ b/packages/webapp/src/containers/ExpiredTokenScreen/index.jsx
@@ -0,0 +1,42 @@
+import React, { useLayoutEffect, useState } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import PureExpiredTokenScreen from '../../components/ExpiredTokenScreen';
+import ResetPassword from '../ResetPassword';
+import { sendResetPasswordEmail } from '../CustomSignUp/saga';
+import { useDispatch } from 'react-redux';
+
+export default function ExpiredTokenScreen({ history }) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ const { translation_key, email } = history.location.state;
+ const isInvalidPasswordResetToken = translation_key === 'RESET_PASSWORD';
+ useLayoutEffect(() => {
+ if (!isInvalidPasswordResetToken) {
+ history.push('/');
+ }
+ }, []);
+ const [showResetModal, setShowResetModal] = useState(false);
+ const dismissModal = () => {
+ setShowResetModal(false);
+ };
+ const forgotPassword = () => {
+ dispatch(sendResetPasswordEmail(email));
+ setShowResetModal(true);
+ };
+ return (
+ <>
+
+ {showResetModal && }
+ >
+ );
+}
+
+ExpiredTokenScreen.prototype = {
+ history: PropTypes.object,
+};
diff --git a/packages/webapp/src/containers/ExportDownload/index.js b/packages/webapp/src/containers/ExportDownload/index.js
deleted file mode 100644
index 6bc521d2e7..0000000000
--- a/packages/webapp/src/containers/ExportDownload/index.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2019-2022 LiteFarm.org
- * This file is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { downloadExport } from './saga';
-import i18n from '../../locales/i18n';
-
-export default function DownloadExport({ match }) {
- const { id, from, to } = match.params;
- let fileSrc = Buffer.from(id, 'base64');
- const dispatch = useDispatch();
-
- useEffect(() => {
- dispatch(downloadExport({
- file: `https://${process.env.REACT_APP_DO_BUCKET_NAME}.nyc3.digitaloceanspaces.com/${fileSrc}.zip`,
- from,
- to
- }));
- }, [dispatch, fileSrc, from, to])
-
- return {i18n.t('CERTIFICATIONS.EXPORT_DOWNLOADING_MESSAGE')}
;
-}
diff --git a/packages/webapp/src/containers/ExportDownload/index.jsx b/packages/webapp/src/containers/ExportDownload/index.jsx
new file mode 100644
index 0000000000..dc52e64f49
--- /dev/null
+++ b/packages/webapp/src/containers/ExportDownload/index.jsx
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import { useEffect } from 'react';
+import { useDispatch } from 'react-redux';
+import { downloadExport } from './saga';
+import i18n from '../../locales/i18n';
+
+export default function DownloadExport({ match }) {
+ const { id, from, to } = match.params;
+ let fileSrc = window.atob(id);
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ dispatch(downloadExport({
+ file: `https://${import.meta.env.VITE_DO_BUCKET_NAME}.nyc3.digitaloceanspaces.com/${fileSrc}.zip`,
+ from,
+ to,
+ }));
+ }, [])
+
+ return {i18n.t('CERTIFICATIONS.EXPORT_DOWNLOADING_MESSAGE')}
;
+}
diff --git a/packages/webapp/src/containers/FarmSwitchOutro/index.js b/packages/webapp/src/containers/FarmSwitchOutro/index.js
deleted file mode 100644
index 0ceeeb2984..0000000000
--- a/packages/webapp/src/containers/FarmSwitchOutro/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Floater from 'react-floater';
-import React from 'react';
-import FarmSwitchOutro from '../../components/FarmSwitchOutro';
-import { useSelector } from 'react-redux';
-import { userFarmSelector } from '../userFarmSlice';
-
-export default function FarmSwitchOutroFloater({ children, onFinish }) {
- const { farm_name } = useSelector(userFarmSelector);
- return (
- }
- placement={'center'}
- styles={{ floater: { zIndex: 1500 } }}
- >
- {children}
-
- );
-}
diff --git a/packages/webapp/src/containers/FarmSwitchOutro/index.jsx b/packages/webapp/src/containers/FarmSwitchOutro/index.jsx
new file mode 100644
index 0000000000..7740457122
--- /dev/null
+++ b/packages/webapp/src/containers/FarmSwitchOutro/index.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import FarmSwitchOutro from '../../components/FarmSwitchOutro';
+import { useSelector } from 'react-redux';
+import { userFarmSelector } from '../userFarmSlice';
+import { Dialog } from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme) => ({
+ paper: {
+ overflow: 'hidden',
+ },
+}));
+export default function FarmSwitchOutroFloater({ children, onFinish }) {
+ const { farm_name } = useSelector(userFarmSelector);
+ const classes = useStyles();
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Filter/CropCatalogue/index.js b/packages/webapp/src/containers/Filter/CropCatalogue/index.js
deleted file mode 100644
index 6dcc2b6cf0..0000000000
--- a/packages/webapp/src/containers/Filter/CropCatalogue/index.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import React, { useRef } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import PureFilterPage from '../../../components/FilterPage';
-import { cropLocationsSelector } from '../../locationSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import {
- ABANDONED,
- ACTIVE,
- COMPLETE,
- LOCATION,
- NEEDS_PLAN,
- PLANNED,
- STATUS,
- SUPPLIERS,
-} from '../constants';
-import { cropCatalogueFilterSelector, setCropCatalogueFilter } from '../../filterSlice';
-import { suppliersSelector } from '../../cropVarietySlice';
-
-const statuses = [ACTIVE, ABANDONED, PLANNED, COMPLETE, NEEDS_PLAN];
-
-const CropCatalogueFilterPage = ({ onGoBack }) => {
- const { t } = useTranslation(['translation', 'filter']);
- const cropEnabledLocations = useSelector(cropLocationsSelector);
- const cropCatalogueFilter = useSelector(cropCatalogueFilterSelector);
- const suppliers = useSelector(suppliersSelector);
- const dispatch = useDispatch();
-
- const handleApply = () => {
- dispatch(setCropCatalogueFilter(filterRef.current));
- onGoBack?.();
- };
- const filterRef = useRef({});
-
- const filters = [
- {
- subject: t('CROP_CATALOGUE.FILTER.STATUS'),
- filterKey: STATUS,
- options: statuses.map((status) => ({
- value: status,
- default: cropCatalogueFilter[STATUS][status]?.active ?? false,
- label: t(`filter:CROP_CATALOGUE.${status}`),
- })),
- },
- {
- subject: t('CROP_CATALOGUE.FILTER.LOCATION'),
- filterKey: LOCATION,
- options: cropEnabledLocations.map((location) => ({
- value: location.location_id,
- default: cropCatalogueFilter[LOCATION][location.location_id]?.active ?? false,
- label: location.name,
- })),
- },
- {
- subject: t('CROP_CATALOGUE.FILTER.SUPPLIERS'),
- filterKey: SUPPLIERS,
- options: suppliers.map((supplier) => ({
- value: supplier,
- default: cropCatalogueFilter[SUPPLIERS][supplier]?.active ?? false,
- label: supplier,
- })),
- },
- ];
-
- return (
-
- );
-};
-
-CropCatalogueFilterPage.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
-};
-
-export default CropCatalogueFilterPage;
diff --git a/packages/webapp/src/containers/Filter/CropCatalogue/index.jsx b/packages/webapp/src/containers/Filter/CropCatalogue/index.jsx
new file mode 100644
index 0000000000..8132acb66d
--- /dev/null
+++ b/packages/webapp/src/containers/Filter/CropCatalogue/index.jsx
@@ -0,0 +1,84 @@
+import React, { useRef } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import PureFilterPage from '../../../components/FilterPage';
+import { cropLocationsSelector } from '../../locationSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ ABANDONED,
+ ACTIVE,
+ COMPLETE,
+ LOCATION,
+ NEEDS_PLAN,
+ PLANNED,
+ STATUS,
+ SUPPLIERS,
+} from '../constants';
+import { cropCatalogueFilterSelector, setCropCatalogueFilter } from '../../filterSlice';
+import { suppliersSelector } from '../../cropVarietySlice';
+import { SEARCHABLE_MULTI_SELECT } from '../../../components/Filter/filterTypes';
+
+const statuses = [ACTIVE, ABANDONED, PLANNED, COMPLETE, NEEDS_PLAN];
+
+const CropCatalogueFilterPage = ({ onGoBack }) => {
+ const { t } = useTranslation(['translation', 'filter']);
+ const cropEnabledLocations = useSelector(cropLocationsSelector);
+ const cropCatalogueFilter = useSelector(cropCatalogueFilterSelector);
+ const suppliers = useSelector(suppliersSelector);
+ const dispatch = useDispatch();
+
+ const handleApply = () => {
+ dispatch(setCropCatalogueFilter(filterRef.current));
+ onGoBack?.();
+ };
+ const filterRef = useRef({});
+
+ const filters = [
+ {
+ subject: t('CROP_CATALOGUE.FILTER.STATUS'),
+ filterKey: STATUS,
+ options: statuses.map((status) => ({
+ value: status,
+ default: cropCatalogueFilter[STATUS][status]?.active ?? false,
+ label: t(`filter:CROP_CATALOGUE.${status}`),
+ })),
+ },
+ {
+ subject: t('CROP_CATALOGUE.FILTER.LOCATION'),
+ filterKey: LOCATION,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: cropEnabledLocations.map((location) => ({
+ value: location.location_id,
+ default: cropCatalogueFilter[LOCATION][location.location_id]?.active ?? false,
+ label: location.name,
+ })),
+ },
+ {
+ subject: t('CROP_CATALOGUE.FILTER.SUPPLIERS'),
+ filterKey: SUPPLIERS,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: suppliers.map((supplier) => ({
+ value: supplier,
+ default: cropCatalogueFilter[SUPPLIERS][supplier]?.active ?? false,
+ label: supplier,
+ })),
+ },
+ ];
+
+ return (
+
+ );
+};
+
+CropCatalogueFilterPage.prototype = {
+ subject: PropTypes.string,
+ items: PropTypes.array,
+};
+
+export default CropCatalogueFilterPage;
diff --git a/packages/webapp/src/containers/Filter/CropVariety/index.js b/packages/webapp/src/containers/Filter/CropVariety/index.js
deleted file mode 100644
index bf02375ea2..0000000000
--- a/packages/webapp/src/containers/Filter/CropVariety/index.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import PureFilterPage from '../../../components/FilterPage';
-import { cropLocationsSelector } from '../../locationSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import {
- ABANDONED,
- ACTIVE,
- COMPLETE,
- LOCATION,
- NEEDS_PLAN,
- PLANNED,
- STATUS,
- SUPPLIERS,
-} from '../constants';
-import {
- cropVarietyFilterSelector,
- setCropVarietyFilter,
- setCropVarietyFilterDefault,
-} from '../../filterSlice';
-import { suppliersSelector } from '../../cropVarietySlice';
-
-const statuses = [ACTIVE, ABANDONED, PLANNED, COMPLETE, NEEDS_PLAN];
-
-const CropVarietyFilterPage = ({ cropId, onGoBack }) => {
- const { t } = useTranslation(['translation', 'filter']);
- const cropEnabledLocations = useSelector(cropLocationsSelector);
- const cropVarietyFilter = useSelector(cropVarietyFilterSelector(cropId));
- const suppliers = useSelector(suppliersSelector); //TODO: SELECT SUPPLIERS EXCLUSIVE TO THIS CROP
- const dispatch = useDispatch();
-
- useEffect(() => {
- if (!cropVarietyFilter) {
- dispatch(setCropVarietyFilterDefault(cropId));
- }
- }, []);
-
- const handleApply = () => {
- dispatch(
- setCropVarietyFilter({
- cropId,
- cropVarietyFilter: filterRef.current,
- }),
- );
- onGoBack?.();
- };
- const filterRef = useRef({});
-
- const filters = [
- {
- subject: t('CROP_CATALOGUE.FILTER.STATUS'),
- filterKey: STATUS,
- options: statuses.map((status) => ({
- value: status,
- default: cropVarietyFilter?.[STATUS][status]?.active ?? false,
- label: t(`filter:CROP_CATALOGUE.${status}`),
- })),
- },
- {
- subject: t('CROP_CATALOGUE.FILTER.LOCATION'),
- filterKey: LOCATION,
- options: cropEnabledLocations.map((location) => ({
- value: location.location_id,
- default: cropVarietyFilter?.[LOCATION][location.location_id]?.active ?? false,
- label: location.name,
- })),
- },
- {
- subject: t('CROP_CATALOGUE.FILTER.SUPPLIERS'),
- filterKey: SUPPLIERS,
- options: suppliers.map((supplier) => ({
- value: supplier,
- default: cropVarietyFilter?.[SUPPLIERS][supplier]?.active ?? false,
- label: supplier,
- })),
- },
- ];
-
- return (
-
- );
-};
-
-CropVarietyFilterPage.prototype = {
- crop_id: PropTypes.number,
-};
-
-export default CropVarietyFilterPage;
diff --git a/packages/webapp/src/containers/Filter/CropVariety/index.jsx b/packages/webapp/src/containers/Filter/CropVariety/index.jsx
new file mode 100644
index 0000000000..582bac483f
--- /dev/null
+++ b/packages/webapp/src/containers/Filter/CropVariety/index.jsx
@@ -0,0 +1,98 @@
+import React, { useEffect, useRef } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import PureFilterPage from '../../../components/FilterPage';
+import { cropLocationsSelector } from '../../locationSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ ABANDONED,
+ ACTIVE,
+ COMPLETE,
+ LOCATION,
+ NEEDS_PLAN,
+ PLANNED,
+ STATUS,
+ SUPPLIERS,
+} from '../constants';
+import {
+ cropVarietyFilterSelector,
+ setCropVarietyFilter,
+ setCropVarietyFilterDefault,
+} from '../../filterSlice';
+import { suppliersByCropIdSelector } from '../../cropVarietySlice';
+import { SEARCHABLE_MULTI_SELECT } from '../../../components/Filter/filterTypes';
+
+const statuses = [ACTIVE, ABANDONED, PLANNED, COMPLETE, NEEDS_PLAN];
+
+const CropVarietyFilterPage = ({ cropId, onGoBack }) => {
+ const { t } = useTranslation(['translation', 'filter']);
+ const cropEnabledLocations = useSelector(cropLocationsSelector);
+ const cropVarietyFilter = useSelector(cropVarietyFilterSelector(cropId));
+ const suppliers = useSelector(suppliersByCropIdSelector(cropId));
+ const dispatch = useDispatch();
+
+ useEffect(() => {
+ if (!cropVarietyFilter) {
+ dispatch(setCropVarietyFilterDefault(cropId));
+ }
+ }, []);
+
+ const handleApply = () => {
+ dispatch(
+ setCropVarietyFilter({
+ cropId,
+ cropVarietyFilter: filterRef.current,
+ }),
+ );
+ onGoBack?.();
+ };
+ const filterRef = useRef({});
+
+ const filters = [
+ {
+ subject: t('CROP_CATALOGUE.FILTER.STATUS'),
+ filterKey: STATUS,
+ options: statuses.map((status) => ({
+ value: status,
+ default: cropVarietyFilter?.[STATUS][status]?.active ?? false,
+ label: t(`filter:CROP_CATALOGUE.${status}`),
+ })),
+ },
+ {
+ subject: t('CROP_CATALOGUE.FILTER.LOCATION'),
+ filterKey: LOCATION,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: cropEnabledLocations.map((location) => ({
+ value: location.location_id,
+ default: cropVarietyFilter?.[LOCATION][location.location_id]?.active ?? false,
+ label: location.name,
+ })),
+ },
+ {
+ subject: t('CROP_CATALOGUE.FILTER.SUPPLIERS'),
+ filterKey: SUPPLIERS,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: suppliers.map((supplier) => ({
+ value: supplier,
+ default: cropVarietyFilter?.[SUPPLIERS][supplier]?.active ?? false,
+ label: supplier,
+ })),
+ },
+ ];
+
+ return (
+
+ );
+};
+
+CropVarietyFilterPage.prototype = {
+ crop_id: PropTypes.number,
+};
+
+export default CropVarietyFilterPage;
diff --git a/packages/webapp/src/containers/Filter/Documents/index.js b/packages/webapp/src/containers/Filter/Documents/index.js
deleted file mode 100644
index 3fc2959314..0000000000
--- a/packages/webapp/src/containers/Filter/Documents/index.js
+++ /dev/null
@@ -1,95 +0,0 @@
-import React, { useRef, useState } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import PureFilterPage from '../../../components/FilterPage';
-import Input from '../../../components/Form/Input';
-import { useDispatch, useSelector } from 'react-redux';
-import {
- TYPE,
- CLEANING_PRODUCT,
- CROP_COMPLIANCE,
- FERTILIZING_PRODUCT,
- PEST_CONTROL_PRODUCT,
- SOIL_AMENDMENT,
- SOIL_SAMPLE_RESULTS,
- WATER_SAMPLE_RESULTS,
- OTHER,
- VALID_ON,
- UNCATEGORIZED,
-} from '../constants';
-import { documentsFilterSelector, setDocumentsFilter } from '../../filterSlice';
-
-const types = [
- CLEANING_PRODUCT,
- CROP_COMPLIANCE,
- FERTILIZING_PRODUCT,
- PEST_CONTROL_PRODUCT,
- SOIL_AMENDMENT,
- SOIL_SAMPLE_RESULTS,
- WATER_SAMPLE_RESULTS,
- OTHER,
- UNCATEGORIZED,
-];
-
-const DocumentsFilterPage = ({ onGoBack }) => {
- const { t } = useTranslation(['translation', 'filter']);
- const documentsFilter = useSelector(documentsFilterSelector);
- const dispatch = useDispatch();
- const [validUntilDate, setValidUntilDate] = useState(documentsFilter[VALID_ON] ?? '');
-
- const handleApply = () => {
- const filterToApply = {
- ...filterRef.current,
- VALID_ON: validUntilDate ? validUntilDate : undefined,
- };
- dispatch(setDocumentsFilter(filterToApply));
- onGoBack?.();
- };
- const handleDateChange = (e) => {
- setValidUntilDate(e.target.value);
- };
-
- const filterRef = useRef({});
-
- const filters = [
- {
- subject: t('DOCUMENTS.FILTER.TYPE'),
- filterKey: TYPE,
- options: types.map((type) => ({
- value: type,
- default: documentsFilter[TYPE][type]?.active ?? false,
- label: t(`filter:DOCUMENTS.${type}`),
- })),
- },
- ];
-
- return (
-
-
-
- );
-};
-
-DocumentsFilterPage.prototype = {
- subject: PropTypes.string,
- items: PropTypes.array,
-};
-
-export default DocumentsFilterPage;
diff --git a/packages/webapp/src/containers/Filter/Documents/index.jsx b/packages/webapp/src/containers/Filter/Documents/index.jsx
new file mode 100644
index 0000000000..5507f47412
--- /dev/null
+++ b/packages/webapp/src/containers/Filter/Documents/index.jsx
@@ -0,0 +1,84 @@
+import React, { useRef } from 'react';
+import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
+import PureFilterPage from '../../../components/FilterPage';
+import { useDispatch, useSelector } from 'react-redux';
+import {
+ CLEANING_PRODUCT,
+ CROP_COMPLIANCE,
+ FERTILIZING_PRODUCT,
+ OTHER,
+ PEST_CONTROL_PRODUCT,
+ SOIL_AMENDMENT,
+ SOIL_SAMPLE_RESULTS,
+ TYPE,
+ UNCATEGORIZED,
+ VALID_ON,
+ WATER_SAMPLE_RESULTS,
+ RECEIPTS,
+ INVOICES,
+} from '../constants';
+import { documentsFilterSelector, setDocumentsFilter } from '../../filterSlice';
+import { DATE } from '../../../components/Filter/filterTypes';
+
+const types = [
+ CLEANING_PRODUCT,
+ CROP_COMPLIANCE,
+ FERTILIZING_PRODUCT,
+ INVOICES,
+ PEST_CONTROL_PRODUCT,
+ RECEIPTS,
+ SOIL_AMENDMENT,
+ SOIL_SAMPLE_RESULTS,
+ WATER_SAMPLE_RESULTS,
+ OTHER,
+ UNCATEGORIZED,
+];
+
+const DocumentsFilterPage = ({ onGoBack }) => {
+ const { t } = useTranslation(['translation', 'filter']);
+ const documentsFilter = useSelector(documentsFilterSelector);
+ const dispatch = useDispatch();
+
+ const handleApply = () => {
+ dispatch(setDocumentsFilter(filterRef.current));
+ onGoBack?.();
+ };
+
+ const filterRef = useRef({});
+
+ const filters = [
+ {
+ subject: t('DOCUMENTS.FILTER.TYPE'),
+ filterKey: TYPE,
+ options: types.map((type) => ({
+ value: type,
+ default: documentsFilter[TYPE][type]?.active ?? false,
+ label: t(`filter:DOCUMENTS.${type}`),
+ })),
+ },
+ {
+ subject: t('DOCUMENTS.FILTER.VALID_ON'),
+ filterKey: 'VALID_ON',
+ type: DATE,
+ defaultValue: documentsFilter[VALID_ON],
+ },
+ ];
+
+ return (
+
+ );
+};
+
+DocumentsFilterPage.prototype = {
+ subject: PropTypes.string,
+ items: PropTypes.array,
+};
+
+export default DocumentsFilterPage;
diff --git a/packages/webapp/src/containers/Filter/Tasks/index.jsx b/packages/webapp/src/containers/Filter/Tasks/index.jsx
new file mode 100644
index 0000000000..b6280fe77e
--- /dev/null
+++ b/packages/webapp/src/containers/Filter/Tasks/index.jsx
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import { useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import React, { useMemo, useRef, useEffect } from 'react';
+
+import PureFilterPage from '../../../components/FilterPage';
+import { setTasksFilter, tasksFilterSelector } from '../../filterSlice';
+import { userFarmsByFarmSelector } from '../../userFarmSlice';
+import { getTaskTypes } from '../../Task/saga';
+import { defaultTaskTypesSelector, userCreatedTaskTypesSelector } from '../../taskTypeSlice';
+
+import {
+ ABANDONED,
+ ASSIGNEE,
+ COMPLETED,
+ CROP,
+ FROM_DATE,
+ LATE,
+ LOCATION,
+ PLANNED,
+ STATUS,
+ TO_DATE,
+ TYPE,
+} from '../constants';
+
+import { DATE_RANGE, SEARCHABLE_MULTI_SELECT } from '../../../components/Filter/filterTypes';
+import { tasksSelector } from '../../taskSlice';
+import { locationsSelector } from '../../locationSlice';
+import { getSupportedTaskTypesSet } from '../../../components/Task/getSupportedTaskTypesSet';
+
+const TasksFilterPage = ({ onGoBack }) => {
+ const { t } = useTranslation(['translation', 'filter', 'task']);
+ const tasksFilter = useSelector(tasksFilterSelector);
+ const tasks = useSelector(tasksSelector);
+ const dispatch = useDispatch();
+ const locations = useSelector(locationsSelector);
+ const activeUsers = useSelector(userFarmsByFarmSelector).filter(
+ (user) => user.status != 'Inactive',
+ );
+ const defaultTaskTypes = useSelector(defaultTaskTypesSelector);
+ const customTaskTypes = useSelector(userCreatedTaskTypesSelector);
+
+ useEffect(() => {
+ dispatch(getTaskTypes());
+ }, []);
+
+ const taskTypes = useMemo(() => {
+ const supportedTaskTypes = getSupportedTaskTypesSet(true);
+ let taskTypes = {};
+ for (const type of defaultTaskTypes) {
+ if (type.deleted === false && supportedTaskTypes.has(type.task_translation_key)) {
+ taskTypes[type.task_type_id] = type;
+ }
+ }
+ for (const type of customTaskTypes) {
+ if (type.deleted === false) {
+ taskTypes[type.task_type_id] = type;
+ }
+ }
+ return taskTypes;
+ }, [defaultTaskTypes, customTaskTypes]);
+
+ const statuses = [ABANDONED, COMPLETED, LATE, PLANNED];
+
+ const { assignees } = useMemo(() => {
+ let assignees = {};
+ for (const task of tasks) {
+ if (task.assignee !== undefined) {
+ const { user_id, first_name, last_name } = task.assignee;
+ assignees[user_id] = `${first_name} ${last_name}`;
+ }
+ }
+ for (const user of activeUsers) {
+ assignees[user['user_id']] = `${user['first_name']} ${user['last_name']}`;
+ }
+ assignees['unassigned'] = t('TASK.UNASSIGNED');
+ return { taskTypes, assignees };
+ }, [tasks.length]);
+
+ const cropVarietyEntities = useMemo(() => {
+ return tasks.reduce((cropVarietyEntities, { managementPlans }) => {
+ for (const managementPlan of managementPlans) {
+ const cropVariety = managementPlan.crop_variety;
+ const crop = cropVariety.crop;
+ const cropName = t(`crop:${crop.crop_translation_key}`);
+ cropVarietyEntities[cropVariety.crop_variety_id] = cropVariety.crop_variety_name
+ ? `${cropVariety.crop_variety_name}, ${cropName}`
+ : cropName;
+ }
+ return cropVarietyEntities;
+ }, {});
+ }, [tasks.length]);
+
+ const filterRef = useRef({});
+
+ const handleApply = () => {
+ dispatch(setTasksFilter(filterRef.current));
+ onGoBack?.();
+ };
+
+ const filters = [
+ {
+ subject: t('TASK.FILTER.STATUS'),
+ filterKey: STATUS,
+ options: statuses.map((status) => ({
+ value: status.toLowerCase(),
+ default: tasksFilter[STATUS][status.toLowerCase()]?.active ?? false,
+ label: t(`filter:TASKS.${status}`),
+ })),
+ },
+ {
+ subject: t('TASK.FILTER.TYPE'),
+ filterKey: TYPE,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: Object.values(taskTypes).map((type) => ({
+ value: type.task_type_id,
+ default: tasksFilter[TYPE][type.task_type_id]?.active ?? false,
+ label: t(`task:${type.task_translation_key}`),
+ })),
+ },
+ {
+ subject: t('TASK.FILTER.LOCATION'),
+ filterKey: LOCATION,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: locations.map(({ location_id, name }) => ({
+ value: location_id,
+ default: tasksFilter[LOCATION][location_id]?.active ?? false,
+ label: name,
+ })),
+ },
+ {
+ subject: t('TASK.FILTER.ASSIGNEE'),
+ filterKey: ASSIGNEE,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: Object.keys(assignees).map((user_id) => ({
+ value: user_id,
+ default: tasksFilter[ASSIGNEE][user_id]?.active ?? false,
+ label: assignees[user_id],
+ })),
+ },
+ {
+ subject: t('TASK.FILTER.CROP'),
+ filterKey: CROP,
+ type: SEARCHABLE_MULTI_SELECT,
+ options: Object.entries(cropVarietyEntities).map(([crop_variety_id, name]) => ({
+ value: crop_variety_id,
+ default: tasksFilter[CROP][crop_variety_id]?.active ?? false,
+ label: name,
+ })),
+ },
+ {
+ subject: t('TASK.FILTER.DATE_RANGE'),
+ type: DATE_RANGE,
+ defaultFromDate: tasksFilter[FROM_DATE],
+ defaultToDate: tasksFilter[TO_DATE],
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export default TasksFilterPage;
diff --git a/packages/webapp/src/containers/Filter/constants.js b/packages/webapp/src/containers/Filter/constants.js
index 5ed4f708bc..0dffa1c31e 100644
--- a/packages/webapp/src/containers/Filter/constants.js
+++ b/packages/webapp/src/containers/Filter/constants.js
@@ -18,3 +18,14 @@ export const WATER_SAMPLE_RESULTS = 'WATER_SAMPLE_RESULTS';
export const OTHER = 'OTHER';
export const VALID_ON = 'VALID_ON';
export const UNCATEGORIZED = 'UNCATEGORIZED';
+export const RECEIPTS = 'RECEIPTS';
+export const INVOICES = 'INVOICES';
+
+export const CROP = 'CROP';
+export const ASSIGNEE = 'ASSIGNEE';
+export const LATE = 'LATE';
+export const COMPLETED = 'COMPLETED';
+export const FROM_DATE = 'FROM_DATE';
+export const TO_DATE = 'TO_DATE';
+export const FOR_REVIEW = 'FOR_REVIEW';
+export const IS_ASCENDING = 'IS_ASCENDING';
diff --git a/packages/webapp/src/containers/Finances/ActualCropRevenue/index.js b/packages/webapp/src/containers/Finances/ActualCropRevenue/index.js
deleted file mode 100644
index ba81fa9505..0000000000
--- a/packages/webapp/src/containers/Finances/ActualCropRevenue/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useDispatch, useSelector } from 'react-redux';
-import FinanceGroup from '../../../components/Finances/FinanceGroup';
-import { getManagementPlanCardDate } from '../../../util/moment';
-import { cropVarietyEntitiesSelector } from '../../cropVarietySlice';
-import { setSelectedSale } from '../actions';
-import { convertFromMetric, roundToTwoDecimal } from '../../../util';
-import { useTranslation } from 'react-i18next';
-
-const ActualCropRevenue = ({ sale, history, ...props }) => {
- const { t } = useTranslation();
- const { sale_id, sale_date, customer_name, crop_variety_sale } = sale;
-
- const dispatch = useDispatch();
-
- // TODO: optimize this - put in parent component or seek by id
- const cropVarietyEntities = useSelector(cropVarietyEntitiesSelector);
-
- const total = crop_variety_sale.reduce((total, sale) => total + sale.sale_value, 0);
-
- const onClickForward = () => {
- dispatch(setSelectedSale(sale));
- history.push(`/edit_sale`);
- };
-
- return (
- {
- const convertedQuantity = roundToTwoDecimal(
- convertFromMetric(cvs.quantity.toString(), cvs.quantity_unit, 'kg').toString(),
- );
- const { crop_variety_name, crop: { crop_translation_key } } = cropVarietyEntities[cvs.crop_variety_id];
- const title = crop_variety_name ? `${crop_variety_name}, ${t(`crop:${crop_translation_key}`)}`
- : t(`crop:${crop_translation_key}`);
- return {
- key: cvs.crop_variety_id,
- title,
- subtitle: `${convertedQuantity} ${cvs.quantity_unit}`,
- amount: cvs.sale_value,
- };
- })}
- {...props}
- />
- );
-};
-
-ActualCropRevenue.prototype = {
- isDropDown: PropTypes.bool,
-};
-
-export default ActualCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/ActualCropRevenue/index.jsx b/packages/webapp/src/containers/Finances/ActualCropRevenue/index.jsx
new file mode 100644
index 0000000000..c6837c3bc1
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/ActualCropRevenue/index.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useDispatch, useSelector } from 'react-redux';
+import FinanceGroup from '../../../components/Finances/FinanceGroup';
+import { getManagementPlanCardDate } from '../../../util/moment';
+import { cropVarietyEntitiesSelector } from '../../cropVarietySlice';
+import { setSelectedSale } from '../actions';
+import { getMass, getMassUnit, roundToTwoDecimal } from '../../../util';
+import { useTranslation } from 'react-i18next';
+
+const ActualCropRevenue = ({ sale, history, ...props }) => {
+ const { t } = useTranslation();
+ const { sale_date, customer_name, crop_variety_sale } = sale;
+
+ const dispatch = useDispatch();
+
+ // TODO: optimize this - put in parent component or seek by id
+ const cropVarietyEntities = useSelector(cropVarietyEntitiesSelector);
+
+ const total = crop_variety_sale.reduce((total, sale) => total + sale.sale_value, 0);
+
+ const onClickForward = () => {
+ dispatch(setSelectedSale(sale));
+ history.push(`/edit_sale`);
+ };
+
+ const quantity_unit = getMassUnit();
+
+ return (
+ {
+ const convertedQuantity = roundToTwoDecimal(getMass(cvs.quantity).toString());
+ const {
+ crop_variety_name,
+ crop: { crop_translation_key },
+ } = cropVarietyEntities[cvs.crop_variety_id];
+ const title = crop_variety_name
+ ? `${crop_variety_name}, ${t(`crop:${crop_translation_key}`)}`
+ : t(`crop:${crop_translation_key}`);
+ return {
+ key: cvs.crop_variety_id,
+ title,
+ subtitle: `${convertedQuantity} ${quantity_unit}`,
+ amount: cvs.sale_value,
+ };
+ })}
+ {...props}
+ />
+ );
+};
+
+ActualCropRevenue.prototype = {
+ isDropDown: PropTypes.bool,
+};
+
+export default ActualCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/ActualRevenue/index.js b/packages/webapp/src/containers/Finances/ActualRevenue/index.js
deleted file mode 100644
index c3a9bb680f..0000000000
--- a/packages/webapp/src/containers/Finances/ActualRevenue/index.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, { useMemo } from 'react';
-import Layout from '../../../components/Layout';
-import PageTitle from '../../../components/PageTitle/v2';
-import { useSelector } from 'react-redux';
-import { useTranslation } from 'react-i18next';
-import { useForm } from 'react-hook-form';
-import moment from 'moment';
-import { salesSelector } from '../selectors';
-import WholeFarmRevenue from '../../../components/Finances/WholeFarmRevenue';
-import { AddLink, Semibold } from '../../../components/Typography';
-import DateRangePicker from '../../../components/Form/DateRangePicker';
-import ActualCropRevenue from '../ActualCropRevenue';
-import FinanceListHeader from '../../../components/Finances/FinanceListHeader';
-
-export default function ActualRevenue({ history, match }) {
- const { t } = useTranslation();
- const onGoBack = () => history.goBack();
- const onAddRevenue = () => history.push(`/add_sale`);
- // TODO: refactor sale data after finance reducer is remade
- const sales = useSelector(salesSelector);
-
- const {
- register,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onBlur',
- shouldUnregister: true,
- defaultValues: {
- from_date: moment().startOf('year').format('YYYY-MM-DD'),
- to_date: moment().endOf('year').format('YYYY-MM-DD'),
- },
- });
-
- const fromDate = watch('from_date');
- const toDate = watch('to_date');
-
- const filteredSales = useMemo(() => {
- return sales.filter((sale) => {
- const saleDate = moment(new Date(sale.sale_date)).utc().format('YYYY-MM-DD');
- return new Date(saleDate) >= new Date(fromDate) && new Date(saleDate) <= new Date(toDate);
- });
- }, [sales, fromDate, toDate]);
-
- const total = filteredSales.reduce((acc, sale) => {
- const { crop_variety_sale } = sale;
- return acc + crop_variety_sale.reduce((acc, cvs) => acc + cvs.sale_value, 0);
- }, 0);
-
- return (
-
-
-
-
-
- {t('FINANCES.ACTUAL_REVENUE.ADD_REVENUE')}
-
-
-
- {t('FINANCES.VIEW_WITHIN_DATE_RANGE')}
-
-
-
-
- {filteredSales.map((sale) => (
-
- ))}
-
- );
-}
diff --git a/packages/webapp/src/containers/Finances/ActualRevenue/index.jsx b/packages/webapp/src/containers/Finances/ActualRevenue/index.jsx
new file mode 100644
index 0000000000..d3164d30d1
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/ActualRevenue/index.jsx
@@ -0,0 +1,112 @@
+import React, { useEffect, useMemo } from 'react';
+import Layout from '../../../components/Layout';
+import PageTitle from '../../../components/PageTitle/v2';
+import { useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import { useForm } from 'react-hook-form';
+import { dateRangeSelector, salesSelector } from '../selectors';
+import WholeFarmRevenue from '../../../components/Finances/WholeFarmRevenue';
+import { AddLink, Semibold } from '../../../components/Typography';
+import DateRangePicker from '../../../components/Form/DateRangePicker';
+import ActualCropRevenue from '../ActualCropRevenue';
+import FinanceListHeader from '../../../components/Finances/FinanceListHeader';
+import { calcActualRevenue, filterSalesByDateRange } from '../util';
+import { setDateRange } from '../actions';
+
+export default function ActualRevenue({ history, match }) {
+ const { t } = useTranslation();
+ const onGoBack = () => history.back();
+ const onAddRevenue = () => history.push(`/add_sale`);
+ // TODO: refactor sale data after finance reducer is remade
+ const sales = useSelector(salesSelector);
+ const dateRange = useSelector(dateRangeSelector);
+ const dispatch = useDispatch();
+
+ const year = new Date().getFullYear();
+
+ const {
+ register,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onBlur',
+ shouldUnregister: true,
+ defaultValues: {
+ from_date: dateRange?.startDate
+ ? new Date(
+ typeof dateRange.startDate === 'string'
+ ? dateRange.startDate.split('T')[0] + 'T00:00:00.000Z'
+ : dateRange.startDate,
+ )
+ .toISOString()
+ .split('T')[0]
+ : `${year}-01-01`,
+ to_date: dateRange?.endDate
+ ? new Date(
+ typeof dateRange.endDate === 'string'
+ ? dateRange.endDate.split('T')[0] + 'T00:00:00.000Z'
+ : dateRange.endDate,
+ )
+ .toISOString()
+ .split('T')[0]
+ : `${year}-12-31`,
+ },
+ });
+
+ const fromDate = watch('from_date');
+ const toDate = watch('to_date');
+
+ const revenueForWholeFarm = useMemo(
+ () => calcActualRevenue(sales, fromDate, toDate),
+ [sales, fromDate, toDate],
+ );
+ const filteredSales = useMemo(
+ () => filterSalesByDateRange(sales, fromDate, toDate),
+ [sales, fromDate, toDate],
+ );
+
+ useEffect(() => {
+ dispatch(setDateRange({ startDate: fromDate, endDate: toDate }));
+ }, [fromDate, toDate]);
+
+ return (
+
+
+
+
+
+ {t('FINANCES.ACTUAL_REVENUE.ADD_REVENUE')}
+
+
+
+ {t('FINANCES.VIEW_WITHIN_DATE_RANGE')}
+
+
+
+
+ {filteredSales.map((sale) => (
+
+ ))}
+
+ );
+}
diff --git a/packages/webapp/src/containers/Finances/AddSale/index.js b/packages/webapp/src/containers/Finances/AddSale/index.js
deleted file mode 100644
index 9ff8d33929..0000000000
--- a/packages/webapp/src/containers/Finances/AddSale/index.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import React, { Component } from 'react';
-import DateContainer from '../../../components/Inputs/DateContainer';
-import moment from 'moment';
-import PageTitle from '../../../components/PageTitle/v2';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../styles.module.scss';
-import { actions } from 'react-redux-form';
-import SaleForm from '../../../components/Forms/Sale';
-import { addOrUpdateSale } from '../actions';
-import { convertToMetric, getUnit } from '../../../util';
-import history from '../../../history';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
-import { getManagementPlans } from '../../saga';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-
-class AddSale extends Component {
- constructor(props) {
- super(props);
- this.state = {
- date: moment(),
- chosenOptions: [],
- quantity_unit: getUnit(this.props.farm, 'kg', 'lb'),
- currencySymbol: grabCurrencySymbol(this.props.farm),
- };
- this.props.dispatch(actions.reset('financeReducer.forms.addSale'));
- this.handleSubmit = this.handleSubmit.bind(this);
- this.handleChooseCrop = this.handleChooseCrop.bind(this);
- }
-
- componentDidMount() {
- this.props.dispatch(getManagementPlans());
- //TODO fetch farm
- }
-
- handleSubmit(sale) {
- const { dispatch } = this.props;
- const crop_variety_sale = this.state.chosenOptions.map((c) => {
- return {
- sale_value: sale ? sale[c.label].value && parseFloat(sale[c.label].value).toFixed(2) : 0,
- quantity: sale
- ? sale[c.label].quantity &&
- parseFloat(
- convertToMetric(parseFloat(sale[c.label].quantity), this.state.quantity_unit, 'kg'),
- )
- : 0,
- quantity_unit: this.state.quantity_unit,
- crop_variety_id: c.value,
- };
- });
- const newSale = {
- customer_name: sale.name,
- sale_date: this.state.date,
- farm_id: this.props.farm.farm_id,
- crop_variety_sale,
- };
- dispatch(addOrUpdateSale(newSale));
- }
-
- handleChooseCrop(option) {
- this.setState({
- chosenOptions: option,
- });
- }
-
- getCropVarietyOptions = (managementPlans) => {
- if (!managementPlans || managementPlans.length === 0) {
- return;
- }
-
- let cropVarietyOptions = [];
- let cropVarietySet = new Set();
-
- for (let mp of managementPlans) {
- if (!cropVarietySet.has(mp.crop_variety_id)) {
- cropVarietyOptions.push({
- label: mp.crop_variety_name
- ? `${mp.crop_variety_name}, ${this.props.t(`crop:${mp.crop_translation_key}`)}`
- : this.props.t(`crop:${mp.crop_translation_key}`),
- value: mp.crop_variety_id,
- });
- cropVarietySet.add(mp.crop_variety_id);
- }
- }
-
- cropVarietyOptions.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0));
-
- return cropVarietyOptions;
- };
-
- render() {
- let managementPlans = this.props.managementPlans || [];
- const cropVarietyOptions = this.getCropVarietyOptions(managementPlans);
- return (
-
-
history.goBack()} />
-
- {this.props.t('SALE.ADD_SALE.DATE')}
- this.setState({ date })}
- />
-
- history.push('/finances')}
- currencySymbol={this.state.currencySymbol}
- />
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- managementPlans: currentAndPlannedManagementPlansSelector(state),
- farm: userFarmSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(AddSale));
diff --git a/packages/webapp/src/containers/Finances/AddSale/index.jsx b/packages/webapp/src/containers/Finances/AddSale/index.jsx
new file mode 100644
index 0000000000..1cb7e1adbc
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/AddSale/index.jsx
@@ -0,0 +1,136 @@
+import React, { Component } from 'react';
+import DateContainer from '../../../components/Inputs/DateContainer';
+import moment from 'moment';
+import PageTitle from '../../../components/PageTitle/v2';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../styles.module.scss';
+import { actions } from 'react-redux-form';
+import SaleForm from '../../../components/Forms/Sale';
+import { addOrUpdateSale } from '../actions';
+import { convertToMetric, getUnit } from '../../../util';
+import history from '../../../history';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
+import { getManagementPlans } from '../../saga';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+
+class AddSale extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ date: moment(),
+ chosenOptions: [],
+ quantity_unit: getUnit(this.props.farm, 'kg', 'lb'),
+ currencySymbol: grabCurrencySymbol(),
+ };
+ this.props.dispatch(actions.reset('financeReducer.forms.addSale'));
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleChooseCrop = this.handleChooseCrop.bind(this);
+ }
+
+ componentDidMount() {
+ this.props.dispatch(getManagementPlans());
+ //TODO fetch farm
+ }
+
+ handleSubmit(sale) {
+ const { dispatch } = this.props;
+ const crop_variety_sale = this.state.chosenOptions.map((c) => {
+ return {
+ sale_value: sale ? sale[c.label].value && parseFloat(sale[c.label].value).toFixed(2) : 0,
+ quantity: sale
+ ? sale[c.label].quantity &&
+ parseFloat(
+ convertToMetric(parseFloat(sale[c.label].quantity), this.state.quantity_unit, 'kg'),
+ )
+ : 0,
+ quantity_unit: this.state.quantity_unit,
+ crop_variety_id: c.value,
+ };
+ });
+ const newSale = {
+ customer_name: sale.name,
+ sale_date: this.state.date,
+ farm_id: this.props.farm.farm_id,
+ crop_variety_sale,
+ };
+ dispatch(addOrUpdateSale(newSale));
+ }
+
+ handleChooseCrop(option) {
+ this.setState({
+ chosenOptions: option,
+ });
+ }
+
+ getCropVarietyOptions = (managementPlans) => {
+ if (!managementPlans || managementPlans.length === 0) {
+ return;
+ }
+
+ let cropVarietyOptions = [];
+ let cropVarietySet = new Set();
+
+ for (let mp of managementPlans) {
+ if (!cropVarietySet.has(mp.crop_variety_id)) {
+ cropVarietyOptions.push({
+ label: mp.crop_variety_name
+ ? `${mp.crop_variety_name}, ${this.props.t(`crop:${mp.crop_translation_key}`)}`
+ : this.props.t(`crop:${mp.crop_translation_key}`),
+ value: mp.crop_variety_id,
+ });
+ cropVarietySet.add(mp.crop_variety_id);
+ }
+ }
+
+ cropVarietyOptions.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0));
+
+ return cropVarietyOptions;
+ };
+
+ render() {
+ let managementPlans = this.props.managementPlans || [];
+ const cropVarietyOptions = this.getCropVarietyOptions(managementPlans);
+ return (
+
+
history.back()} />
+
+ {this.props.t('SALE.ADD_SALE.DATE')}
+ this.setState({ date })}
+ />
+
+ history.push('/finances')}
+ currencySymbol={this.state.currencySymbol}
+ />
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ managementPlans: currentAndPlannedManagementPlansSelector(state),
+ farm: userFarmSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(AddSale));
diff --git a/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/index.js b/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/index.js
deleted file mode 100644
index 895c57afbd..0000000000
--- a/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/index.js
+++ /dev/null
@@ -1,277 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import PageTitle from '../../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../../styles.module.scss';
-import styles from './styles.module.scss';
-import {
- expenseTypeSelector,
- selectedEditExpenseSelector,
- expenseDetailSelector,
- expensesToEditSelector,
-} from '../../selectors';
-import history from '../../../../history';
-import DateContainer from '../../../../components/Inputs/DateContainer';
-import { Field, actions, Form, Control } from 'react-redux-form';
-import footerStyles from '../../../../components/LogFooter/styles.module.scss';
-import { addRemoveExpense } from '../../actions';
-import { Alert } from 'react-bootstrap';
-import { userFarmSelector } from '../../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { numberOnKeyDown } from '../../../../components/Form/Input';
-
-class EditAddExpense extends Component {
- constructor(props) {
- super(props);
- this.state = {
- date: moment(),
- expenseDetail: {},
- expenseNames: {},
- };
- this.setDate = this.setDate.bind(this);
- this.getTypeName = this.getTypeName.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.removeField = this.removeField.bind(this);
- }
-
- componentDidMount() {
- this.props.dispatch(actions.setInitial('financeReducer.forms.expenseDetail'));
- const { selectedEditExpense, expenseToEdit } = this.props;
- let expenseNames = {};
- let formValue = {};
- let date;
- let counter = 0;
- for (let s of selectedEditExpense) {
- expenseNames[s] = this.getTypeName(s);
- }
- this.setState({ expenseNames });
-
- for (let e of expenseToEdit) {
- if (selectedEditExpense.indexOf(e.expense_type_id) > -1) {
- if (!formValue.hasOwnProperty(e.expense_type_id)) {
- if (counter === 0) {
- date = moment(e.expense_date);
- counter++;
- }
- formValue[e.expense_type_id] = [
- {
- note: e.note,
- value: e.value,
- },
- ];
- } else {
- formValue[e.expense_type_id].push({
- note: e.note,
- value: e.value,
- });
- }
- }
- }
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', formValue));
- this.setState({ date });
- }
-
- getTypeName(id) {
- const { expenseTypes } = this.props;
-
- for (let e of expenseTypes) {
- if (e.expense_type_id === id) {
- this.props.t(`expense:${e.expense_translation_key}`);
- }
- }
- return 'NAME NOT FOUND';
- }
-
- addSubExpense(key) {
- this.props.dispatch(
- actions.push(`financeReducer.forms.expenseDetail[${key}]`, {
- note: '',
- value: 0,
- }),
- );
- }
-
- setDate(date) {
- this.setState({
- date: date,
- });
- }
-
- handleSubmit() {
- const { currentExpenseDetail, expenseToEdit } = this.props;
- let data = [];
- let keys = Object.keys(currentExpenseDetail);
- let { farm_id } = this.props.farm;
- let date = this.state.date;
- for (let k of keys) {
- let values = currentExpenseDetail[k];
-
- for (let v of values) {
- if (v.note !== '' && !isNaN(v.value) && v.value > 0) {
- // dumb JS can't retain the Float type if done otherwise
- let value = parseFloat(parseFloat(v.value).toFixed(2));
- let temp = {
- farm_id,
- note: v.note,
- value: value,
- expense_type_id: k,
- expense_date: date,
- };
- data.push(temp);
- }
- }
- }
-
- let expensesToDelete = [];
- for (let e of expenseToEdit) {
- expensesToDelete.push(e.farm_expense_id);
- }
-
- let addRemoveObj = {
- add: data,
- remove: expensesToDelete,
- };
-
- this.props.dispatch(addRemoveExpense(addRemoveObj));
- history.push('/other_expense');
- }
-
- removeField(key, index) {
- const { currentExpenseDetail } = this.props;
- if (index !== 0) {
- let newArray = [];
- let values = currentExpenseDetail[key];
- // can't use splice cuz error: cannot delete property '0' of [object Array]
- for (let i = 0; i < values.length; i++) {
- if (i !== index) {
- newArray.push(values[i]);
- }
- }
- // Deep copy of the read only object
- let newObj = JSON.parse(JSON.stringify(currentExpenseDetail));
- newObj[key] = newArray;
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', newObj));
- } else {
- let newObj = JSON.parse(JSON.stringify(currentExpenseDetail));
- let values = newObj[key];
- if (values.length === 1) {
- let { expenseNames } = this.state;
- delete newObj[key];
- delete expenseNames[key];
- this.setState({ expenseNames });
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', newObj));
- } else {
- let newArr = [];
- for (let i = 1; i < values.length; i++) {
- newArr.push(values[i]);
- }
- newObj[key] = newArr;
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', newObj));
- }
- }
- }
-
- render() {
- const { currentExpenseDetail } = this.props;
- const { expenseNames } = this.state;
- return (
-
-
-
-
- {Object.keys(expenseNames).map((k) => {
- return (
-
- );
- })}
- {Object.keys(expenseNames).length === 0 && (
-
{this.props.t('EXPENSE.EDIT_EXPENSE.REMOVE_ALL')}
- )}
-
-
-
history.push('/finances')}>
- {this.props.t('common:CANCEL')}
-
-
this.handleSubmit()}>
- {this.props.t('common:SAVE')}
-
-
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- expenseTypes: expenseTypeSelector(state),
- selectedEditExpense: selectedEditExpenseSelector(state),
- currentExpenseDetail: expenseDetailSelector(state),
- expenseToEdit: expensesToEditSelector(state),
- farm: userFarmSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(EditAddExpense));
diff --git a/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/styles.module.scss b/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/styles.module.scss
deleted file mode 100644
index 31a96f9e36..0000000000
--- a/packages/webapp/src/containers/Finances/EditExpense/EditAddExpense/styles.module.scss
+++ /dev/null
@@ -1,78 +0,0 @@
-.greenPlus {
- width: 2em;
- height: 2em;
- background: #1b847a;
- font-weight: bolder;
- display: flex;
- align-items: center;
- justify-content: center;
- color: white;
- border-radius: 2em;
-}
-
-.expenseTitle {
- color: #5b6370;
- font-size: 18px;
- font-style: normal;
- font-weight: 600;
- line-height: normal;
- margin-bottom: 10px;
-}
-
-.addContainer {
- width: 70%;
- margin: 18px auto 25px auto;
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: center;
- color: #00756a;
- font-style: normal;
- font-weight: normal;
- line-height: 26px;
- font-size: 16px;
-}
-
-.itemContainer {
- mix-blend-mode: normal;
- border: 1px solid #e5e5e5;
- box-sizing: border-box;
- border-radius: 4px;
- padding: 5% 3%;
-}
-
-.labelInput {
- label {
- word-wrap: break-word;
- font-style: normal;
- font-weight: normal;
- line-height: 26px;
- font-size: 18px;
- letter-spacing: 0.324px;
- color: #4d4d4d;
- }
- input {
- width: 60%;
- height: 37px;
- border: 1px solid #efefef;
- box-sizing: border-box;
- border-radius: 4px;
- padding: 0 5%;
- }
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- align-items: center;
-}
-
-.fieldContainer {
- margin-bottom: 15px;
-}
-
-.removeButton {
- display: flex;
- justify-content: center;
- color: #ef3b7d;
- width: 100%;
-}
diff --git a/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/index.js b/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/index.js
deleted file mode 100644
index 06c701b09a..0000000000
--- a/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/index.js
+++ /dev/null
@@ -1,167 +0,0 @@
-import React, { Component } from 'react';
-import PageTitle from '../../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../../styles.module.scss';
-import styles from './styles.module.scss';
-import { expenseTypeSelector, expensesToEditSelector } from '../../selectors';
-import { Container, Row, Col, Alert } from 'react-bootstrap';
-import EquipImg from '../../../../assets/images/log/equipment.svg';
-import FertImg from '../../../../assets/images/log/fertilizing.svg';
-import PestImg from '../../../../assets/images/log/bug.svg';
-import FueldImg from '../../../../assets/images/log/fuel.svg';
-import MachineImg from '../../../../assets/images/log/machinery.svg';
-import SeedImg from '../../../../assets/images/log/seeding.svg';
-import OtherImg from '../../../../assets/images/log/other.svg';
-import LandImg from '../../../../assets/images/log/land.svg';
-import { setSelectedEditExpense } from '../../actions';
-import history from '../../../../history';
-import { withTranslation } from 'react-i18next';
-
-class EditExpenseCategories extends Component {
- constructor(props) {
- super(props);
- this.state = {
- selectedStyle: {
- width: '80px',
- height: '80px',
- borderRadius: '50px',
- background: '#00756A',
- margin: '0 auto',
- boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.08)',
- },
- unSelectedStyle: {
- width: '80px',
- height: '80px',
- borderRadius: '50px',
- margin: '0 auto',
- background: '#82CF9C',
- boxShadow: '0px 2px 4px rgba(0, 0, 0, 0.08)',
- },
- selectedTypes: [],
- };
-
- this.addRemoveType = this.addRemoveType.bind(this);
- this.nextPage = this.nextPage.bind(this);
- }
-
- componentDidMount() {
- const { expenseToEdit } = this.props;
- let { selectedTypes } = this.state;
- for (let e of expenseToEdit) {
- if (selectedTypes.indexOf(e.expense_type_id) === -1) {
- selectedTypes.push(e.expense_type_id);
- }
- }
- this.setState({ selectedTypes });
- }
-
- nextPage() {
- this.props.dispatch(setSelectedEditExpense(this.state.selectedTypes));
- history.push('/edit_add_expense');
- }
-
- addRemoveType(id) {
- let { selectedTypes } = this.state;
- if (selectedTypes.includes(id)) {
- const index = selectedTypes.indexOf(id);
- selectedTypes.splice(index, 1);
- } else {
- selectedTypes.push(id);
- }
- this.setState({
- selectedTypes,
- });
- }
-
- render() {
- const { expenseTypes } = this.props;
- const { selectedStyle, unSelectedStyle, selectedTypes } = this.state;
- return (
-
-
-
{this.props.t('EXPENSE.EDIT_EXPENSE.DESELECTING_CATEGORY')}
-
-
- {expenseTypes.length > 0 &&
- expenseTypes.map((type) => {
- return (
-
-
-
this.addRemoveType(type.expense_type_id)}
- >
- {type.expense_name === 'Equipment' && (
-
- )}
- {type.expense_name === 'Fertilizer' && (
-
- )}
- {type.expense_name === 'Machinery' && (
-
- )}
- {type.expense_name === 'Pesticide' && (
-
- )}
- {type.expense_name === 'Fuel' && (
-
- )}
- {type.expense_name === 'Land' && (
-
- )}
- {type.expense_name === 'Seeds' && (
-
- )}
- {type.expense_name === 'Other' && (
-
- )}
-
-
- {this.props.t(`expense:${type.expense_translation_key}`)}
-
-
-
- );
- })}
-
-
-
- this.nextPage()}>
- {this.props.t('common:NEXT')}
-
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- expenseTypes: expenseTypeSelector(state),
- expenseToEdit: expensesToEditSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps,
-)(withTranslation()(EditExpenseCategories));
diff --git a/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/styles.module.scss b/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/styles.module.scss
deleted file mode 100644
index 2d5b4b0d6c..0000000000
--- a/packages/webapp/src/containers/Finances/EditExpense/EditExpenseCategories/styles.module.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-.moodContainer {
- width: 80%;
- margin-bottom: 2em;
- height: auto;
-}
-
-.circleImg {
- display: block;
- margin: 0 auto;
- padding-top: 1.5em;
-}
-
-.typeName {
- text-align: center;
-}
-
-.bottomContainer {
- max-width: 1024px;
- width: 100%;
- position: fixed;
- bottom: 0;
- display: flex;
- flex-direction: row;
- justify-content: center;
- font-weight: 600;
- align-items: center;
- padding: 2% 5% 2% 5%;
- margin-left: -5%;
- background: white;
- box-shadow: 0 -5px 5px -5px #333;
- border-radius: 10px;
-}
diff --git a/packages/webapp/src/containers/Finances/EditExpense/TempEditExpense/index.js b/packages/webapp/src/containers/Finances/EditExpense/TempEditExpense/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/EditExpense/TempEditExpense/index.js
rename to packages/webapp/src/containers/Finances/EditExpense/TempEditExpense/index.jsx
diff --git a/packages/webapp/src/containers/Finances/EditSale/index.js b/packages/webapp/src/containers/Finances/EditSale/index.js
deleted file mode 100644
index c1da71c795..0000000000
--- a/packages/webapp/src/containers/Finances/EditSale/index.js
+++ /dev/null
@@ -1,198 +0,0 @@
-import React, { Component } from 'react';
-import PageTitle from '../../../components/PageTitle/v2';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../styles.module.scss';
-import { actions } from 'react-redux-form';
-import SaleForm from '../../../components/Forms/Sale';
-import { selectedSaleSelector } from '../selectors';
-import DateContainer from '../../../components/Inputs/DateContainer';
-import moment from 'moment';
-import { deleteSale, updateSale } from '../actions';
-import { convertFromMetric, convertToMetric, getUnit, roundToTwoDecimal } from '../../../util';
-import ConfirmModal from '../../../components/Modals/Confirm';
-import history from '../../../history';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
-import { getManagementPlans } from '../../saga';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-import { cropVarietyEntitiesSelector } from '../../cropVarietySlice';
-import { cropEntitiesSelector } from '../../cropSlice';
-
-class EditSale extends Component {
- constructor(props) {
- super(props);
- this.props.dispatch(actions.reset('financeReducer.forms.editSale'));
- const sale = this.props.sale || {};
- const chosenOptions =
- sale &&
- sale.crop_variety_sale.map((cvs) => {
- const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[cvs.crop_variety_id];
- const { crop_translation_key } = this.props.cropEntities[crop_id];
- return {
- label: crop_variety_name
- ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
- : this.props.t(`crop:${crop_translation_key}`),
- value: cvs.crop_variety_id,
- };
- });
- const quantity_unit =
- sale?.crop_variety_sale[0].quantity_unit || getUnit(this.props.farm, 'kg', 'lb');
- this.state = {
- date: moment.utc(sale && sale.sale_date),
- quantity_unit,
- chosenOptions,
- currencySymbol: grabCurrencySymbol(this.props.farm),
- };
- sale?.crop_variety_sale.forEach((cvs) => {
- const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[cvs.crop_variety_id];
- const { crop_translation_key } = this.props.cropEntities[crop_id];
- const cropVariety = crop_variety_name
- ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
- : this.props.t(`crop:${crop_translation_key}`);
- this.props.dispatch(
- actions.change(
- `financeReducer.forms.editSale.${cropVariety}.value`,
- cvs.sale_value.toString(),
- ),
- );
- this.props.dispatch(
- actions.change(
- `financeReducer.forms.editSale.${cropVariety}.quantity`,
- roundToTwoDecimal(
- convertFromMetric(cvs.quantity.toString(), this.state.quantity_unit, 'kg').toString(),
- ),
- ),
- );
- });
- this.props.dispatch(actions.change('financeReducer.forms.editSale.name', sale.customer_name));
- this.props.dispatch(
- actions.change('financeReducer.forms.editSale.managementPlan', chosenOptions),
- );
-
- this.handleChooseCrop = this.handleChooseCrop.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- }
-
- componentDidMount() {
- this.props.dispatch(getManagementPlans());
- }
-
- handleChooseCrop(option) {
- this.setState({
- chosenOptions: option,
- });
- }
-
- handleSubmit(form) {
- const { dispatch, sale } = this.props;
-
- const crop_variety_sale = this.state.chosenOptions.map((c) => {
- return {
- sale_value: form?.[c.label]?.value ? parseFloat(form[c.label].value).toFixed(2) : 0,
- quantity: form?.[c.label]?.quantity
- ? convertToMetric(parseFloat(form[c.label].quantity), this.state.quantity_unit, 'kg')
- : 0,
- quantity_unit: this.state.quantity_unit,
- crop_variety_id: c.value,
- };
- });
-
- const editedSale = {
- sale_id: sale.sale_id,
- customer_name: form.name,
- sale_date: this.state.date,
- farm_id: this.props.farm.farm_id,
- crop_variety_sale,
- };
- dispatch(updateSale(editedSale));
- history.push('/finances');
- }
-
- getCropVarietyOptions = (managementPlans) => {
- if (!managementPlans || managementPlans.length === 0) {
- return;
- }
-
- let cropVarietyOptions = [];
- let cropVarietySet = new Set();
-
- for (let mp of managementPlans) {
- if (!cropVarietySet.has(mp.crop_variety_id)) {
- const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[mp.crop_variety_id];
- const { crop_translation_key } = this.props.cropEntities[crop_id];
- cropVarietyOptions.push({
- label: crop_variety_name
- ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
- : this.props.t(`crop:${crop_translation_key}`),
- value: mp.crop_variety_id,
- });
- cropVarietySet.add(mp.crop_variety_id);
- }
- }
-
- cropVarietyOptions.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0));
-
- return cropVarietyOptions;
- };
-
- render() {
- let managementPlans = this.props.managementPlans || [];
- const cropVarietyOptions = this.getCropVarietyOptions(managementPlans);
- return (
-
-
history.goBack()}
- />
-
- {this.props.t('SALE.EDIT_SALE.DATE')}
- this.setState({ date })}
- />
-
- this.setState({ showModal: true })}
- footerText={this.props.t('common:DELETE')}
- currencySymbol={this.state.currencySymbol}
- />
- this.setState({ showModal: false })}
- onConfirm={() => {
- this.props.dispatch(deleteSale(this.props.sale));
- }}
- message={this.props.t('SALE.EDIT_SALE.DELETE_CONFIRMATION')}
- />
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- sale: selectedSaleSelector(state),
- managementPlans: currentAndPlannedManagementPlansSelector(state),
- farm: userFarmSelector(state),
- cropVarietyEntities: cropVarietyEntitiesSelector(state),
- cropEntities: cropEntitiesSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(EditSale));
diff --git a/packages/webapp/src/containers/Finances/EditSale/index.jsx b/packages/webapp/src/containers/Finances/EditSale/index.jsx
new file mode 100644
index 0000000000..20001f1e82
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/EditSale/index.jsx
@@ -0,0 +1,198 @@
+import React, { Component } from 'react';
+import PageTitle from '../../../components/PageTitle/v2';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../styles.module.scss';
+import { actions } from 'react-redux-form';
+import SaleForm from '../../../components/Forms/Sale';
+import { selectedSaleSelector } from '../selectors';
+import DateContainer from '../../../components/Inputs/DateContainer';
+import moment from 'moment';
+import { deleteSale, updateSale } from '../actions';
+import { convertFromMetric, convertToMetric, getUnit, roundToTwoDecimal } from '../../../util';
+import ConfirmModal from '../../../components/Modals/Confirm';
+import history from '../../../history';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
+import { getManagementPlans } from '../../saga';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+import { cropVarietyEntitiesSelector } from '../../cropVarietySlice';
+import { cropEntitiesSelector } from '../../cropSlice';
+
+class EditSale extends Component {
+ constructor(props) {
+ super(props);
+ this.props.dispatch(actions.reset('financeReducer.forms.editSale'));
+ const sale = this.props.sale || {};
+ const chosenOptions =
+ sale &&
+ sale.crop_variety_sale.map((cvs) => {
+ const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[cvs.crop_variety_id];
+ const { crop_translation_key } = this.props.cropEntities[crop_id];
+ return {
+ label: crop_variety_name
+ ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
+ : this.props.t(`crop:${crop_translation_key}`),
+ value: cvs.crop_variety_id,
+ };
+ });
+ const quantity_unit =
+ sale?.crop_variety_sale[0].quantity_unit || getUnit(this.props.farm, 'kg', 'lb');
+ this.state = {
+ date: moment.utc(sale && sale.sale_date),
+ quantity_unit,
+ chosenOptions,
+ currencySymbol: grabCurrencySymbol(),
+ };
+ sale?.crop_variety_sale.forEach((cvs) => {
+ const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[cvs.crop_variety_id];
+ const { crop_translation_key } = this.props.cropEntities[crop_id];
+ const cropVariety = crop_variety_name
+ ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
+ : this.props.t(`crop:${crop_translation_key}`);
+ this.props.dispatch(
+ actions.change(
+ `financeReducer.forms.editSale.${cropVariety}.value`,
+ cvs.sale_value.toString(),
+ ),
+ );
+ this.props.dispatch(
+ actions.change(
+ `financeReducer.forms.editSale.${cropVariety}.quantity`,
+ roundToTwoDecimal(
+ convertFromMetric(cvs.quantity.toString(), this.state.quantity_unit, 'kg').toString(),
+ ),
+ ),
+ );
+ });
+ this.props.dispatch(actions.change('financeReducer.forms.editSale.name', sale.customer_name));
+ this.props.dispatch(
+ actions.change('financeReducer.forms.editSale.managementPlan', chosenOptions),
+ );
+
+ this.handleChooseCrop = this.handleChooseCrop.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ }
+
+ componentDidMount() {
+ this.props.dispatch(getManagementPlans());
+ }
+
+ handleChooseCrop(option) {
+ this.setState({
+ chosenOptions: option,
+ });
+ }
+
+ handleSubmit(form) {
+ const { dispatch, sale } = this.props;
+
+ const crop_variety_sale = this.state.chosenOptions.map((c) => {
+ return {
+ sale_value: form?.[c.label]?.value ? parseFloat(form[c.label].value).toFixed(2) : 0,
+ quantity: form?.[c.label]?.quantity
+ ? convertToMetric(parseFloat(form[c.label].quantity), this.state.quantity_unit, 'kg')
+ : 0,
+ quantity_unit: this.state.quantity_unit,
+ crop_variety_id: c.value,
+ };
+ });
+
+ const editedSale = {
+ sale_id: sale.sale_id,
+ customer_name: form.name,
+ sale_date: this.state.date,
+ farm_id: this.props.farm.farm_id,
+ crop_variety_sale,
+ };
+ dispatch(updateSale(editedSale));
+ history.push('/finances');
+ }
+
+ getCropVarietyOptions = (managementPlans) => {
+ if (!managementPlans || managementPlans.length === 0) {
+ return;
+ }
+
+ let cropVarietyOptions = [];
+ let cropVarietySet = new Set();
+
+ for (let mp of managementPlans) {
+ if (!cropVarietySet.has(mp.crop_variety_id)) {
+ const { crop_variety_name, crop_id } = this.props.cropVarietyEntities[mp.crop_variety_id];
+ const { crop_translation_key } = this.props.cropEntities[crop_id];
+ cropVarietyOptions.push({
+ label: crop_variety_name
+ ? `${crop_variety_name}, ${this.props.t(`crop:${crop_translation_key}`)}`
+ : this.props.t(`crop:${crop_translation_key}`),
+ value: mp.crop_variety_id,
+ });
+ cropVarietySet.add(mp.crop_variety_id);
+ }
+ }
+
+ cropVarietyOptions.sort((a, b) => (a.label > b.label ? 1 : b.label > a.label ? -1 : 0));
+
+ return cropVarietyOptions;
+ };
+
+ render() {
+ let managementPlans = this.props.managementPlans || [];
+ const cropVarietyOptions = this.getCropVarietyOptions(managementPlans);
+ return (
+
+
history.back()}
+ />
+
+ {this.props.t('SALE.EDIT_SALE.DATE')}
+ this.setState({ date })}
+ />
+
+ this.setState({ showModal: true })}
+ footerText={this.props.t('common:DELETE')}
+ currencySymbol={this.state.currencySymbol}
+ />
+ this.setState({ showModal: false })}
+ onConfirm={() => {
+ this.props.dispatch(deleteSale(this.props.sale));
+ }}
+ message={this.props.t('SALE.EDIT_SALE.DELETE_CONFIRMATION')}
+ />
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ sale: selectedSaleSelector(state),
+ managementPlans: currentAndPlannedManagementPlansSelector(state),
+ farm: userFarmSelector(state),
+ cropVarietyEntities: cropVarietyEntitiesSelector(state),
+ cropEntities: cropEntitiesSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(EditSale));
diff --git a/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.js b/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.js
deleted file mode 100644
index 89be8166a5..0000000000
--- a/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { useDispatch, useSelector } from 'react-redux';
-import FinanceGroup from '../../../components/Finances/FinanceGroup';
-import { getManagementPlanCardDate, getManagementPlanTileDate } from '../../../util/moment';
-import { cropVarietyEntitiesSelector, cropVarietySelector } from '../../cropVarietySlice';
-import { setSelectedSale } from '../actions';
-import { convertFromMetric, roundToTwoDecimal } from '../../../util';
-import { useTranslation } from 'react-i18next';
-import { getTasksMinMaxDate } from '../../Task/getTasksMinMaxDate';
-import { taskEntitiesByManagementPlanIdSelector } from '../../taskSlice';
-
-const EstimatedCropRevenue = ({ cropVarietyId, managementPlans, history, ...props }) => {
- const dispatch = useDispatch();
- const { t } = useTranslation();
-
- const cropVariety = useSelector(cropVarietySelector(cropVarietyId));
- const tasksByManagementPlanId = useSelector(taskEntitiesByManagementPlanIdSelector);
-
- const total = managementPlans.reduce((acc, plan) => {
- const { estimated_revenue } = plan;
- if (estimated_revenue) {
- return acc + estimated_revenue;
- }
- return acc;
- }, 0);
-
- const { crop } = cropVariety;
- const groupTitle = cropVariety.crop_variety_name
- ? `${cropVariety.crop_variety_name}, ${t(`crop:${crop.crop_translation_key}`)}`
- : t(`crop:${crop.crop_translation_key}`);
-
- return (
- {
- const tasks = tasksByManagementPlanId[plan.management_plan_id];
- const firstTaskDate = getTasksMinMaxDate(tasks).startDate;
- return {
- title: plan.name,
- subtitle: `${getManagementPlanTileDate(firstTaskDate)}`,
- amount: plan.estimated_revenue || 0,
- isPlan: true,
- onClickForward: () =>
- history.push(`/finances/estimated_revenue/plan/${plan.management_plan_id}`),
- };
- })}
- isDropDown
- {...props}
- />
- );
-};
-
-EstimatedCropRevenue.prototype = {
- isDropDown: PropTypes.bool,
-};
-
-export default EstimatedCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.jsx b/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.jsx
new file mode 100644
index 0000000000..dd3546493d
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/EstimatedCropRevenue/index.jsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { useDispatch, useSelector } from 'react-redux';
+import FinanceGroup from '../../../components/Finances/FinanceGroup';
+import { getManagementPlanTileDate } from '../../../util/moment';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { useTranslation } from 'react-i18next';
+import { getTasksMinMaxDate } from '../../Task/getTasksMinMaxDate';
+import { taskEntitiesByManagementPlanIdSelector } from '../../taskSlice';
+
+const EstimatedCropRevenue = ({ cropVarietyId, managementPlans, history, ...props }) => {
+ const dispatch = useDispatch();
+ const { t } = useTranslation();
+
+ const cropVariety = useSelector(cropVarietySelector(cropVarietyId));
+ const tasksByManagementPlanId = useSelector(taskEntitiesByManagementPlanIdSelector);
+
+ const total = managementPlans.reduce((acc, plan) => {
+ const { estimated_revenue } = plan;
+ if (estimated_revenue) {
+ return acc + estimated_revenue;
+ }
+ return acc;
+ }, 0);
+
+ const { crop } = cropVariety;
+ const groupTitle = cropVariety.crop_variety_name
+ ? `${cropVariety.crop_variety_name}, ${t(`crop:${crop.crop_translation_key}`)}`
+ : t(`crop:${crop.crop_translation_key}`);
+
+ return (
+ {
+ const tasks = tasksByManagementPlanId[plan.management_plan_id];
+ const firstTaskDate = getTasksMinMaxDate(tasks).startDate;
+ return {
+ title: plan.name,
+ subtitle: `${getManagementPlanTileDate(firstTaskDate)}`,
+ amount: plan.estimated_revenue || 0,
+ isPlan: true,
+ onClickForward: () =>
+ history.push(`/finances/estimated_revenue/plan/${plan.management_plan_id}`),
+ };
+ })}
+ isDropDown
+ {...props}
+ />
+ );
+};
+
+EstimatedCropRevenue.prototype = {
+ isDropDown: PropTypes.bool,
+};
+
+export default EstimatedCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/EstimatedRevenue/index.js b/packages/webapp/src/containers/Finances/EstimatedRevenue/index.js
deleted file mode 100644
index f6dc8e7bc3..0000000000
--- a/packages/webapp/src/containers/Finances/EstimatedRevenue/index.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import React, { useMemo } from 'react';
-import Layout from '../../../components/Layout';
-import PageTitle from '../../../components/PageTitle/v2';
-import { useSelector } from 'react-redux';
-import { useTranslation } from 'react-i18next';
-import { useForm } from 'react-hook-form';
-import moment from 'moment';
-import WholeFarmRevenue from '../../../components/Finances/WholeFarmRevenue';
-import { Semibold } from '../../../components/Typography';
-import DateRangePicker from '../../../components/Form/DateRangePicker';
-import EstimatedCropRevenue from '../EstimatedCropRevenue';
-import FinanceListHeader from '../../../components/Finances/FinanceListHeader';
-import { managementPlansSelector } from '../../managementPlanSlice';
-import { taskEntitiesByManagementPlanIdSelector } from '../../taskSlice';
-import { isTaskType } from '../../Task/useIsTaskType';
-
-export default function EstimatedRevenue({ history, match }) {
- const { t } = useTranslation();
- const onGoBack = () => history.push(`/finances`);
- const managementPlans = useSelector(managementPlansSelector);
- const tasksByManagementPlanId = useSelector(taskEntitiesByManagementPlanIdSelector);
-
- const {
- register,
- getValues,
- watch,
- control,
- formState: { errors, isValid },
- } = useForm({
- mode: 'onBlur',
- shouldUnregister: true,
- defaultValues: {
- from_date: moment().startOf('year').format('YYYY-MM-DD'),
- to_date: moment().endOf('year').format('YYYY-MM-DD'),
- },
- });
-
- const fromDate = watch('from_date');
- const toDate = watch('to_date');
-
- const estimatedRevenueItems = useMemo(() => {
- return managementPlans
- .filter(({ abandon_date }) => !abandon_date)
- .reduce((acc, plan) => {
- const { crop_variety_id } = plan;
- if (!acc[crop_variety_id]) acc[crop_variety_id] = [];
-
- const harvestTasks =
- tasksByManagementPlanId[plan.management_plan_id]?.filter((task) =>
- isTaskType(task.taskType, 'HARVEST_TASK'),
- ) || [];
- const harvestDates = harvestTasks?.map((task) =>
- moment(task.due_date).utc().format('YYYY-MM-DD'),
- );
- if (
- harvestDates.some(
- (harvestDate) =>
- new Date(harvestDate) >= new Date(fromDate) &&
- new Date(harvestDate) <= new Date(toDate),
- )
- ) {
- acc[crop_variety_id].push(plan);
- }
- return acc;
- }, {});
- }, [managementPlans, fromDate, toDate]);
-
- const total = Object.entries(estimatedRevenueItems).reduce((acc, [crop_variety_id, plans]) => {
- const varietyTotal = plans.reduce((acc, plan) => {
- const { estimated_revenue } = plan;
- return acc + estimated_revenue;
- }, 0);
- return acc + varietyTotal;
- }, 0);
-
- return (
-
-
-
-
-
-
- {t('FINANCES.VIEW_WITHIN_DATE_RANGE')}
-
-
-
-
- {Object.entries(estimatedRevenueItems).map(
- ([crop_variety_id, plans]) =>
- plans.length > 0 && (
-
- ),
- )}
-
- );
-}
diff --git a/packages/webapp/src/containers/Finances/EstimatedRevenue/index.jsx b/packages/webapp/src/containers/Finances/EstimatedRevenue/index.jsx
new file mode 100644
index 0000000000..a232f4f192
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/EstimatedRevenue/index.jsx
@@ -0,0 +1,142 @@
+import React, { useEffect, useMemo } from 'react';
+import Layout from '../../../components/Layout';
+import PageTitle from '../../../components/PageTitle/v2';
+import { useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import { useForm } from 'react-hook-form';
+import moment from 'moment';
+import WholeFarmRevenue from '../../../components/Finances/WholeFarmRevenue';
+import { Semibold } from '../../../components/Typography';
+import DateRangePicker from '../../../components/Form/DateRangePicker';
+import EstimatedCropRevenue from '../EstimatedCropRevenue';
+import FinanceListHeader from '../../../components/Finances/FinanceListHeader';
+import { managementPlansSelector } from '../../managementPlanSlice';
+import { taskEntitiesByManagementPlanIdSelector } from '../../taskSlice';
+import { isTaskType } from '../../Task/useIsTaskType';
+import { dateRangeSelector } from '../selectors';
+import { setDateRange } from '../actions';
+
+export default function EstimatedRevenue({ history, match }) {
+ const { t } = useTranslation();
+ const onGoBack = () => history.push(`/finances`);
+ const managementPlans = useSelector(managementPlansSelector);
+ const tasksByManagementPlanId = useSelector(taskEntitiesByManagementPlanIdSelector);
+ const dateRange = useSelector(dateRangeSelector);
+ const dispatch = useDispatch();
+
+ const year = new Date().getFullYear();
+
+ const {
+ register,
+ getValues,
+ watch,
+ control,
+ formState: { errors, isValid },
+ } = useForm({
+ mode: 'onBlur',
+ shouldUnregister: true,
+ defaultValues: {
+ from_date: dateRange?.startDate
+ ? new Date(
+ typeof dateRange.startDate === 'string'
+ ? dateRange.startDate.split('T')[0] + 'T00:00:00.000Z'
+ : dateRange.startDate,
+ )
+ .toISOString()
+ .split('T')[0]
+ : `${year}-01-01`,
+ to_date: dateRange?.endDate
+ ? new Date(
+ typeof dateRange.endDate === 'string'
+ ? dateRange.endDate.split('T')[0] + 'T00:00:00.000Z'
+ : dateRange.endDate,
+ )
+ .toISOString()
+ .split('T')[0]
+ : `${year}-12-31`,
+ },
+ });
+
+ const fromDate = watch('from_date');
+ const toDate = watch('to_date');
+
+ useEffect(() => {
+ dispatch(setDateRange({ startDate: fromDate, endDate: toDate }));
+ }, [fromDate, toDate]);
+
+ const estimatedRevenueItems = useMemo(() => {
+ return managementPlans
+ .filter(({ abandon_date }) => !abandon_date)
+ .reduce((acc, plan) => {
+ const { crop_variety_id } = plan;
+ if (!acc[crop_variety_id]) acc[crop_variety_id] = [];
+
+ const harvestTasks =
+ tasksByManagementPlanId[plan.management_plan_id]?.filter((task) =>
+ isTaskType(task.taskType, 'HARVEST_TASK'),
+ ) || [];
+ const harvestDates = harvestTasks?.map((task) =>
+ moment(task.due_date).utc().format('YYYY-MM-DD'),
+ );
+ if (
+ harvestDates.some(
+ (harvestDate) =>
+ new Date(harvestDate) >= new Date(fromDate) &&
+ new Date(harvestDate) <= new Date(toDate),
+ )
+ ) {
+ acc[crop_variety_id].push(plan);
+ }
+ return acc;
+ }, {});
+ }, [managementPlans, fromDate, toDate]);
+
+ const total = Object.entries(estimatedRevenueItems).reduce((acc, [crop_variety_id, plans]) => {
+ const varietyTotal = plans.reduce((acc, plan) => {
+ const { estimated_revenue } = plan;
+ return acc + estimated_revenue;
+ }, 0);
+ return acc + varietyTotal;
+ }, 0);
+
+ return (
+
+
+
+
+
+
+ {t('FINANCES.VIEW_WITHIN_DATE_RANGE')}
+
+
+
+
+ {Object.entries(estimatedRevenueItems).map(
+ ([crop_variety_id, plans]) =>
+ plans.length > 0 && (
+
+ ),
+ )}
+
+ );
+}
diff --git a/packages/webapp/src/containers/Finances/ExpenseDetail/index.js b/packages/webapp/src/containers/Finances/ExpenseDetail/index.js
deleted file mode 100644
index 7837764ed0..0000000000
--- a/packages/webapp/src/containers/Finances/ExpenseDetail/index.js
+++ /dev/null
@@ -1,222 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import PageTitle from '../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../styles.module.scss';
-import styles from './styles.module.scss';
-import { expenseSelector, expenseToDetailSelector, expenseTypeSelector } from '../selectors';
-import { tempDeleteExpense, tempSetEditExpense } from '../actions';
-import history from '../../../history';
-import ConfirmModal from '../../../components/Modals/Confirm';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { Semibold } from '../../../components/Typography';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-import DropdownButton from '../../../components/Form/DropDownButton';
-import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
-
-class ExpenseDetail extends Component {
- constructor(props) {
- super(props);
- this.state = {
- date: null,
- expenseItems: [],
- total: 0,
- filteredExpenses: [],
- currencySymbol: '$',
- showModal: false, // for confirming deleting all expenses
- };
- this.getExpensesByDate = this.getExpensesByDate.bind(this);
- this.getExpenseType = this.getExpenseType.bind(this);
- // this.editExpenses = this.editExpenses.bind(this);
- this.editExpense = this.editExpense.bind(this);
- }
-
- componentDidMount() {
- const { farm, expense } = this.props;
- this.setState({ currencySymbol: grabCurrencySymbol(farm) });
- const language = getLanguageFromLocalStorage();
- const date = moment(expense.expense_date).locale(language).format('MMM DD, YYYY');
- this.setState({
- date,
- });
- this.getExpensesByDate();
- }
-
- getExpensesByDate() {
- const { expenses, expense } = this.props;
- let targetDate = moment(expense.expense_date).format('YYYY-MM-DD');
- let dict = {};
- let total = 0;
- let filteredExpenses = [];
- for (let e of expenses) {
- let expenseDate = moment(e.expense_date).format('YYYY-MM-DD');
- if (targetDate === expenseDate) {
- let id = e.expense_type_id;
- total += parseFloat(e.value);
- filteredExpenses.push(e);
- if (!dict.hasOwnProperty(id)) {
- dict[id] = {
- type_name: this.getExpenseType(id),
- items: [
- {
- note: e.note,
- value: e.value,
- },
- ],
- };
- } else {
- dict[id].items.push({
- note: e.note,
- value: e.value,
- });
- }
- }
- }
-
- this.setState({
- expenseItems: Object.values(dict),
- total: total.toFixed(2),
- filteredExpenses,
- });
- }
-
- getExpenseType(id) {
- const { expenseTypes } = this.props;
- for (let type of expenseTypes) {
- if (type.expense_type_id === id) {
- return this.props.t(`expense:${type.expense_translation_key}`);
- }
- }
- return 'TYPE_NOT_FOUND';
- }
-
- handleDeleteExpenses = () => {
- this.setState({ showModal: true });
- };
-
- // TODO: replace when expense items are split by expense
- deleteExpense = () => {
- const { expense } = this.props;
- this.props.dispatch(tempDeleteExpense(expense.expense_item_id));
- };
- // deleteExpenses = () => {
- // // eslint-disable-next-line
- // let farmIDs = [];
- // const { filteredExpenses } = this.state;
- // for (let f of filteredExpenses) {
- // farmIDs.push(f.farm_expense_id);
- // }
- // if (farmIDs.length > 0) {
- // this.props.dispatch(deleteExpenses(farmIDs));
- // history.push('/other_expense');
- // }
- // };
-
- //TODO remove edit expense related functions
- editExpense() {
- // editExpenses() {
- // TODO: use the commented out code for when expense items are split by expense
- // const { filteredExpenses } = this.state;
- // this.props.dispatch(setEditExpenses(filteredExpenses));
- // history.push('/edit_expense_categories');
-
- // temporary implementation to edit expense items separately
- const { expense } = this.props;
- this.props.dispatch(tempSetEditExpense(expense));
- history.push('/edit_expense');
- }
-
- render() {
- const { date, expenseItems, total } = this.state;
- const { expense } = this.props;
- const dropDown = 0;
- const options = [
- {
- text: this.props.t('common:EDIT'),
- onClick: () => this.editExpense(),
- },
- { text: this.props.t('common:DELETE'), onClick: () => this.handleDeleteExpenses() },
- ];
-
- return (
-
-
-
-
{date}
-
- {this.props.t('SALE.EXPENSE_DETAIL.ACTION')}
-
-
-
-
-
{this.props.t('SALE.EXPENSE_DETAIL.DESCRIPTION')}
-
{this.props.t('SALE.EXPENSE_DETAIL.COST')}
-
- {/* {expenseItems.length > 0 &&
- expenseItems.map((e) => {
- return (
-
-
- {e.type_name}
-
- {e.items.length > 0 &&
- e.items.map((i) => {
- return (
-
-
{'- ' + i.note}
-
- {this.state.currencySymbol + i.value.toFixed(2).toString()}
-
-
- );
- })}
-
- );
- })} */}
-
-
- {expense.type}
-
-
-
{'- ' + expense.note}
-
{expense.amount}
-
-
- {/*
-
{this.props.t('SALE.EXPENSE_DETAIL.TOTAL')}
-
- {this.state.currencySymbol + total}
-
-
*/}
-
this.setState({ showModal: false })}
- onConfirm={() => {
- this.deleteExpense();
- this.setState({ showModal: false });
- }}
- message={this.props.t('SALE.EXPENSE_DETAIL.TEMP_DELETE_CONFIRMATION')}
- />
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- // expense_detail_date: expenseDetailDateSelector(state),
- expenses: expenseSelector(state),
- expenseTypes: expenseTypeSelector(state),
- farm: userFarmSelector(state),
- expense: expenseToDetailSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(ExpenseDetail));
diff --git a/packages/webapp/src/containers/Finances/ExpenseDetail/index.jsx b/packages/webapp/src/containers/Finances/ExpenseDetail/index.jsx
new file mode 100644
index 0000000000..e8f37f077d
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/ExpenseDetail/index.jsx
@@ -0,0 +1,222 @@
+import React, { Component } from 'react';
+import moment from 'moment';
+import PageTitle from '../../../components/PageTitle';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../styles.module.scss';
+import styles from './styles.module.scss';
+import { expenseSelector, expenseToDetailSelector, expenseTypeSelector } from '../selectors';
+import { tempDeleteExpense, tempSetEditExpense } from '../actions';
+import history from '../../../history';
+import ConfirmModal from '../../../components/Modals/Confirm';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { Semibold } from '../../../components/Typography';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+import DropdownButton from '../../../components/Form/DropDownButton';
+import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
+
+class ExpenseDetail extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ date: null,
+ expenseItems: [],
+ total: 0,
+ filteredExpenses: [],
+ currencySymbol: '$',
+ showModal: false, // for confirming deleting all expenses
+ };
+ this.getExpensesByDate = this.getExpensesByDate.bind(this);
+ this.getExpenseType = this.getExpenseType.bind(this);
+ // this.editExpenses = this.editExpenses.bind(this);
+ this.editExpense = this.editExpense.bind(this);
+ }
+
+ componentDidMount() {
+ const { farm, expense } = this.props;
+ this.setState({ currencySymbol: grabCurrencySymbol() });
+ const language = getLanguageFromLocalStorage();
+ const date = moment(expense.expense_date).locale(language).format('MMM DD, YYYY');
+ this.setState({
+ date,
+ });
+ this.getExpensesByDate();
+ }
+
+ getExpensesByDate() {
+ const { expenses, expense } = this.props;
+ let targetDate = moment(expense.expense_date).format('YYYY-MM-DD');
+ let dict = {};
+ let total = 0;
+ let filteredExpenses = [];
+ for (let e of expenses) {
+ let expenseDate = moment(e.expense_date).format('YYYY-MM-DD');
+ if (targetDate === expenseDate) {
+ let id = e.expense_type_id;
+ total += parseFloat(e.value);
+ filteredExpenses.push(e);
+ if (!dict.hasOwnProperty(id)) {
+ dict[id] = {
+ type_name: this.getExpenseType(id),
+ items: [
+ {
+ note: e.note,
+ value: e.value,
+ },
+ ],
+ };
+ } else {
+ dict[id].items.push({
+ note: e.note,
+ value: e.value,
+ });
+ }
+ }
+ }
+
+ this.setState({
+ expenseItems: Object.values(dict),
+ total: total.toFixed(2),
+ filteredExpenses,
+ });
+ }
+
+ getExpenseType(id) {
+ const { expenseTypes } = this.props;
+ for (let type of expenseTypes) {
+ if (type.expense_type_id === id) {
+ return this.props.t(`expense:${type.expense_translation_key}`);
+ }
+ }
+ return 'TYPE_NOT_FOUND';
+ }
+
+ handleDeleteExpenses = () => {
+ this.setState({ showModal: true });
+ };
+
+ // TODO: replace when expense items are split by expense
+ deleteExpense = () => {
+ const { expense } = this.props;
+ this.props.dispatch(tempDeleteExpense(expense.expense_item_id));
+ };
+ // deleteExpenses = () => {
+ // // eslint-disable-next-line
+ // let farmIDs = [];
+ // const { filteredExpenses } = this.state;
+ // for (let f of filteredExpenses) {
+ // farmIDs.push(f.farm_expense_id);
+ // }
+ // if (farmIDs.length > 0) {
+ // this.props.dispatch(deleteExpenses(farmIDs));
+ // history.push('/other_expense');
+ // }
+ // };
+
+ //TODO remove edit expense related functions
+ editExpense() {
+ // editExpenses() {
+ // TODO: use the commented out code for when expense items are split by expense
+ // const { filteredExpenses } = this.state;
+ // this.props.dispatch(setEditExpenses(filteredExpenses));
+ // history.push('/edit_expense_categories');
+
+ // temporary implementation to edit expense items separately
+ const { expense } = this.props;
+ this.props.dispatch(tempSetEditExpense(expense));
+ history.push('/edit_expense');
+ }
+
+ render() {
+ const { date, expenseItems, total } = this.state;
+ const { expense } = this.props;
+ const dropDown = 0;
+ const options = [
+ {
+ text: this.props.t('common:EDIT'),
+ onClick: () => this.editExpense(),
+ },
+ { text: this.props.t('common:DELETE'), onClick: () => this.handleDeleteExpenses() },
+ ];
+
+ return (
+
+
+
+
{date}
+
+ {this.props.t('SALE.EXPENSE_DETAIL.ACTION')}
+
+
+
+
+
{this.props.t('SALE.EXPENSE_DETAIL.DESCRIPTION')}
+
{this.props.t('SALE.EXPENSE_DETAIL.COST')}
+
+ {/* {expenseItems.length > 0 &&
+ expenseItems.map((e) => {
+ return (
+
+
+ {e.type_name}
+
+ {e.items.length > 0 &&
+ e.items.map((i) => {
+ return (
+
+
{'- ' + i.note}
+
+ {this.state.currencySymbol + i.value.toFixed(2).toString()}
+
+
+ );
+ })}
+
+ );
+ })} */}
+
+
+ {expense.type}
+
+
+
{'- ' + expense.note}
+
{expense.amount}
+
+
+ {/*
+
{this.props.t('SALE.EXPENSE_DETAIL.TOTAL')}
+
+ {this.state.currencySymbol + total}
+
+
*/}
+
this.setState({ showModal: false })}
+ onConfirm={() => {
+ this.deleteExpense();
+ this.setState({ showModal: false });
+ }}
+ message={this.props.t('SALE.EXPENSE_DETAIL.TEMP_DELETE_CONFIRMATION')}
+ />
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ // expense_detail_date: expenseDetailDateSelector(state),
+ expenses: expenseSelector(state),
+ expenseTypes: expenseTypeSelector(state),
+ farm: userFarmSelector(state),
+ expense: expenseToDetailSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(ExpenseDetail));
diff --git a/packages/webapp/src/containers/Finances/Labour/Crop/index.js b/packages/webapp/src/containers/Finances/Labour/Crop/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/Labour/Crop/index.js
rename to packages/webapp/src/containers/Finances/Labour/Crop/index.jsx
diff --git a/packages/webapp/src/containers/Finances/Labour/Employee/index.js b/packages/webapp/src/containers/Finances/Labour/Employee/index.js
deleted file mode 100644
index ccb443ae7d..0000000000
--- a/packages/webapp/src/containers/Finances/Labour/Employee/index.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import Table from '../../../../components/Table';
-import moment from 'moment';
-import { useTranslation } from 'react-i18next';
-import { userFarmsByFarmSelector } from '../../../userFarmSlice';
-import { useSelector } from 'react-redux';
-
-const Employee = ({ currencySymbol, tasks, startDate, endDate }) => {
- let data = [];
- let sortObj = {};
- const { t } = useTranslation();
- const userFarmsOfFarm = useSelector(userFarmsByFarmSelector);
- for (let task of tasks) {
- const assignee = userFarmsOfFarm.find((user) => user.user_id === task.assignee_user_id);
- const completedTime = moment(task.completed_time);
- const abandonedTime = moment(task.abandoned_time);
- if (
- ( completedTime.isSameOrAfter(startDate, 'day') &&
- completedTime.isSameOrBefore(endDate, 'day') &&
- task.duration) ||
- ( abandonedTime.isSameOrAfter(startDate, 'day') &&
- abandonedTime.isSameOrBefore(endDate, 'day') &&
- task.duration)
- ) {
- if (sortObj.hasOwnProperty(task.assignee_user_id)) {
- let referenceObj = sortObj[task.assignee_user_id];
- const currentWorkedTime = hourlyTwoDecimals(referenceObj.time);
- referenceObj.wage_amount =
- (currentWorkedTime * referenceObj.wage_amount +
- hourlyTwoDecimals(task.duration) * task.wage_at_moment) /
- (currentWorkedTime + hourlyTwoDecimals(task.duration));
- referenceObj.time = referenceObj.time + Number(task.duration);
- } else {
- let wage_amount = 0;
-
- // if (s.wage.type === 'hourly') {
- // wage_amount = Number(parseFloat(s.wage_at_moment).toFixed(2));
- // }
- wage_amount = Number(parseFloat(task.wage_at_moment).toFixed(2));
- sortObj[task.assignee_user_id] = {
- time: Number(task.duration),
- wage_amount,
- employee: `${assignee.first_name} ${assignee.last_name.substring(0, 1).toUpperCase()}.`,
- shift_numbers: 1,
- };
- }
- }
- }
-
- let keys = Object.keys(sortObj);
-
- for (let k of keys) {
- let timeInHour = (sortObj[k].time / 60).toFixed(2);
- data.push({
- employee: sortObj[k].employee,
- time: timeInHour.toString() + ' HR',
- labour_cost:
- currencySymbol +
- Number((sortObj[k].time / 60) * sortObj[k].wage_amount)
- .toFixed(2)
- .toString(),
- });
- }
-
- function hourlyTwoDecimals(number) {
- return Number((number / 60).toFixed(2));
- }
-
- const columns = [
- {
- id: 'employee',
- Header: t('SALE.LABOUR.TABLE.EMPLOYEE'),
- accessor: (d) => d.employee,
- minWidth: 80,
- },
- {
- id: 'time',
- Header: t('SALE.LABOUR.TABLE.TIME'),
- accessor: (d) => d.time,
- minWidth: 75,
- },
- {
- id: 'labour_cost',
- Header: t('SALE.LABOUR.TABLE.LABOUR_COST'),
- accessor: (d) => d.labour_cost,
- },
- ];
-
- return (
-
- );
-};
-
-export default Employee;
diff --git a/packages/webapp/src/containers/Finances/Labour/Employee/index.jsx b/packages/webapp/src/containers/Finances/Labour/Employee/index.jsx
new file mode 100644
index 0000000000..14855966ee
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/Labour/Employee/index.jsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import Table from '../../../../components/Table';
+import moment from 'moment';
+import { useTranslation } from 'react-i18next';
+import { userFarmsByFarmSelector } from '../../../userFarmSlice';
+import { useSelector } from 'react-redux';
+import { roundToTwoDecimal } from '../../../../util';
+
+const Employee = ({ currencySymbol, tasks, startDate, endDate }) => {
+ let data = [];
+ let sortObj = {};
+ const { t } = useTranslation();
+ const userFarmsOfFarm = useSelector(userFarmsByFarmSelector);
+ for (let task of tasks) {
+ const assignee = userFarmsOfFarm.find((user) => user.user_id === task.assignee_user_id);
+ const completedTime = moment(task.complete_date);
+ const abandonedTime = moment(task.abandon_date);
+ if (
+ (completedTime.isSameOrAfter(startDate, 'day') &&
+ completedTime.isSameOrBefore(endDate, 'day') &&
+ task.duration) ||
+ (abandonedTime.isSameOrAfter(startDate, 'day') &&
+ abandonedTime.isSameOrBefore(endDate, 'day') &&
+ task.duration)
+ ) {
+ const minutes = parseInt(task.duration, 10);
+ const hours = roundToTwoDecimal(minutes / 60);
+ const rate = roundToTwoDecimal(task.wage_at_moment);
+ const labour_cost = roundToTwoDecimal(rate * hours);
+
+ if (sortObj.hasOwnProperty(task.assignee_user_id)) {
+ let referenceObj = sortObj[task.assignee_user_id];
+ referenceObj.labour_cost = roundToTwoDecimal(roundToTwoDecimal(referenceObj.labour_cost) + labour_cost);
+ referenceObj.hours = roundToTwoDecimal(referenceObj.hours + hours);
+ } else {
+ sortObj[task.assignee_user_id] = {
+ hours,
+ labour_cost,
+ employee: `${assignee.first_name} ${assignee.last_name.substring(0, 1).toUpperCase()}.`,
+ };
+ }
+ }
+ }
+
+ let keys = Object.keys(sortObj);
+
+ for (let k of keys) {
+ data.push({
+ employee: sortObj[k].employee,
+ time: sortObj[k].hours.toFixed(2) + ' HR',
+ labour_cost: currencySymbol + sortObj[k].labour_cost.toFixed(2),
+ });
+ }
+
+ const columns = [
+ {
+ id: 'employee',
+ Header: t('SALE.LABOUR.TABLE.EMPLOYEE'),
+ accessor: (d) => d.employee,
+ minWidth: 80,
+ },
+ {
+ id: 'time',
+ Header: t('SALE.LABOUR.TABLE.TIME'),
+ accessor: (d) => d.time,
+ minWidth: 75,
+ },
+ {
+ id: 'labour_cost',
+ Header: t('SALE.LABOUR.TABLE.LABOUR_COST'),
+ accessor: (d) => d.labour_cost,
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export default Employee;
diff --git a/packages/webapp/src/containers/Finances/Labour/Task/index.js b/packages/webapp/src/containers/Finances/Labour/Task/index.js
deleted file mode 100644
index 78580321c6..0000000000
--- a/packages/webapp/src/containers/Finances/Labour/Task/index.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import Table from '../../../../components/Table';
-import moment from 'moment';
-import { useTranslation } from 'react-i18next';
-
-const Task = ({ currencySymbol, tasks, startDate, endDate }) => {
- let data = [];
- let sortObj = {};
- const { t } = useTranslation(['translation', 'task']);
- for (let task of tasks) {
- const completedTime = moment(task.completed_time);
- const abandonedTime = moment(task.abandoned_time);
- if (
- ( completedTime.isSameOrAfter(startDate, 'day') &&
- completedTime.isSameOrBefore(endDate, 'day') &&
- task.duration) ||
- ( abandonedTime.isSameOrAfter(startDate, 'day') &&
- abandonedTime.isSameOrBefore(endDate, 'day') &&
- task.duration)
- ) {
- if (sortObj.hasOwnProperty(task.task_type_id)) {
- sortObj[task.task_type_id].time += parseInt(task.duration, 10);
- sortObj[task.task_type_id].labour_cost +=
- parseFloat(task.wage_at_moment) * (task.duration / 60);
- } else {
- sortObj[task.task_type_id] = {
- time: parseInt(task.duration, 10),
- labour_cost: parseFloat(task.wage_at_moment) * (task.duration / 60),
- task: t(`task:${task.taskType.task_translation_key}`),
- };
- }
- }
- }
-
- let keys = Object.keys(sortObj);
-
- for (let k of keys) {
- let obj = sortObj[k];
- data.push({
- task: obj.task,
- time: (obj.time / 60).toFixed(2).toString() + ' HR',
- labour_cost: currencySymbol + obj.labour_cost.toFixed(2),
- });
- }
-
- const columns = [
- {
- id: 'task',
- Header: t('SALE.LABOUR.TABLE.TASK'),
- accessor: (d) => d.task,
- minWidth: 80,
- },
- {
- id: 'time',
- Header: t('SALE.LABOUR.TABLE.TIME'),
- accessor: (d) => d.time,
- minWidth: 75,
- },
- {
- id: 'labour_cost',
- Header: t('SALE.LABOUR.TABLE.LABOUR_COST'),
- accessor: (d) => d.labour_cost,
- },
- ];
-
- return (
-
- );
-};
-
-export default Task;
diff --git a/packages/webapp/src/containers/Finances/Labour/Task/index.jsx b/packages/webapp/src/containers/Finances/Labour/Task/index.jsx
new file mode 100644
index 0000000000..e8905b2daa
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/Labour/Task/index.jsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import Table from '../../../../components/Table';
+import moment from 'moment';
+import { useTranslation } from 'react-i18next';
+import { roundToTwoDecimal } from '../../../../util';
+
+const Task = ({ currencySymbol, tasks, startDate, endDate }) => {
+ let data = [];
+ let sortObj = {};
+ const { t } = useTranslation(['translation', 'task']);
+ for (let task of tasks) {
+ const completedTime = moment(task.complete_date);
+ const abandonedTime = moment(task.abandon_date);
+ if (
+ (completedTime.isSameOrAfter(startDate, 'day') &&
+ completedTime.isSameOrBefore(endDate, 'day') &&
+ task.duration) ||
+ (abandonedTime.isSameOrAfter(startDate, 'day') &&
+ abandonedTime.isSameOrBefore(endDate, 'day') &&
+ task.duration)
+ ) {
+ const minutes = parseInt(task.duration, 10);
+ const hours = roundToTwoDecimal(minutes / 60);
+ const rate = roundToTwoDecimal(task.wage_at_moment);
+ const labour_cost = roundToTwoDecimal(rate * hours);
+
+ if (sortObj.hasOwnProperty(task.task_type_id)) {
+ sortObj[task.task_type_id].time = roundToTwoDecimal(sortObj[task.task_type_id].time) + minutes;
+ sortObj[task.task_type_id].labour_cost = roundToTwoDecimal(sortObj[task.task_type_id].labour_cost) + labour_cost;
+ } else {
+ sortObj[task.task_type_id] = {
+ time: minutes,
+ labour_cost,
+ task: t(`task:${task.taskType.task_translation_key}`),
+ };
+ }
+ }
+ }
+
+ let keys = Object.keys(sortObj);
+
+ for (let k of keys) {
+ let obj = sortObj[k];
+ data.push({
+ task: obj.task,
+ time: roundToTwoDecimal(obj.time / 60) + ' HR',
+ labour_cost: currencySymbol + roundToTwoDecimal(obj.labour_cost).toFixed(2),
+ });
+ }
+
+ const columns = [
+ {
+ id: 'task',
+ Header: t('SALE.LABOUR.TABLE.TASK'),
+ accessor: (d) => d.task,
+ minWidth: 80,
+ },
+ {
+ id: 'time',
+ Header: t('SALE.LABOUR.TABLE.TIME'),
+ accessor: (d) => d.time,
+ minWidth: 75,
+ },
+ {
+ id: 'labour_cost',
+ Header: t('SALE.LABOUR.TABLE.LABOUR_COST'),
+ accessor: (d) => d.labour_cost,
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export default Task;
diff --git a/packages/webapp/src/containers/Finances/Labour/index.js b/packages/webapp/src/containers/Finances/Labour/index.js
deleted file mode 100644
index a27026ec9c..0000000000
--- a/packages/webapp/src/containers/Finances/Labour/index.js
+++ /dev/null
@@ -1,139 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import PageTitle from '../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../styles.module.scss';
-import styles from './styles.module.scss';
-import Employee from './Employee';
-import Crop from './Crop';
-import Task from './Task';
-import { dateRangeSelector, shiftSelector } from '../selectors';
-import DateRangeSelector from '../../../components/Finances/DateRangeSelector';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
-import { Main } from '../../../components/Typography';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-import DropdownButton from '../../../components/Form/DropDownButton';
-import { tasksSelector } from '../../taskSlice';
-
-class Labour extends Component {
- constructor(props) {
- super(props);
-
- let startDate, endDate;
- const { dateRange } = this.props;
- if (dateRange && dateRange.startDate && dateRange.endDate) {
- startDate = moment(dateRange.startDate);
- endDate = moment(dateRange.endDate);
- } else {
- startDate = moment().startOf('year');
- endDate = moment().endOf('year');
- }
-
- this.state = {
- startDate,
- endDate,
- dropDownTitle: 'EMPLOYEES',
- dButtonStyle: {
- background: '#fff',
- color: '#333',
- borderColor: '#fff',
- boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
- width: '100%',
- },
- sortYear: moment().year(),
- };
-
- this.sortBy = this.sortBy.bind(this);
- this.changeDate = this.changeDate.bind(this);
- }
-
- changeDate(type, date) {
- if (type === 'start') {
- this.setState({ startDate: date });
- } else if (type === 'end') {
- this.setState({ endDate: date });
- } else {
- console.log('Error, type not specified');
- }
- }
- sortBy(type) {
- this.setState({
- dropDownTitle: type,
- });
- }
-
- render() {
- const i = 1;
- const { dropDownTitle, dButtonStyle } = this.state;
- const { farm } = this.props;
- const symbol = grabCurrencySymbol(farm);
- const options = [
- {
- text: this.props.t('SALE.LABOUR.EMPLOYEES'),
- onClick: () => this.sortBy('EMPLOYEES'),
- },
- // { text: this.props.t('SALE.LABOUR.CROPS'), onClick: () => this.sortBy('CROPS') },
- { text: this.props.t('SALE.LABOUR.TASKS'), onClick: () => this.sortBy('TASKS') },
- ];
-
- return (
-
-
-
-
-
{this.props.t('SALE.LABOUR.BY')}
-
-
- {this.props.t(`SALE.LABOUR.${dropDownTitle}`)}
-
-
-
- {dropDownTitle === 'EMPLOYEES' && (
-
- )}
- {/* {dropDownTitle === 'CROPS' && (
-
- )} */}
- {dropDownTitle === 'TASKS' && (
-
- )}
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- shifts: shiftSelector(state),
- tasks: tasksSelector(state),
- dateRange: dateRangeSelector(state),
- farm: userFarmSelector(state),
- managementPlans: currentAndPlannedManagementPlansSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Labour));
diff --git a/packages/webapp/src/containers/Finances/Labour/index.jsx b/packages/webapp/src/containers/Finances/Labour/index.jsx
new file mode 100644
index 0000000000..d671c2b917
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/Labour/index.jsx
@@ -0,0 +1,138 @@
+import React, { Component } from 'react';
+import moment from 'moment';
+import PageTitle from '../../../components/PageTitle';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../styles.module.scss';
+import styles from './styles.module.scss';
+import Employee from './Employee';
+import Task from './Task';
+import { dateRangeSelector, shiftSelector } from '../selectors';
+import DateRangeSelector from '../../../components/Finances/DateRangeSelector';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
+import { Main } from '../../../components/Typography';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+import DropdownButton from '../../../components/Form/DropDownButton';
+import { tasksSelector } from '../../taskSlice';
+
+class Labour extends Component {
+ constructor(props) {
+ super(props);
+
+ let startDate, endDate;
+ const { dateRange } = this.props;
+ if (dateRange && dateRange.startDate && dateRange.endDate) {
+ startDate = moment(dateRange.startDate);
+ endDate = moment(dateRange.endDate);
+ } else {
+ startDate = moment().startOf('year');
+ endDate = moment().endOf('year');
+ }
+
+ this.state = {
+ startDate,
+ endDate,
+ dropDownTitle: 'EMPLOYEES',
+ dButtonStyle: {
+ background: '#fff',
+ color: '#333',
+ borderColor: '#fff',
+ boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
+ width: '100%',
+ },
+ sortYear: moment().year(),
+ };
+
+ this.sortBy = this.sortBy.bind(this);
+ this.changeDate = this.changeDate.bind(this);
+ }
+
+ changeDate(type, date) {
+ if (type === 'start') {
+ this.setState({ startDate: date });
+ } else if (type === 'end') {
+ this.setState({ endDate: date });
+ } else {
+ console.log('Error, type not specified');
+ }
+ }
+ sortBy(type) {
+ this.setState({
+ dropDownTitle: type,
+ });
+ }
+
+ render() {
+ const i = 1;
+ const { dropDownTitle, dButtonStyle } = this.state;
+ const { farm } = this.props;
+ const symbol = grabCurrencySymbol();
+ const options = [
+ {
+ text: this.props.t('SALE.LABOUR.EMPLOYEES'),
+ onClick: () => this.sortBy('EMPLOYEES'),
+ },
+ // { text: this.props.t('SALE.LABOUR.CROPS'), onClick: () => this.sortBy('CROPS') },
+ { text: this.props.t('SALE.LABOUR.TASKS'), onClick: () => this.sortBy('TASKS') },
+ ];
+
+ return (
+
+
+
+
+
{this.props.t('SALE.LABOUR.BY')}
+
+
+ {this.props.t(`SALE.LABOUR.${dropDownTitle}`)}
+
+
+
+ {dropDownTitle === 'EMPLOYEES' && (
+
+ )}
+ {/* {dropDownTitle === 'CROPS' && (
+
+ )} */}
+ {dropDownTitle === 'TASKS' && (
+
+ )}
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ shifts: shiftSelector(state),
+ tasks: tasksSelector(state),
+ dateRange: dateRangeSelector(state),
+ farm: userFarmSelector(state),
+ managementPlans: currentAndPlannedManagementPlansSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Labour));
diff --git a/packages/webapp/src/containers/Finances/LegacyEstimatedRevenue/index.js b/packages/webapp/src/containers/Finances/LegacyEstimatedRevenue/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/LegacyEstimatedRevenue/index.js
rename to packages/webapp/src/containers/Finances/LegacyEstimatedRevenue/index.jsx
diff --git a/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.js b/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.js
deleted file mode 100644
index 013a40d6fa..0000000000
--- a/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.js
+++ /dev/null
@@ -1,246 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import PageTitle from '../../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../../styles.module.scss';
-import styles from './styles.module.scss';
-import {
- expenseDetailSelector,
- expenseTypeSelector,
- selectedExpenseSelector,
-} from '../../selectors';
-import history from '../../../../history';
-import DateContainer from '../../../../components/Inputs/DateContainer';
-import { actions, Control, Field, Form } from 'react-redux-form';
-import footerStyles from '../../../../components/LogFooter/styles.module.scss';
-import { addExpenses } from '../../actions';
-import { userFarmSelector } from '../../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { numberOnKeyDown } from '../../../../components/Form/Input';
-import grabCurrencySymbol from '../../../../util/grabCurrencySymbol';
-
-class AddExpense extends Component {
- constructor(props) {
- super(props);
- this.state = {
- date: moment(),
- expenseDetail: {},
- expenseNames: {},
- currencySymbol: grabCurrencySymbol(this.props.farm),
- };
- this.setDate = this.setDate.bind(this);
- this.getTypeName = this.getTypeName.bind(this);
- this.handleSubmit = this.handleSubmit.bind(this);
- this.removeField = this.removeField.bind(this);
- this.min = this.min.bind(this);
- this.required = this.required.bind(this);
- }
-
- componentDidMount() {
- const { selectedExpense } = this.props;
- let expenseDetail = {};
- let expenseNames = {};
- let formValue = {};
- for (let s of selectedExpense) {
- expenseDetail[s] = [
- {
- note: '',
- value: undefined,
- },
- ];
- expenseNames[s] = this.getTypeName(s);
- formValue[s] = [{ note: '', value: undefined }];
- }
- this.setState({ expenseNames, expenseDetail });
-
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', formValue));
- }
-
- getTypeName(id) {
- const { expenseTypes } = this.props;
-
- for (let e of expenseTypes) {
- if (e.expense_type_id === id) {
- return this.props.t(`expense:${e.expense_translation_key}`);
- }
- }
- return 'NAME NOT FOUND';
- }
-
- addSubExpense(key) {
- this.props.dispatch(
- actions.push(`financeReducer.forms.expenseDetail[${key}]`, {
- note: '',
- value: undefined,
- }),
- );
- }
-
- setDate(date) {
- this.setState({
- date: date,
- });
- }
-
- handleSubmit() {
- const { currentExpenseDetail } = this.props;
- let data = [];
- let keys = Object.keys(currentExpenseDetail);
- let farm_id = this.props.farm.farm_id;
- let date = this.state.date;
- for (let k of keys) {
- let values = currentExpenseDetail[k];
-
- for (let v of values) {
- if (v.note !== '' && !isNaN(v.value) && v.value >= 0) {
- let value = parseFloat(parseFloat(v.value).toFixed(2));
- let temp = {
- farm_id,
- note: v.note,
- value: value,
- expense_type_id: k,
- expense_date: date,
- };
- data.push(temp);
- }
- }
- }
-
- if (data.length < 1) {
- alert(this.props.t('EXPENSE.ADD_EXPENSE.REQUIRED_ERROR'));
- } else {
- this.props.dispatch(addExpenses(data));
- history.push('/finances');
- }
- }
-
- removeField(key, index) {
- if (index !== 0) {
- const { currentExpenseDetail } = this.props;
- let newArray = [];
- let values = currentExpenseDetail[key];
- // can't use splice cuz error: cannot delete property '0' of [object Array]
- for (let i = 0; i < values.length; i++) {
- if (i !== index) {
- newArray.push(values[i]);
- }
- }
- // Deep copy of the read only object
- let newObj = JSON.parse(JSON.stringify(currentExpenseDetail));
- newObj[key] = newArray;
- this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', newObj));
- }
- }
-
- required(value) {
- return value ? undefined : this.props.t('EXPENSE.ADD_EXPENSE.REQUIRED_ERROR');
- }
- min(value) {
- return value >= 0 ? undefined : this.props.t('EXPENSE.ADD_EXPENSE.MIN_ERROR') + '0';
- }
-
- render() {
- const { currentExpenseDetail } = this.props;
- const { expenseNames } = this.state;
- return (
-
-
-
-
- {Object.keys(expenseNames).map((k) => {
- return (
-
- );
- })}
-
-
-
history.push('/finances')}>
- {this.props.t('common:CANCEL')}
-
-
this.handleSubmit()}>
- {this.props.t('common:SAVE')}
-
-
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- expenseTypes: expenseTypeSelector(state),
- selectedExpense: selectedExpenseSelector(state),
- currentExpenseDetail: expenseDetailSelector(state),
- farm: userFarmSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(AddExpense));
diff --git a/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.jsx b/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.jsx
new file mode 100644
index 0000000000..2345e1ed13
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/NewExpense/AddExpense/index.jsx
@@ -0,0 +1,267 @@
+import React, { Component } from 'react';
+import moment from 'moment';
+import PageTitle from '../../../../components/PageTitle';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../../styles.module.scss';
+import { AddLink, Semibold } from '../../../../components/Typography';
+import styles from './styles.module.scss';
+import {
+ expenseDetailSelector,
+ expenseTypeSelector,
+ selectedExpenseSelector,
+} from '../../selectors';
+import history from '../../../../history';
+import DateContainer from '../../../../components/Inputs/DateContainer';
+import { actions, Control, Field, Form, Errors } from 'react-redux-form';
+import footerStyles from '../../../../components/LogFooter/styles.module.scss';
+import { addExpenses } from '../../actions';
+import { userFarmSelector } from '../../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { numberOnKeyDown } from '../../../../components/Form/Input';
+import grabCurrencySymbol from '../../../../util/grabCurrencySymbol';
+
+class AddExpense extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ date: moment(),
+ expenseDetail: {},
+ expenseNames: {},
+ currencySymbol: grabCurrencySymbol(),
+ };
+ this.setDate = this.setDate.bind(this);
+ this.getTypeName = this.getTypeName.bind(this);
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.removeField = this.removeField.bind(this);
+ this.min = this.min.bind(this);
+ this.required = this.required.bind(this);
+ }
+
+ componentDidMount() {
+ const { selectedExpense } = this.props;
+ let expenseDetail = {};
+ let expenseNames = {};
+ let formValue = {};
+ for (let s of selectedExpense) {
+ expenseDetail[s] = [
+ {
+ note: '',
+ value: undefined,
+ },
+ ];
+ expenseNames[s] = this.getTypeName(s);
+ formValue[s] = [{ note: '', value: undefined }];
+ }
+ this.setState({ expenseNames, expenseDetail });
+
+ this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', formValue));
+ }
+
+ getTypeName(id) {
+ const { expenseTypes } = this.props;
+
+ for (let e of expenseTypes) {
+ if (e.expense_type_id === id) {
+ return this.props.t(`expense:${e.expense_translation_key}`);
+ }
+ }
+ return 'NAME NOT FOUND';
+ }
+
+ addSubExpense(key) {
+ this.props.dispatch(
+ actions.push(`financeReducer.forms.expenseDetail[${key}]`, {
+ note: '',
+ value: undefined,
+ }),
+ );
+ }
+
+ setDate(date) {
+ this.setState({
+ date: date,
+ });
+ }
+
+ handleSubmit() {
+ const { currentExpenseDetail } = this.props;
+ let data = [];
+ let keys = Object.keys(currentExpenseDetail);
+ let farm_id = this.props.farm.farm_id;
+ let date = this.state.date;
+ let missingText = false;
+ for (let k of keys) {
+ let values = currentExpenseDetail[k];
+
+ for (let v of values) {
+ if (v.note === '') {
+ missingText = true;
+ } else {
+ let value = parseFloat(parseFloat(v.value).toFixed(2));
+ let temp = {
+ farm_id,
+ note: v.note,
+ value: value,
+ expense_type_id: k,
+ expense_date: date,
+ };
+ data.push(temp);
+ }
+ }
+ }
+
+ // if (data.length < 1) {
+ // alert(this.props.t('EXPENSE.ADD_EXPENSE.REQUIRED_ERROR'));
+ if (
+ !missingText &&
+ data.length &&
+ data.filter((d) => d.value <= 0 || isNaN(d.value)).length === 0
+ ) {
+ this.props.dispatch(addExpenses(data));
+ history.push('/finances');
+ }
+ }
+
+ removeField(key, index) {
+ if (index !== 0) {
+ const { currentExpenseDetail } = this.props;
+ let newArray = [];
+ let values = currentExpenseDetail[key];
+ // can't use splice cuz error: cannot delete property '0' of [object Array]
+ for (let i = 0; i < values.length; i++) {
+ if (i !== index) {
+ newArray.push(values[i]);
+ }
+ }
+ // Deep copy of the read only object
+ let newObj = JSON.parse(JSON.stringify(currentExpenseDetail));
+ newObj[key] = newArray;
+ this.props.dispatch(actions.change('financeReducer.forms.expenseDetail', newObj));
+ }
+ }
+
+ required(value) {
+ return value ? undefined : this.props.t('EXPENSE.ADD_EXPENSE.REQUIRED_ERROR');
+ }
+ min(value) {
+ return !isNaN(value) && value >= 0
+ ? undefined
+ : this.props.t('EXPENSE.ADD_EXPENSE.MIN_ERROR') + '0';
+ }
+
+ render() {
+ const { currentExpenseDetail } = this.props;
+ const { expenseNames } = this.state;
+ return (
+
+
+
+
+ {Object.keys(expenseNames).map((k) => {
+ return (
+
+ );
+ })}
+
+
+
history.push('/finances')}>
+ {this.props.t('common:CANCEL')}
+
+
this.handleSubmit()}>
+ {this.props.t('common:SAVE')}
+
+
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ expenseTypes: expenseTypeSelector(state),
+ selectedExpense: selectedExpenseSelector(state),
+ currentExpenseDetail: expenseDetailSelector(state),
+ farm: userFarmSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(AddExpense));
diff --git a/packages/webapp/src/containers/Finances/NewExpense/AddExpense/styles.module.scss b/packages/webapp/src/containers/Finances/NewExpense/AddExpense/styles.module.scss
index 31a96f9e36..67e39d6aef 100644
--- a/packages/webapp/src/containers/Finances/NewExpense/AddExpense/styles.module.scss
+++ b/packages/webapp/src/containers/Finances/NewExpense/AddExpense/styles.module.scss
@@ -8,6 +8,12 @@
justify-content: center;
color: white;
border-radius: 2em;
+ cursor: pointer;
+}
+
+.greenPlus:hover {
+
+ background: #286090;
}
.expenseTitle {
@@ -21,11 +27,11 @@
.addContainer {
width: 70%;
- margin: 18px auto 25px auto;
+ margin: 18px 0px 25px 0px;
display: flex;
flex-direction: row;
- justify-content: center;
- align-items: center;
+ justify-content: left;
+ align-items: left;
color: #00756a;
font-style: normal;
font-weight: normal;
diff --git a/packages/webapp/src/containers/Finances/NewExpense/ExpenseCategories/index.js b/packages/webapp/src/containers/Finances/NewExpense/ExpenseCategories/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/NewExpense/ExpenseCategories/index.js
rename to packages/webapp/src/containers/Finances/NewExpense/ExpenseCategories/index.jsx
diff --git a/packages/webapp/src/containers/Finances/OtherExpense/index.js b/packages/webapp/src/containers/Finances/OtherExpense/index.js
deleted file mode 100644
index 566706232c..0000000000
--- a/packages/webapp/src/containers/Finances/OtherExpense/index.js
+++ /dev/null
@@ -1,289 +0,0 @@
-import React, { Component } from 'react';
-import moment from 'moment';
-import PageTitle from '../../../components/PageTitle';
-import connect from 'react-redux/es/connect/connect';
-import defaultStyles from '../styles.module.scss';
-import styles from './styles.module.scss';
-import { dateRangeSelector, expenseSelector, expenseTypeSelector } from '../selectors';
-import Table from '../../../components/Table';
-import { getExpense, setExpenseDetailItem } from '../actions';
-import history from '../../../history';
-import DateRangeSelector from '../../../components/Finances/DateRangeSelector';
-import { BsCaretRight } from 'react-icons/bs';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { Semibold } from '../../../components/Typography';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-
-class OtherExpense extends Component {
- constructor(props) {
- super(props);
- let startDate, endDate;
- const { dateRange } = this.props;
- if (dateRange && dateRange.startDate && dateRange.endDate) {
- startDate = moment(dateRange.startDate);
- endDate = moment(dateRange.endDate);
- } else {
- startDate = moment().startOf('year');
- endDate = moment().endOf('year');
- }
-
- this.state = {
- startDate,
- endDate,
- totalExpense: 0,
- subTotal: 0,
- sortMonth: 0,
- dropDownTitle: 'All Months',
- dButtonStyle: {
- background: '#fff',
- color: '#333',
- borderColor: '#fff',
- boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
- width: '100%',
- marginBottom: '10px',
- },
- currencySymbol: grabCurrencySymbol(this.props.farm),
- };
- this.computeTable = this.computeTable.bind(this);
- this.getExpenseType = this.getExpenseType.bind(this);
- this.computeDetailedTable = this.computeDetailedTable.bind(this);
- this.changeDate = this.changeDate.bind(this);
- }
-
- componentDidMount() {
- this.props.dispatch(getExpense());
- }
-
- componentDidUpdate(prevProps) {
- // Typical usage (don't forget to compare props):
- if (this.props.expenses !== prevProps.expenses) {
- this.computeTable();
- this.computeDetailedTable();
- }
- }
-
- changeDate(type, date) {
- if (type === 'start') {
- this.setState({ startDate: date });
- } else if (type === 'end') {
- this.setState({ endDate: date });
- } else {
- console.log('Error, type not specified');
- }
- }
-
- computeTable() {
- const { expenses } = this.props;
- const { startDate, endDate } = this.state;
- let dict = {};
-
- for (let e of expenses) {
- const expenseDate = moment(e.expense_date);
-
- if (
- expenseDate.isSameOrAfter(startDate, 'day') &&
- expenseDate.isSameOrBefore(endDate, 'day')
- ) {
- let id = e.expense_type_id;
- if (!dict.hasOwnProperty(id)) {
- let typeName = this.getExpenseType(id);
- dict[id] = {
- type: typeName,
- amount: e.value,
- };
- } else {
- dict[id].amount = dict[id].amount + e.value;
- }
- }
- }
-
- let data = [];
- let keys = Object.keys(dict);
- let total = 0;
-
- for (let k of keys) {
- data.push({
- type: dict[k].type,
- amount: dict[k].amount,
- });
- total += dict[k].amount;
- }
- return [data, total.toFixed(2)];
- }
-
- computeDetailedTable() {
- const { expenses } = this.props;
- const { startDate, endDate } = this.state;
- let detailedHistory = [];
-
- let subTotal = 0;
-
- for (let e of expenses) {
- const expenseDate = moment(e.expense_date);
-
- if (
- expenseDate.isSameOrAfter(startDate, 'day') &&
- expenseDate.isSameOrBefore(endDate, 'day')
- ) {
- let amount = parseFloat(e.value);
- subTotal += amount;
- detailedHistory.push({
- date: moment(e.expense_date),
- type: this.getExpenseType(e.expense_type_id),
- amount: this.state.currencySymbol + amount.toFixed(2).toString(),
- expense_date: e.expense_date,
- note: e.note,
- expense_item_id: e.farm_expense_id,
- value: amount,
- });
- }
- }
- return [detailedHistory, subTotal.toFixed(2)];
- }
-
- getExpenseType(id) {
- const { expenseTypes } = this.props;
- for (let type of expenseTypes) {
- if (type.expense_type_id === id) {
- return this.props.t(`expense:${type.expense_translation_key}`);
- }
- }
- return 'TYPE_NOT_FOUND';
- }
-
- render() {
- const [data, totalData] = this.computeTable();
- const [detailedHistory, totalDetailed] = this.computeDetailedTable();
-
- const columns = [
- {
- id: 'type',
- Header: this.props.t('SALE.SUMMARY.TYPE'),
- accessor: (d) => d.type,
- minWidth: 80,
- Footer: {this.props.t('SALE.SUMMARY.TOTAL')}
,
- },
- {
- id: 'amount',
- Header: this.props.t('SALE.SUMMARY.AMOUNT'),
- accessor: 'amount',
- minWidth: 75,
- Cell: (d) => {`${this.state.currencySymbol}${d.value.toFixed(2).toString()}`} ,
- Footer: {this.state.currencySymbol + totalData}
,
- },
- ];
-
- const detailedColumns = [
- {
- id: 'date',
- Header: this.props.t('SALE.LABOUR.TABLE.DATE'),
- Cell: (d) => {moment(d.value).format('YYYY-MM-DD')} ,
- accessor: (d) => moment(d.date),
- minWidth: 70,
- Footer: {this.props.t('SALE.SUMMARY.SUBTOTAL')}
,
- },
- {
- id: 'type',
- Header: this.props.t('SALE.LABOUR.TABLE.TYPE'),
- accessor: (d) => d.type,
- minWidth: 55,
- },
- {
- id: 'name',
- Header: this.props.t('common:NAME'),
- accessor: (d) => d.note,
- minWidth: 55,
- },
- {
- id: 'amount',
- Header: this.props.t('SALE.LABOUR.TABLE.AMOUNT'),
- accessor: 'value',
- Cell: (d) => {`${this.state.currencySymbol}${d.value.toFixed(2).toString()}`} ,
- minWidth: 55,
- Footer: {this.state.currencySymbol + totalDetailed}
,
- },
- {
- id: 'chevron',
- maxWidth: 25,
- accessor: () => ,
- },
- ];
-
- return (
-
-
-
-
-
{this.props.t('EXPENSE.SUMMARY')}
-
- {data.length > 0 && (
-
- )}
- {data.length === 0 &&
{this.props.t('EXPENSE.NO_EXPENSE_YEAR')} }
-
-
- {this.props.t('EXPENSE.DETAILED_HISTORY')}
-
-
- {detailedHistory.length > 0 && (
-
-
{
- return {
- onClick: (e, handleOriginal) => {
- if (rowInfo && rowInfo.original) {
- this.props.dispatch(setExpenseDetailItem(rowInfo.original));
- history.push('/expense_detail');
- }
- if (handleOriginal) {
- handleOriginal();
- }
- },
- };
- }}
- />
-
- )}
- {detailedHistory.length === 0 && (
-
-
{this.props.t('EXPENSE.NO_EXPENSE')}
-
- )}
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- expenses: expenseSelector(state),
- expenseTypes: expenseTypeSelector(state),
- dateRange: dateRangeSelector(state),
- farm: userFarmSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(OtherExpense));
diff --git a/packages/webapp/src/containers/Finances/OtherExpense/index.jsx b/packages/webapp/src/containers/Finances/OtherExpense/index.jsx
new file mode 100644
index 0000000000..0ad1ae52ab
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/OtherExpense/index.jsx
@@ -0,0 +1,289 @@
+import React, { Component } from 'react';
+import moment from 'moment';
+import PageTitle from '../../../components/PageTitle';
+import connect from 'react-redux/es/connect/connect';
+import defaultStyles from '../styles.module.scss';
+import styles from './styles.module.scss';
+import { dateRangeSelector, expenseSelector, expenseTypeSelector } from '../selectors';
+import Table from '../../../components/Table';
+import { getExpense, setExpenseDetailItem } from '../actions';
+import history from '../../../history';
+import DateRangeSelector from '../../../components/Finances/DateRangeSelector';
+import { BsCaretRight } from 'react-icons/bs';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { Semibold } from '../../../components/Typography';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+
+class OtherExpense extends Component {
+ constructor(props) {
+ super(props);
+ let startDate, endDate;
+ const { dateRange } = this.props;
+ if (dateRange && dateRange.startDate && dateRange.endDate) {
+ startDate = moment(dateRange.startDate);
+ endDate = moment(dateRange.endDate);
+ } else {
+ startDate = moment().startOf('year');
+ endDate = moment().endOf('year');
+ }
+
+ this.state = {
+ startDate,
+ endDate,
+ totalExpense: 0,
+ subTotal: 0,
+ sortMonth: 0,
+ dropDownTitle: 'All Months',
+ dButtonStyle: {
+ background: '#fff',
+ color: '#333',
+ borderColor: '#fff',
+ boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
+ width: '100%',
+ marginBottom: '10px',
+ },
+ currencySymbol: grabCurrencySymbol(),
+ };
+ this.computeTable = this.computeTable.bind(this);
+ this.getExpenseType = this.getExpenseType.bind(this);
+ this.computeDetailedTable = this.computeDetailedTable.bind(this);
+ this.changeDate = this.changeDate.bind(this);
+ }
+
+ componentDidMount() {
+ this.props.dispatch(getExpense());
+ }
+
+ componentDidUpdate(prevProps) {
+ // Typical usage (don't forget to compare props):
+ if (this.props.expenses !== prevProps.expenses) {
+ this.computeTable();
+ this.computeDetailedTable();
+ }
+ }
+
+ changeDate(type, date) {
+ if (type === 'start') {
+ this.setState({ startDate: date });
+ } else if (type === 'end') {
+ this.setState({ endDate: date });
+ } else {
+ console.log('Error, type not specified');
+ }
+ }
+
+ computeTable() {
+ const { expenses } = this.props;
+ const { startDate, endDate } = this.state;
+ let dict = {};
+
+ for (let e of expenses) {
+ const expenseDate = moment(e.expense_date);
+
+ if (
+ expenseDate.isSameOrAfter(startDate, 'day') &&
+ expenseDate.isSameOrBefore(endDate, 'day')
+ ) {
+ let id = e.expense_type_id;
+ if (!dict.hasOwnProperty(id)) {
+ let typeName = this.getExpenseType(id);
+ dict[id] = {
+ type: typeName,
+ amount: e.value,
+ };
+ } else {
+ dict[id].amount = dict[id].amount + e.value;
+ }
+ }
+ }
+
+ let data = [];
+ let keys = Object.keys(dict);
+ let total = 0;
+
+ for (let k of keys) {
+ data.push({
+ type: dict[k].type,
+ amount: dict[k].amount,
+ });
+ total += dict[k].amount;
+ }
+ return [data, total.toFixed(2)];
+ }
+
+ computeDetailedTable() {
+ const { expenses } = this.props;
+ const { startDate, endDate } = this.state;
+ let detailedHistory = [];
+
+ let subTotal = 0;
+
+ for (let e of expenses) {
+ const expenseDate = moment(e.expense_date);
+
+ if (
+ expenseDate.isSameOrAfter(startDate, 'day') &&
+ expenseDate.isSameOrBefore(endDate, 'day')
+ ) {
+ let amount = parseFloat(e.value);
+ subTotal += amount;
+ detailedHistory.push({
+ date: moment(e.expense_date),
+ type: this.getExpenseType(e.expense_type_id),
+ amount: this.state.currencySymbol + amount.toFixed(2).toString(),
+ expense_date: e.expense_date,
+ note: e.note,
+ expense_item_id: e.farm_expense_id,
+ value: amount,
+ });
+ }
+ }
+ return [detailedHistory, subTotal.toFixed(2)];
+ }
+
+ getExpenseType(id) {
+ const { expenseTypes } = this.props;
+ for (let type of expenseTypes) {
+ if (type.expense_type_id === id) {
+ return this.props.t(`expense:${type.expense_translation_key}`);
+ }
+ }
+ return 'TYPE_NOT_FOUND';
+ }
+
+ render() {
+ const [data, totalData] = this.computeTable();
+ const [detailedHistory, totalDetailed] = this.computeDetailedTable();
+
+ const columns = [
+ {
+ id: 'type',
+ Header: this.props.t('SALE.SUMMARY.TYPE'),
+ accessor: (d) => d.type,
+ minWidth: 80,
+ Footer: {this.props.t('SALE.SUMMARY.TOTAL')}
,
+ },
+ {
+ id: 'amount',
+ Header: this.props.t('SALE.SUMMARY.AMOUNT'),
+ accessor: 'amount',
+ minWidth: 75,
+ Cell: (d) => {`${this.state.currencySymbol}${d.value.toFixed(2).toString()}`} ,
+ Footer: {this.state.currencySymbol + totalData}
,
+ },
+ ];
+
+ const detailedColumns = [
+ {
+ id: 'date',
+ Header: this.props.t('SALE.LABOUR.TABLE.DATE'),
+ Cell: (d) => {moment(d.value).format('YYYY-MM-DD')} ,
+ accessor: (d) => moment(d.date),
+ minWidth: 70,
+ Footer: {this.props.t('SALE.SUMMARY.SUBTOTAL')}
,
+ },
+ {
+ id: 'type',
+ Header: this.props.t('SALE.LABOUR.TABLE.TYPE'),
+ accessor: (d) => d.type,
+ minWidth: 55,
+ },
+ {
+ id: 'name',
+ Header: this.props.t('common:NAME'),
+ accessor: (d) => d.note,
+ minWidth: 55,
+ },
+ {
+ id: 'amount',
+ Header: this.props.t('SALE.LABOUR.TABLE.AMOUNT'),
+ accessor: 'value',
+ Cell: (d) => {`${this.state.currencySymbol}${d.value.toFixed(2).toString()}`} ,
+ minWidth: 55,
+ Footer: {this.state.currencySymbol + totalDetailed}
,
+ },
+ {
+ id: 'chevron',
+ maxWidth: 25,
+ accessor: () => ,
+ },
+ ];
+
+ return (
+
+
+
+
+
{this.props.t('EXPENSE.SUMMARY')}
+
+ {data.length > 0 && (
+
+ )}
+ {data.length === 0 &&
{this.props.t('EXPENSE.NO_EXPENSE_YEAR')} }
+
+
+ {this.props.t('EXPENSE.DETAILED_HISTORY')}
+
+
+ {detailedHistory.length > 0 && (
+
+
{
+ return {
+ onClick: (e, handleOriginal) => {
+ if (rowInfo && rowInfo.original) {
+ this.props.dispatch(setExpenseDetailItem(rowInfo.original));
+ history.push('/expense_detail');
+ }
+ if (handleOriginal) {
+ handleOriginal();
+ }
+ },
+ };
+ }}
+ />
+
+ )}
+ {detailedHistory.length === 0 && (
+
+
{this.props.t('EXPENSE.NO_EXPENSE')}
+
+ )}
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ expenses: expenseSelector(state),
+ expenseTypes: expenseTypeSelector(state),
+ dateRange: dateRangeSelector(state),
+ farm: userFarmSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(OtherExpense));
diff --git a/packages/webapp/src/containers/Finances/SaleDetail/index.js b/packages/webapp/src/containers/Finances/SaleDetail/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/SaleDetail/index.js
rename to packages/webapp/src/containers/Finances/SaleDetail/index.jsx
diff --git a/packages/webapp/src/containers/Finances/SalesSummary/index.js b/packages/webapp/src/containers/Finances/SalesSummary/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Finances/SalesSummary/index.js
rename to packages/webapp/src/containers/Finances/SalesSummary/index.jsx
diff --git a/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.js b/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.js
deleted file mode 100644
index 44c1c1f8a4..0000000000
--- a/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React, { useEffect } from 'react';
-import { useTranslation } from 'react-i18next';
-import { useSelector, useDispatch } from 'react-redux';
-import produce from 'immer';
-import PureUpdateEstimatedCropRevenue from '../../../components/Finances/UpdateEstimatedCropRevenue';
-import { managementPlanSelector } from '../../managementPlanSlice';
-import { measurementSelector } from '../../userFarmSlice';
-import { getProcessedFormData } from '../../hooks/useHookFormPersist/utils';
-import { patchEstimatedCropRevenue } from '../saga';
-
-function UpdateEstimatedCropRevenue({ history, match }) {
- const { management_plan_id } = match.params;
- const { t } = useTranslation();
-
- const dispatch = useDispatch();
- const managementPlan = useSelector(managementPlanSelector(management_plan_id));
- const system = useSelector(measurementSelector);
-
- const { crop_variety_id } = managementPlan;
-
- const onSubmit = (data) => {
- const managementPlan = produce(data, (data) => {
- data.management_plan_id = management_plan_id;
- data.crop_management_plan &&
- (data.crop_management_plan.management_plan_id = management_plan_id);
- data.crop_variety_id = crop_variety_id;
- });
- dispatch(patchEstimatedCropRevenue(getProcessedFormData(managementPlan)));
- };
-
- return (
- history.goBack()}
- onSubmit={onSubmit}
- />
- );
-}
-
-export default UpdateEstimatedCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.jsx b/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.jsx
new file mode 100644
index 0000000000..ce38f734ce
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/UpdateEstimatedCropRevenue/index.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import { useDispatch, useSelector } from 'react-redux';
+import produce from 'immer';
+import PureUpdateEstimatedCropRevenue from '../../../components/Finances/UpdateEstimatedCropRevenue';
+import { managementPlanSelector } from '../../managementPlanSlice';
+import { measurementSelector } from '../../userFarmSlice';
+import { getProcessedFormData } from '../../hooks/useHookFormPersist/utils';
+import { patchEstimatedCropRevenue } from '../saga';
+
+function UpdateEstimatedCropRevenue({ history, match }) {
+ const { management_plan_id } = match.params;
+ const { t } = useTranslation();
+
+ const dispatch = useDispatch();
+ const managementPlan = useSelector(managementPlanSelector(management_plan_id));
+ const system = useSelector(measurementSelector);
+
+ const { crop_variety_id } = managementPlan;
+
+ const onSubmit = (data) => {
+ const managementPlan = produce(data, (data) => {
+ data.management_plan_id = management_plan_id;
+ data.crop_management_plan &&
+ (data.crop_management_plan.management_plan_id = management_plan_id);
+ data.crop_variety_id = crop_variety_id;
+ });
+ dispatch(patchEstimatedCropRevenue(getProcessedFormData(managementPlan)));
+ };
+
+ return (
+ history.back()}
+ onSubmit={onSubmit}
+ />
+ );
+}
+
+export default UpdateEstimatedCropRevenue;
diff --git a/packages/webapp/src/containers/Finances/index.js b/packages/webapp/src/containers/Finances/index.js
deleted file mode 100644
index 47ea5be6cc..0000000000
--- a/packages/webapp/src/containers/Finances/index.js
+++ /dev/null
@@ -1,572 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import styles from './styles.module.scss';
-import DescriptiveButton from '../../components/Inputs/DescriptiveButton';
-import history from '../../history';
-import { dateRangeSelector, expenseSelector, salesSelector, shiftSelector } from './selectors';
-import { getDefaultExpenseType, getExpense, getSales, setDateRange } from './actions';
-import { calcOtherExpense, calcTotalLabour, filterSalesByCurrentYear } from './util';
-import Moment from 'moment';
-import { roundToTwoDecimal } from '../../util';
-import DateRangeSelector from '../../components/Finances/DateRangeSelector';
-import InfoBoxComponent from '../../components/InfoBoxComponent';
-import { extendMoment } from 'moment-range';
-import { userFarmSelector } from '../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { managementPlansSelector } from '../managementPlanSlice';
-import { getManagementPlansAndTasks } from '../saga';
-import Button from '../../components/Form/Button';
-import { Semibold, Title } from '../../components/Typography';
-import grabCurrencySymbol from '../../util/grabCurrencySymbol';
-import { taskEntitiesByManagementPlanIdSelector, tasksSelector } from '../taskSlice';
-import { isTaskType } from '../Task/useIsTaskType';
-
-const moment = extendMoment(Moment);
-
-class Finances extends Component {
- constructor(props) {
- super(props);
- this.state = {
- balanceByCrop: [],
- startDate: moment().startOf('year'),
- endDate: moment().endOf('year'),
- dButtonStyle: {
- background: '#fff',
- color: '#333',
- borderColor: '#fff',
- boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
- width: '100%',
- },
- dropDownTitle: this.props.t('SALE.FINANCES.ACTUAL'),
- focusedInput: null,
- hasUnAllocated: false,
- showUnTip: 'none',
- unTipButton: this.props.t('SALE.FINANCES.UNALLOCATED_TIP'),
- currencySymbol: grabCurrencySymbol(this.props.farm),
- };
- this.getRevenue = this.getRevenue.bind(this);
- this.getEstimatedRevenue = this.getEstimatedRevenue.bind(this);
- // this.calcBalanceByCrop = this.calcBalanceByCrop.bind(this);
- this.getShiftCropOnField = this.getShiftCropOnField.bind(this);
- this.toggleTip = this.toggleTip.bind(this);
- this.changeDate = this.changeDate.bind(this);
- }
-
- //TODO: filter revenue of cropSales for the current year?
- getRevenue() {
- let cropVarietySale = [];
- if (this.props.sales && Array.isArray(this.props.sales)) {
- filterSalesByCurrentYear(this.props.sales).map((s) => {
- return s.crop_variety_sale.map((cvs) => {
- return cropVarietySale.push(cvs);
- });
- });
- }
- let totalRevenue = 0;
- cropVarietySale.map((cvs) => {
- return (totalRevenue += cvs.sale_value || 0);
- });
- return totalRevenue.toFixed(2);
- }
-
- componentDidMount() {
- const { dateRange } = this.props;
- this.props.dispatch(getSales());
- this.props.dispatch(getExpense());
- this.props.dispatch(getDefaultExpenseType());
- this.props.dispatch(getManagementPlansAndTasks());
- //TODO fetch userFarm
- if (dateRange && dateRange.startDate && dateRange.endDate) {
- this.setState({
- startDate: dateRange.startDate,
- endDate: dateRange.endDate,
- });
- } else {
- this.props.dispatch(
- setDateRange({
- startDate: this.state.startDate,
- endDate: this.state.endDate,
- }),
- );
- }
- // this.calcBalanceByCrop();
- }
-
- componentDidUpdate(prevProps) {
- // Typical usage (don't forget to compare props):
- if (
- this.props.shifts !== prevProps.shifts ||
- this.props.sales !== prevProps.sales ||
- this.props.expenses !== prevProps.expenses ||
- this.props.dateRange !== prevProps.dateRange
- ) {
- // this.calcBalanceByCrop();
- }
- }
-
- changeDate(type, date) {
- if (type === 'start') {
- this.setState({ startDate: date });
- } else if (type === 'end') {
- this.setState({ endDate: date });
- } else {
- console.log('Error, type not specified');
- }
- }
-
- getEstimatedRevenue(managementPlans) {
- let totalRevenue = 0;
- if (managementPlans) {
- managementPlans
- .filter(({ abandon_date }) => !abandon_date)
- .forEach((plan) => {
- // check if this plan has a harvest task projected within the time frame
- const harvestTasks =
- this.props.tasksByManagementPlanId[plan.management_plan_id]?.filter((task) =>
- isTaskType(task.taskType, 'HARVEST_TASK'),
- ) || [];
- const harvestDates = harvestTasks?.map((task) =>
- moment(task.due_date).utc().format('YYYY-MM-DD'),
- );
-
- if (
- harvestDates.some(
- (harvestDate) =>
- moment(this.state.startDate)
- .startOf('day')
- .utc()
- .isSameOrBefore(harvestDate, 'day') &&
- moment(this.state.endDate).utc().isSameOrAfter(harvestDate, 'day'),
- )
- ) {
- totalRevenue += plan.estimated_revenue;
- }
- });
- }
- return parseFloat(totalRevenue).toFixed(2);
- }
-
- getTotalExpense = () => {
- const { expenses } = this.props;
- const { startDate, endDate } = this.state;
-
- let total = 0;
- if (expenses && expenses.length) {
- for (let e of expenses) {
- if (
- moment(e.expense_date).isSameOrAfter(startDate, 'day') &&
- moment(e.expense_date).isSameOrBefore(endDate, 'day')
- ) {
- total += Number(e.value);
- }
- }
- }
-
- return total;
- };
-
- // TODO: currently commented out all usages of this function, until ful refactor to crop variety
- calcBalanceByCrop() {
- const { shifts, sales, expenses } = this.props;
- const { startDate, endDate } = this.state;
-
- if (!(shifts || sales || expenses)) return;
-
- let final = Object.assign({}, {}); // crop: crop name, profit: number
-
- let unAllocated = 0;
- let unAllocatedShifts = {};
-
- let totalExpense = this.getTotalExpense();
-
- if (shifts && shifts.length) {
- for (let s of shifts) {
- let management_plan_id = s.management_plan_id;
- const shiftDate = moment(s.shift_date);
- if (shiftDate.isSameOrAfter(startDate, 'day') && shiftDate.isSameOrBefore(endDate, 'day')) {
- if (management_plan_id !== null) {
- if (final.hasOwnProperty(management_plan_id)) {
- final[management_plan_id].profit =
- final[management_plan_id].profit +
- Number(s.wage_at_moment) * (Number(s.duration) / 60) * -1;
- } else {
- final[management_plan_id] = {
- profit: Number(s.wage_at_moment) * (Number(s.duration) / 60) * -1,
- crop_translation_key: s.crop_translation_key,
- location_id: s.location_id,
- crop_id: s.crop_id,
- management_plan_id: s.management_plan_id,
- };
- }
- }
- // else it's unallocated
- else {
- if (unAllocatedShifts.hasOwnProperty(s.location_id)) {
- unAllocatedShifts[s.location_id].value =
- unAllocatedShifts[s.location_id].value +
- Number(s.wage_at_moment) * (Number(s.duration) / 60);
- } else {
- unAllocatedShifts = Object.assign(unAllocatedShifts, {
- [s.location_id]: {
- value: Number(s.wage_at_moment) * (Number(s.duration) / 60),
- hasAllocated: false,
- },
- });
- }
- }
- }
- }
- }
-
- // balance by crop used to be sorted by field crop,
- // i'm keeping the original code, and will modify the object to make it sorted by crop
- final = this.convertToCropID(final);
-
- // allocate unallocated to used-to-be fields
- let ukeys = Object.keys(unAllocatedShifts);
- for (let uk of ukeys) {
- // uk = location_id
- let uShift = unAllocatedShifts[uk];
-
- // a list of crop ids
- let waitForAllocate = this.getCropsByFieldID(uk);
-
- let avg = Number(parseFloat(uShift.value / waitForAllocate.length).toFixed(2));
-
- let fkeys = Object.keys(final);
-
- for (let wa of waitForAllocate) {
- for (let fk of fkeys) {
- if (Number(fk) === Number(wa)) {
- final[fk].profit -= avg;
- }
- }
- }
-
- if (waitForAllocate.length > 0) {
- unAllocatedShifts[uk].hasAllocated = true;
- }
- }
-
- let cropKeys = Object.keys(final);
- let averageExpense = Number(parseFloat(totalExpense / cropKeys.length).toFixed(2));
- // apply expense evenly to each crop
- for (let ck of cropKeys) {
- final[ck].profit -= averageExpense;
- }
-
- for (let uk of ukeys) {
- let uShift = unAllocatedShifts[uk];
- if (!uShift.hasAllocated) {
- unAllocated += uShift.value;
- }
- }
-
- if (unAllocated !== 0) {
- final = Object.assign(final, {
- unallocated: {
- crop: this.props.t('SALE.FINANCES.UNALLOCATED_CROP'),
- profit: unAllocated * -1,
- },
- });
- }
-
- this.setState({
- balanceByCrop: Object.values(final),
- });
- }
-
- getCropsByFieldID = (location_id) => {
- const { managementPlans } = this.props;
-
- let result = new Set();
-
- for (let fc of managementPlans) {
- if (fc.location_id === location_id) {
- result.add(fc.crop_id);
- }
- }
-
- return Array.from(result);
- };
-
- convertToCropID = (final) => {
- let fcIDs = Object.keys(final);
- let result = {};
-
- const { startDate, endDate } = this.state;
- const { sales } = this.props;
-
- for (let fkey of fcIDs) {
- let value = final[fkey];
- if (result.hasOwnProperty(value.crop_id)) {
- result[value.crop_id].profit += value.profit;
- } else {
- result[value.crop_id] = {
- crop: this.props.t(`crop:${value.crop_translation_key}`),
- location_id: value.location_id,
- crop_id: value.crop_id,
- profit: value.profit,
- };
- }
- }
-
- //apply sales
- for (let sale of sales || []) {
- const saleDate = moment(sale.sale_date);
-
- if (saleDate.isSameOrAfter(startDate, 'day') && saleDate.isSameOrBefore(endDate, 'day')) {
- for (let cp of sale.cropSale) {
- if (cp.crop && result.hasOwnProperty(cp.crop.crop_id)) {
- result[cp.crop.crop_id].profit += Number(cp.sale_value);
- } else {
- result[cp.crop.crop_id] = {
- crop: this.props.t(`crop:${cp.crop.crop_translation_key}`),
- location_id: 'not available',
- crop_id: cp.crop.crop_id,
- profit: Number(cp.sale_value),
- };
- }
- }
- }
- }
-
- return result;
- };
-
- getShiftCropOnField(location_id) {
- const { shifts } = this.props;
-
- let crops = [];
-
- for (let s of shifts) {
- if (s.location_id === location_id && s.crop_id) {
- crops.push(s.crop_id);
- }
- }
-
- return crops;
- }
-
- toggleTip() {
- let { showUnTip } = this.state;
- let unTipButton;
- if (showUnTip === 'block') {
- showUnTip = 'none';
- unTipButton = this.props.t('SALE.FINANCES.UNALLOCATED_TIP');
- } else {
- showUnTip = 'block';
- unTipButton = this.props.t('common:HIDE');
- }
- this.setState({ showUnTip, unTipButton });
- }
-
- render() {
- const totalRevenue = this.getRevenue();
- const estimatedRevenue = this.getEstimatedRevenue(this.props.managementPlans);
- const { tasks, expenses } = this.props;
- const { balanceByCrop, startDate, endDate, hasUnAllocated, showUnTip, unTipButton } =
- this.state;
- const labourExpense = roundToTwoDecimal(calcTotalLabour(tasks, startDate, endDate));
- const otherExpense = calcOtherExpense(expenses, startDate, endDate);
- const totalExpense = (parseFloat(otherExpense) + parseFloat(labourExpense)).toFixed(2);
- return (
-
-
{this.props.t('SALE.FINANCES.TITLE')}
-
-
{this.props.t('SALE.FINANCES.ACTION')}
-
- {
- history.push('/expense_categories');
- }}
- >
- {this.props.t('SALE.FINANCES.ADD_NEW_EXPENSE')}
-
- {
- history.push('add_sale');
- }}
- >
- {this.props.t('SALE.FINANCES.ADD_NEW_SALE')}
-
-
-
-
-
-
-
-
- {this.props.t('SALE.FINANCES.EXPENSES')}
-
-
history.push('/labour')}
- />
- history.push('/other_expense')}
- />
-
-
-
- {this.props.t('SALE.FINANCES.REVENUE')}
-
- history.push('/finances/actual_revenue')}
- />
- history.push('/estimated_revenue')}
- />
-
-
-
- {this.props.t('SALE.FINANCES.BALANCE_FOR_FARM')}
-
-
-
-
{this.props.t('SALE.FINANCES.REVENUE')}:
{' '}
-
{this.state.currencySymbol + totalRevenue}
-
-
-
{this.props.t('SALE.FINANCES.EXPENSES')}:
-
{this.state.currencySymbol + totalExpense.toString()}
-
-
-
{this.props.t('SALE.FINANCES.BALANCE')}:
-
- {this.state.currencySymbol +
- (parseFloat(totalRevenue) - parseFloat(totalExpense)).toFixed(2)}
-
-
-
-
-
- {/*
- {this.props.t('SALE.FINANCES.BALANCE_BY_CROP')}
-
-
-
- {balanceByCrop.map((b) => {
- return (
-
-
{b.crop}
-
{this.state.currencySymbol + b.profit.toFixed(2)}
-
- );
- })}
- {balanceByCrop.length < 1 && (
-
{this.props.t('SALE.FINANCES.ENSURE_ONE_CROP_WARNING')}
- )}
- {hasUnAllocated && (
-
this.toggleTip()}>
- {unTipButton}
-
- )}
- {hasUnAllocated && (
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE1')}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE2')}
-
-
- {this.props.t('common:EG')}
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_1')}{' '}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_2')}
{' '}
- {this.props.t('common:TO')}{' '}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_3')}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE4')}{' '}
- {this.props.t('common:LOCATION')}1
&{' '}
- {this.props.t('common:LOCATION')}2
.
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE5_1')}
- {this.state.currencySymbol}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE5_2')},
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE6_1')}{' '}
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE6_2')}
- {this.state.currencySymbol}60
-
- .
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE7_1')}{' '}
- {this.props.t('common:LOCATION')}1
{' '}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE7_2')}
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE8')}
- {this.state.currencySymbol}30
-
- .
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE9')}{' '}
-
- {this.state.currencySymbol}30/2 = {this.state.currencySymbol}
- 15
-
- .
-
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE10_1')}
- {this.state.currencySymbol}30
{' '}
- {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE10_2')}
-
- )}
-
*/}
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- sales: salesSelector(state),
- shifts: shiftSelector(state),
- tasks: tasksSelector(state),
- expenses: expenseSelector(state),
- managementPlans: managementPlansSelector(state),
- dateRange: dateRangeSelector(state),
- farm: userFarmSelector(state),
- tasksByManagementPlanId: taskEntitiesByManagementPlanIdSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Finances));
diff --git a/packages/webapp/src/containers/Finances/index.jsx b/packages/webapp/src/containers/Finances/index.jsx
new file mode 100644
index 0000000000..4926493883
--- /dev/null
+++ b/packages/webapp/src/containers/Finances/index.jsx
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import styles from './styles.module.scss';
+import DescriptiveButton from '../../components/Inputs/DescriptiveButton';
+import history from '../../history';
+import { dateRangeSelector, expenseSelector, salesSelector, shiftSelector } from './selectors';
+import { getDefaultExpenseType, getExpense, getSales, setDateRange } from './actions';
+import { calcOtherExpense, calcTotalLabour, calcActualRevenue } from './util';
+import Moment from 'moment';
+import { roundToTwoDecimal } from '../../util';
+import DateRangeSelector from '../../components/Finances/DateRangeSelector';
+import InfoBoxComponent from '../../components/InfoBoxComponent';
+import { extendMoment } from 'moment-range';
+import { userFarmSelector } from '../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { managementPlansSelector } from '../managementPlanSlice';
+import { getManagementPlansAndTasks } from '../saga';
+import Button from '../../components/Form/Button';
+import { Semibold, Title } from '../../components/Typography';
+import grabCurrencySymbol from '../../util/grabCurrencySymbol';
+import { taskEntitiesByManagementPlanIdSelector, tasksSelector } from '../taskSlice';
+import { isTaskType } from '../Task/useIsTaskType';
+
+const moment = extendMoment(Moment);
+
+class Finances extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ balanceByCrop: [],
+ startDate: moment().startOf('year'),
+ endDate: moment().endOf('year'),
+ dButtonStyle: {
+ background: '#fff',
+ color: '#333',
+ borderColor: '#fff',
+ boxShadow: '2px 2px 2px 2px rgba(0, 0, 0, 0.2)',
+ width: '100%',
+ },
+ dropDownTitle: this.props.t('SALE.FINANCES.ACTUAL'),
+ focusedInput: null,
+ hasUnAllocated: false,
+ showUnTip: 'none',
+ unTipButton: this.props.t('SALE.FINANCES.UNALLOCATED_TIP'),
+ currencySymbol: grabCurrencySymbol(),
+ };
+ this.getEstimatedRevenue = this.getEstimatedRevenue.bind(this);
+ // this.calcBalanceByCrop = this.calcBalanceByCrop.bind(this);
+ this.getShiftCropOnField = this.getShiftCropOnField.bind(this);
+ this.toggleTip = this.toggleTip.bind(this);
+ this.changeDate = this.changeDate.bind(this);
+ }
+
+ componentDidMount() {
+ const { dateRange } = this.props;
+ this.props.dispatch(getSales());
+ this.props.dispatch(getExpense());
+ this.props.dispatch(getDefaultExpenseType());
+ this.props.dispatch(getManagementPlansAndTasks());
+ //TODO fetch userFarm
+ if (dateRange && dateRange.startDate && dateRange.endDate) {
+ this.setState({
+ startDate: dateRange.startDate,
+ endDate: dateRange.endDate,
+ });
+ } else {
+ this.props.dispatch(
+ setDateRange({
+ startDate: this.state.startDate,
+ endDate: this.state.endDate,
+ }),
+ );
+ }
+ // this.calcBalanceByCrop();
+ }
+
+ componentDidUpdate(prevProps) {
+ // Typical usage (don't forget to compare props):
+ if (
+ this.props.shifts !== prevProps.shifts ||
+ this.props.sales !== prevProps.sales ||
+ this.props.expenses !== prevProps.expenses ||
+ this.props.dateRange !== prevProps.dateRange
+ ) {
+ // this.calcBalanceByCrop();
+ }
+ }
+
+ changeDate(type, date) {
+ if (type === 'start') {
+ this.setState({ startDate: date });
+ } else if (type === 'end') {
+ this.setState({ endDate: date });
+ } else {
+ console.log('Error, type not specified');
+ }
+ }
+
+ getEstimatedRevenue(managementPlans) {
+ let totalRevenue = 0;
+ if (managementPlans) {
+ managementPlans
+ .filter(({ abandon_date }) => !abandon_date)
+ .forEach((plan) => {
+ // check if this plan has a harvest task projected within the time frame
+ const harvestTasks =
+ this.props.tasksByManagementPlanId[plan.management_plan_id]?.filter((task) =>
+ isTaskType(task.taskType, 'HARVEST_TASK'),
+ ) || [];
+ const harvestDates = harvestTasks?.map((task) =>
+ moment(task.due_date).utc().format('YYYY-MM-DD'),
+ );
+
+ if (
+ harvestDates.some(
+ (harvestDate) =>
+ moment(this.state.startDate)
+ .startOf('day')
+ .utc()
+ .isSameOrBefore(harvestDate, 'day') &&
+ moment(this.state.endDate).utc().isSameOrAfter(harvestDate, 'day'),
+ )
+ ) {
+ totalRevenue += plan.estimated_revenue;
+ }
+ });
+ }
+ return parseFloat(totalRevenue).toFixed(2);
+ }
+
+ getTotalExpense = () => {
+ const { expenses } = this.props;
+ const { startDate, endDate } = this.state;
+
+ let total = 0;
+ if (expenses && expenses.length) {
+ for (let e of expenses) {
+ if (
+ moment(e.expense_date).isSameOrAfter(startDate, 'day') &&
+ moment(e.expense_date).isSameOrBefore(endDate, 'day')
+ ) {
+ total += Number(e.value);
+ }
+ }
+ }
+
+ return total;
+ };
+
+ // TODO: currently commented out all usages of this function, until ful refactor to crop variety
+ calcBalanceByCrop() {
+ const { shifts, sales, expenses } = this.props;
+ const { startDate, endDate } = this.state;
+
+ if (!(shifts || sales || expenses)) return;
+
+ let final = Object.assign({}, {}); // crop: crop name, profit: number
+
+ let unAllocated = 0;
+ let unAllocatedShifts = {};
+
+ let totalExpense = this.getTotalExpense();
+
+ if (shifts && shifts.length) {
+ for (let s of shifts) {
+ let management_plan_id = s.management_plan_id;
+ const shiftDate = moment(s.shift_date);
+ if (shiftDate.isSameOrAfter(startDate, 'day') && shiftDate.isSameOrBefore(endDate, 'day')) {
+ if (management_plan_id !== null) {
+ if (final.hasOwnProperty(management_plan_id)) {
+ final[management_plan_id].profit =
+ final[management_plan_id].profit +
+ Number(s.wage_at_moment) * (Number(s.duration) / 60) * -1;
+ } else {
+ final[management_plan_id] = {
+ profit: Number(s.wage_at_moment) * (Number(s.duration) / 60) * -1,
+ crop_translation_key: s.crop_translation_key,
+ location_id: s.location_id,
+ crop_id: s.crop_id,
+ management_plan_id: s.management_plan_id,
+ };
+ }
+ }
+ // else it's unallocated
+ else {
+ if (unAllocatedShifts.hasOwnProperty(s.location_id)) {
+ unAllocatedShifts[s.location_id].value =
+ unAllocatedShifts[s.location_id].value +
+ Number(s.wage_at_moment) * (Number(s.duration) / 60);
+ } else {
+ unAllocatedShifts = Object.assign(unAllocatedShifts, {
+ [s.location_id]: {
+ value: Number(s.wage_at_moment) * (Number(s.duration) / 60),
+ hasAllocated: false,
+ },
+ });
+ }
+ }
+ }
+ }
+ }
+
+ // balance by crop used to be sorted by field crop,
+ // i'm keeping the original code, and will modify the object to make it sorted by crop
+ final = this.convertToCropID(final);
+
+ // allocate unallocated to used-to-be fields
+ let ukeys = Object.keys(unAllocatedShifts);
+ for (let uk of ukeys) {
+ // uk = location_id
+ let uShift = unAllocatedShifts[uk];
+
+ // a list of crop ids
+ let waitForAllocate = this.getCropsByFieldID(uk);
+
+ let avg = Number(parseFloat(uShift.value / waitForAllocate.length).toFixed(2));
+
+ let fkeys = Object.keys(final);
+
+ for (let wa of waitForAllocate) {
+ for (let fk of fkeys) {
+ if (Number(fk) === Number(wa)) {
+ final[fk].profit -= avg;
+ }
+ }
+ }
+
+ if (waitForAllocate.length > 0) {
+ unAllocatedShifts[uk].hasAllocated = true;
+ }
+ }
+
+ let cropKeys = Object.keys(final);
+ let averageExpense = Number(parseFloat(totalExpense / cropKeys.length).toFixed(2));
+ // apply expense evenly to each crop
+ for (let ck of cropKeys) {
+ final[ck].profit -= averageExpense;
+ }
+
+ for (let uk of ukeys) {
+ let uShift = unAllocatedShifts[uk];
+ if (!uShift.hasAllocated) {
+ unAllocated += uShift.value;
+ }
+ }
+
+ if (unAllocated !== 0) {
+ final = Object.assign(final, {
+ unallocated: {
+ crop: this.props.t('SALE.FINANCES.UNALLOCATED_CROP'),
+ profit: unAllocated * -1,
+ },
+ });
+ }
+
+ this.setState({
+ balanceByCrop: Object.values(final),
+ });
+ }
+
+ getCropsByFieldID = (location_id) => {
+ const { managementPlans } = this.props;
+
+ let result = new Set();
+
+ for (let fc of managementPlans) {
+ if (fc.location_id === location_id) {
+ result.add(fc.crop_id);
+ }
+ }
+
+ return Array.from(result);
+ };
+
+ convertToCropID = (final) => {
+ let fcIDs = Object.keys(final);
+ let result = {};
+
+ const { startDate, endDate } = this.state;
+ const { sales } = this.props;
+
+ for (let fkey of fcIDs) {
+ let value = final[fkey];
+ if (result.hasOwnProperty(value.crop_id)) {
+ result[value.crop_id].profit += value.profit;
+ } else {
+ result[value.crop_id] = {
+ crop: this.props.t(`crop:${value.crop_translation_key}`),
+ location_id: value.location_id,
+ crop_id: value.crop_id,
+ profit: value.profit,
+ };
+ }
+ }
+
+ //apply sales
+ for (let sale of sales || []) {
+ const saleDate = moment(sale.sale_date);
+
+ if (saleDate.isSameOrAfter(startDate, 'day') && saleDate.isSameOrBefore(endDate, 'day')) {
+ for (let cp of sale.cropSale) {
+ if (cp.crop && result.hasOwnProperty(cp.crop.crop_id)) {
+ result[cp.crop.crop_id].profit += Number(cp.sale_value);
+ } else {
+ result[cp.crop.crop_id] = {
+ crop: this.props.t(`crop:${cp.crop.crop_translation_key}`),
+ location_id: 'not available',
+ crop_id: cp.crop.crop_id,
+ profit: Number(cp.sale_value),
+ };
+ }
+ }
+ }
+ }
+
+ return result;
+ };
+
+ getShiftCropOnField(location_id) {
+ const { shifts } = this.props;
+
+ let crops = [];
+
+ for (let s of shifts) {
+ if (s.location_id === location_id && s.crop_id) {
+ crops.push(s.crop_id);
+ }
+ }
+
+ return crops;
+ }
+
+ toggleTip() {
+ let { showUnTip } = this.state;
+ let unTipButton;
+ if (showUnTip === 'block') {
+ showUnTip = 'none';
+ unTipButton = this.props.t('SALE.FINANCES.UNALLOCATED_TIP');
+ } else {
+ showUnTip = 'block';
+ unTipButton = this.props.t('common:HIDE');
+ }
+ this.setState({ showUnTip, unTipButton });
+ }
+
+ render() {
+ const totalRevenue = calcActualRevenue(
+ this.props.sales,
+ this.state.startDate,
+ this.state.endDate,
+ ).toFixed(2);
+ const estimatedRevenue = this.getEstimatedRevenue(this.props.managementPlans);
+ const { tasks, expenses } = this.props;
+ const { balanceByCrop, startDate, endDate, hasUnAllocated, showUnTip, unTipButton } =
+ this.state;
+ const labourExpense = roundToTwoDecimal(calcTotalLabour(tasks, startDate, endDate));
+ const otherExpense = calcOtherExpense(expenses, startDate, endDate);
+ const totalExpense = (parseFloat(otherExpense) + parseFloat(labourExpense)).toFixed(2);
+ return (
+
+
{this.props.t('SALE.FINANCES.TITLE')}
+
+
{this.props.t('SALE.FINANCES.ACTION')}
+
+ {
+ history.push('/expense_categories');
+ }}
+ >
+ {this.props.t('SALE.FINANCES.ADD_NEW_EXPENSE')}
+
+ {
+ history.push('add_sale');
+ }}
+ >
+ {this.props.t('SALE.FINANCES.ADD_NEW_SALE')}
+
+
+
+
+
+
+
+
+ {this.props.t('SALE.FINANCES.EXPENSES')}
+
+
history.push('/labour')}
+ />
+ history.push('/other_expense')}
+ />
+
+
+
+ {this.props.t('SALE.FINANCES.REVENUE')}
+
+ history.push('/finances/actual_revenue')}
+ />
+ history.push('/estimated_revenue')}
+ />
+
+
+
+
+ {this.props.t('SALE.FINANCES.BALANCE_FOR_FARM')}
+
+
+
+
+
+
{this.props.t('SALE.FINANCES.REVENUE')}:
{' '}
+
{this.state.currencySymbol + totalRevenue}
+
+
+
{this.props.t('SALE.FINANCES.EXPENSES')}:
+
{this.state.currencySymbol + totalExpense.toString()}
+
+
+
{this.props.t('SALE.FINANCES.BALANCE')}:
+
+ {this.state.currencySymbol +
+ (parseFloat(totalRevenue) - parseFloat(totalExpense)).toFixed(2)}
+
+
+
+
+ {/*
+ {this.props.t('SALE.FINANCES.BALANCE_BY_CROP')}
+
+
+
+ {balanceByCrop.map((b) => {
+ return (
+
+
{b.crop}
+
{this.state.currencySymbol + b.profit.toFixed(2)}
+
+ );
+ })}
+ {balanceByCrop.length < 1 && (
+
{this.props.t('SALE.FINANCES.ENSURE_ONE_CROP_WARNING')}
+ )}
+ {hasUnAllocated && (
+
this.toggleTip()}>
+ {unTipButton}
+
+ )}
+ {hasUnAllocated && (
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE1')}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE2')}
+
+
+ {this.props.t('common:EG')}
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_1')}{' '}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_2')}
{' '}
+ {this.props.t('common:TO')}{' '}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE3_3')}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE4')}{' '}
+ {this.props.t('common:LOCATION')}1
&{' '}
+ {this.props.t('common:LOCATION')}2
.
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE5_1')}
+ {this.state.currencySymbol}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE5_2')},
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE6_1')}{' '}
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE6_2')}
+ {this.state.currencySymbol}60
+
+ .
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE7_1')}{' '}
+ {this.props.t('common:LOCATION')}1
{' '}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE7_2')}
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE8')}
+ {this.state.currencySymbol}30
+
+ .
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE9')}{' '}
+
+ {this.state.currencySymbol}30/2 = {this.state.currencySymbol}
+ 15
+
+ .
+
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE10_1')}
+ {this.state.currencySymbol}30
{' '}
+ {this.props.t('SALE.FINANCES.HAS_UNALLOCATED_LINE10_2')}
+
+ )}
+
*/}
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ sales: salesSelector(state),
+ shifts: shiftSelector(state),
+ tasks: tasksSelector(state),
+ expenses: expenseSelector(state),
+ managementPlans: managementPlansSelector(state),
+ dateRange: dateRangeSelector(state),
+ farm: userFarmSelector(state),
+ tasksByManagementPlanId: taskEntitiesByManagementPlanIdSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Finances));
diff --git a/packages/webapp/src/containers/Finances/util.js b/packages/webapp/src/containers/Finances/util.js
index f9da332c2b..44d27b4e1d 100644
--- a/packages/webapp/src/containers/Finances/util.js
+++ b/packages/webapp/src/containers/Finances/util.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (util.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,26 +14,27 @@
*/
import moment from 'moment';
+import { roundToTwoDecimal } from '../../util';
export function calcTotalLabour(tasks, startDate, endDate) {
- let total = 0;
+ let total = 0.0;
if (Array.isArray(tasks)) {
- for (let t of tasks) {
- const completedTime = moment(t.completed_time);
- const abandonedTime = moment(t.abandoned_time);
+ for (const t of tasks) {
+ const completedTime = moment(t.complete_date);
+ const abandonedTime = moment(t.abandon_date);
if (
- ( completedTime.isSameOrAfter(startDate, 'day') &&
+ (completedTime.isSameOrAfter(startDate, 'day') &&
completedTime.isSameOrBefore(endDate, 'day') &&
t.duration) ||
- ( abandonedTime.isSameOrAfter(startDate, 'day') &&
+ (abandonedTime.isSameOrAfter(startDate, 'day') &&
abandonedTime.isSameOrBefore(endDate, 'day') &&
t.duration)
) {
// TODO: possibly implement check when wage can be yearly
// if (s.wage.type === 'hourly')
- let rate = parseFloat(t.wage_at_moment).toFixed(2);
- let hoursWorked = Number((t.duration / 60).toFixed(2));
- total += rate * hoursWorked;
+ const rate = roundToTwoDecimal(t.wage_at_moment);
+ const hoursWorked = roundToTwoDecimal(t.duration / 60);
+ total = roundToTwoDecimal(roundToTwoDecimal(total) + roundToTwoDecimal(rate * hoursWorked));
}
}
}
@@ -57,59 +58,64 @@ export const filterSalesByCurrentYear = (sales) => {
};
export function calcOtherExpense(expenses, startDate, endDate) {
- let total = 0;
+ let total = 0.0;
if (Array.isArray(expenses)) {
- for (let e of expenses) {
+ for (const e of expenses) {
const expenseDate = moment(e.expense_date);
if (
expenseDate.isSameOrAfter(startDate, 'day') &&
expenseDate.isSameOrBefore(endDate, 'day')
) {
- total += parseFloat(e.value);
+ total = roundToTwoDecimal(total + roundToTwoDecimal(e.value));
}
}
}
- total = total.toFixed(2);
return total;
}
-export function calcSales(sales, startDate, endDate) {
- let total = 0;
+export function filterSalesByDateRange(sales, startDate, endDate) {
+ if (sales && Array.isArray(sales)) {
+ return sales.filter((s) => {
+ const saleDate = moment(s.sale_date);
+ return saleDate.isSameOrAfter(startDate, 'day') && saleDate.isSameOrBefore(endDate, 'day');
+ });
+ }
+ return [];
+}
+
+export function calcActualRevenue(sales, startDate, endDate) {
+ let total = 0.0;
- if (Array.isArray(sales)) {
- for (let s of sales) {
+ if (sales && Array.isArray(sales)) {
+ for (const s of sales) {
const saleDate = moment(s.sale_date);
- if (
- saleDate.isSameOrAfter(startDate, 'day') &&
- saleDate.isSameOrBefore(endDate, 'day')
- ) {
- for (let c of s.cropSale) {
- total += parseFloat(c.sale_value);
+ if (saleDate.isSameOrAfter(startDate, 'day') && saleDate.isSameOrBefore(endDate, 'day')) {
+ for (const c of s.crop_variety_sale) {
+ total = roundToTwoDecimal(roundToTwoDecimal(total) + roundToTwoDecimal(c.sale_value));
}
}
}
}
- total = total.toFixed(2);
return total;
}
export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
- let sortObj = {};
- let unAllocated = {};
+ const sortObj = {};
+ const unAllocated = {};
if (shifts && shifts.length) {
- for (let s of shifts) {
- let cid = s.crop_id;
+ for (const s of shifts) {
+ const cid = s.crop_id;
+ const cost = roundToTwoDecimal(
+ roundToTwoDecimal(s.wage_at_moment) * roundToTwoDecimal(s.duration / 60),
+ );
if (cid) {
const shiftDate = moment(s.shift_date);
- if (
- shiftDate.isSameOrAfter(startDate, 'day') &&
- shiftDate.isSameOrBefore(endDate, 'day')
- ) {
+ if (shiftDate.isSameOrAfter(startDate, 'day') && shiftDate.isSameOrBefore(endDate, 'day')) {
if (sortObj.hasOwnProperty(cid)) {
- sortObj[cid].cost += parseFloat(s.wage_at_moment) * (s.duration / 60);
+ sortObj[cid].cost = roundToTwoDecimal(roundToTwoDecimal(sortObj[cid].cost) + cost);
} else {
sortObj[cid] = {
- cost: parseFloat(s.wage_at_moment) * (s.duration / 60),
+ cost,
crop: s.crop_common_name,
revenue: 0,
};
@@ -118,26 +124,30 @@ export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
} else {
if (s.location_id && s.is_field) {
if (unAllocated.hasOwnProperty(s.location_id)) {
- unAllocated[s.location_id] += Number(parseFloat(s.wage_at_moment) * (s.duration / 60));
+ unAllocated[s.location_id] = roundToTwoDecimal(
+ roundToTwoDecimal(unAllocated[s.location_id] + cost),
+ );
} else {
- unAllocated[s.location_id] = Number(parseFloat(s.wage_at_moment) * (s.duration / 60));
+ unAllocated[s.location_id] = cost;
}
}
}
}
}
- let fieldKeys = Object.keys(unAllocated);
+ const fieldKeys = Object.keys(unAllocated);
- for (let fk of fieldKeys) {
- let shiftCropOnField = getShiftCropOnField(fk, shifts);
+ for (const fk of fieldKeys) {
+ const shiftCropOnField = getShiftCropOnField(fk, shifts);
let isAllocated = false;
if (shiftCropOnField.length) {
- let avgCost = unAllocated[fk] / shiftCropOnField.length;
- for (let c of shiftCropOnField) {
+ const avgCost = roundToTwoDecimal(
+ roundToTwoDecimal(unAllocated[fk]) / shiftCropOnField.length,
+ );
+ for (const c of shiftCropOnField) {
if (sortObj.hasOwnProperty(c)) {
isAllocated = true;
- sortObj[c].cost += avgCost;
+ sortObj[c].cost = roundToTwoDecimal(roundToTwoDecimal(sortObj[c].cost) + avgCost);
}
}
}
@@ -155,8 +165,8 @@ export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
crop: 'Unallocated*',
revenue: 0,
};
- for(let fk of fieldKeys){
- sortObj['unallocated'].cost += unAllocated[fk];
+ for(const fk of fieldKeys){
+ sortObj['unallocated'].cost = roundToTwoDecimal(roundToTwoDecimal(sortObj['unallocated'].cost) + roundToTwoDecimal(unAllocated[fk]));
}
this.setState({
hasUnAllocated: true,
@@ -165,31 +175,31 @@ export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
*/
let keys = Object.keys(sortObj);
- let numOfCrops = keys.length;
- let expensePerCrop = Number(
- (parseFloat(calcOtherExpense(expenses, startDate, endDate)) / numOfCrops).toFixed(2),
+ const numOfCrops = keys.length;
+ const expensePerCrop = roundToTwoDecimal(
+ calcOtherExpense(expenses, startDate, endDate) / numOfCrops,
);
- for (let k of keys) {
- sortObj[k].cost += Number(parseFloat(expensePerCrop).toFixed(2));
+ for (const k of keys) {
+ sortObj[k].cost = roundToTwoDecimal(roundToTwoDecimal(sortObj[k].cost) + expensePerCrop);
}
if (sales && sales.length) {
- for (let s of sales) {
+ for (const s of sales) {
const saleDate = moment(s.sale_date);
- if (
- saleDate.isSameOrAfter(startDate, 'day') &&
- saleDate.isSameOrBefore(endDate, 'day')
- ) {
- for (let cropSale of s.cropSale) {
- let cid = cropSale.managementPlan.crop_id;
+ if (saleDate.isSameOrAfter(startDate, 'day') && saleDate.isSameOrBefore(endDate, 'day')) {
+ for (const cropSale of s.cropSale) {
+ const cid = cropSale.managementPlan.crop_id;
+ const revenue = roundToTwoDecimal(cropSale.sale_value);
if (sortObj.hasOwnProperty(cid)) {
- sortObj[cid].revenue += Number(parseFloat(cropSale.sale_value).toFixed(2));
+ sortObj[cid].revenue = roundToTwoDecimal(
+ roundToTwoDecimal(sortObj[cid].revenue) + revenue,
+ );
} else {
sortObj[cid] = {
cost: 0,
crop: cropSale.managementPlan.crop.crop_common_name,
- revenue: Number(parseFloat(cropSale.sale_value).toFixed(2)),
+ revenue,
};
}
}
@@ -197,12 +207,14 @@ export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
}
}
- let final = [];
+ const final = [];
keys = Object.keys(sortObj);
- for (let k of keys) {
+ for (const k of keys) {
final.push({
crop: sortObj[k].crop,
- profit: Number((parseFloat(sortObj[k].revenue) - parseFloat(sortObj[k].cost)).toFixed(2)),
+ profit: roundToTwoDecimal(
+ roundToTwoDecimal(sortObj[k].revenue) - roundToTwoDecimal(sortObj[k].cost),
+ ),
});
}
@@ -210,9 +222,9 @@ export function calcBalanceByCrop(shifts, sales, expenses, startDate, endDate) {
}
export function getShiftCropOnField(fieldID, shifts) {
- let crops = [];
+ const crops = [];
- for (let s of shifts) {
+ for (const s of shifts) {
if (s.location_id === fieldID && s.crop_id) {
crops.push(s.crop_id);
}
diff --git a/packages/webapp/src/containers/GoogleLoginButton/index.js b/packages/webapp/src/containers/GoogleLoginButton/index.js
deleted file mode 100644
index efd4f993a0..0000000000
--- a/packages/webapp/src/containers/GoogleLoginButton/index.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React from 'react';
-import GoogleLogin from 'react-google-login';
-import { useDispatch } from 'react-redux';
-import { loginWithGoogle } from './saga';
-import styles from './googleLoginButton.module.scss';
-import { useTranslation } from 'react-i18next';
-import clsx from 'clsx';
-
-function GoogleLoginButton({ disabled }) {
- const dispatch = useDispatch();
- const clientId = process.env.REACT_APP_GOOGLE_OAUTH_CLIENT_ID;
- const onSuccess = (res) => {
- dispatch(loginWithGoogle(res.tokenObj.id_token));
- };
- const onFailure = (res) => {
- console.log(res);
- };
- const { t } = useTranslation();
-
- return (
-
- {t('SIGNUP.GOOGLE_BUTTON')}
-
- );
-}
-
-/**
- Google res shape
- res:{
- profileObj:{
- email: "litefarmdev0@gmail.com"
- familyName: "dev"
- givenName: "litefarm"
- googleId: "104942873090979111002"
- imageUrl: "https://lh5.googleusercontent.com/-ICoPrywDAt0/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclA_5NvcmJaWZP4UlYtqwMIh8PJUw/s96-c/photo.jpg"
- name: "litefarm dev"
- },
- tokenObj:{
- access_token: "ya29.a0AfH6SMAzJ7UwkBMxt7HqCRNiYO5EVgtlBbAbPWfqVF2CaM3suld0ZCZSieXrjhh9zhN7_ArqqAaP20-EnXt1EnuqBJqPG5GJNdQPEKCEIJ3yNahso0jlXewTt-drEiYj-_aiUrrpc-KXuQBNVDUkzoJdpJFk9AsDoKjbQ3NCb5KV"
- expires_at: 1607546106563
- expires_in: 3599
- first_issued_at: 1607542507563
- id_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ0Y2JhMjVlNTYzNjYwYTkwMDlkODIwYTFjMDIwMjIwNzA1NzRlODIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiMTA2MjgxNDAwMDIyNy1yZTRnOXQ5cWNhcjFlYWJicmhma2hwYW9qOGtwdjRqNS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF1ZCI6IjEwNjI4MTQwMDAyMjctcmU0Zzl0OXFjYXIxZWFiYnJoZmtocGFvajhrcHY0ajUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDQ5NDI4NzMwOTA5NzkxMTEwMDIiLCJlbWFpbCI6ImxpdGVmYXJtZGV2MEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6Inh6QjlKNXdMcW1VU255cThYWWFhWEEiLCJuYW1lIjoibGl0ZWZhcm0gZGV2IiwicGljdHVyZSI6Imh0dHBzOi8vbGg1Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tSUNvUHJ5d0RBdDAvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQU1adXVjbEFfNU52Y21KYVdaUDRVbFl0cXdNSWg4UEpVdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoibGl0ZWZhcm0iLCJmYW1pbHlfbmFtZSI6ImRldiIsImxvY2FsZSI6ImVuLUdCIiwiaWF0IjoxNjA3NTQyNTA3LCJleHAiOjE2MDc1NDYxMDcsImp0aSI6ImU4MjkwYmZhZmM2OWJiMzBhMzdlZjFjZDA2ZmViYWRhMjNmOTRlZGIifQ.AlqFs0GbBOS_ir5qxHYj4XE3HMcuihmYyepPUhn_8yTqFuN1lTZ6q3kbwLBGfIQYAi_a1YMgIcdRMp9nq8sVpy4tElIxouCXfahxvhpQhmKQXJ3Sl91WZNV9L7w0rfCMnXRV1f7KOMUyEwAAjzzWWyUT2yaya-xYAyyLWuvGOdldBHTMIBWtIF94LvCgyYmQqw1XGm86zw1OGPNa9x_lWHnH3SJvKVVRDStEYLey_HI9T2Qfbd2n9PPcqYRETXrzLNCQhMYj2sIH6yE96Bwm_cCmhursQqiyYkcISa1XQEuYXk7WmW-PpQyC3KmW31pN4FKYQnBQwPYJklc3Ki_f1A"
- idpId: "google"
- login_hint: "AJDLj6JUa8yxXrhHdWRHIV0S13cAfzUd9_mqXX2hOmOQOH48fV9-ibdj4DsNe9MxdK39uVTNLls4qSIpa0KWHPfnPpznZJqgHA"
- scope: "email profile https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email openid"
- session_state: {extraQueryParams: {…}}
- token_type: "Bearer"
- }
-}
- */
-
-export default GoogleLoginButton;
diff --git a/packages/webapp/src/containers/GoogleLoginButton/index.jsx b/packages/webapp/src/containers/GoogleLoginButton/index.jsx
new file mode 100644
index 0000000000..8507ac2d41
--- /dev/null
+++ b/packages/webapp/src/containers/GoogleLoginButton/index.jsx
@@ -0,0 +1,61 @@
+import React from 'react';
+import GoogleLogin from 'react-google-login';
+import { useDispatch } from 'react-redux';
+import { loginWithGoogle } from './saga';
+import styles from './googleLoginButton.module.scss';
+import { useTranslation } from 'react-i18next';
+import clsx from 'clsx';
+
+function GoogleLoginButton({ disabled }) {
+ const dispatch = useDispatch();
+ const clientId = import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID;
+ const onSuccess = (res) => {
+ dispatch(loginWithGoogle(res.tokenObj.id_token));
+ };
+ const onFailure = (res) => {
+ console.log(res);
+ };
+ const { t } = useTranslation();
+
+ return (
+
+ {t('SIGNUP.GOOGLE_BUTTON')}
+
+ );
+}
+
+/**
+ Google res shape
+ res:{
+ profileObj:{
+ email: "litefarmdev0@gmail.com"
+ familyName: "dev"
+ givenName: "litefarm"
+ googleId: "104942873090979111002"
+ imageUrl: "https://lh5.googleusercontent.com/-ICoPrywDAt0/AAAAAAAAAAI/AAAAAAAAAAA/AMZuuclA_5NvcmJaWZP4UlYtqwMIh8PJUw/s96-c/photo.jpg"
+ name: "litefarm dev"
+ },
+ tokenObj:{
+ access_token: "ya29.a0AfH6SMAzJ7UwkBMxt7HqCRNiYO5EVgtlBbAbPWfqVF2CaM3suld0ZCZSieXrjhh9zhN7_ArqqAaP20-EnXt1EnuqBJqPG5GJNdQPEKCEIJ3yNahso0jlXewTt-drEiYj-_aiUrrpc-KXuQBNVDUkzoJdpJFk9AsDoKjbQ3NCb5KV"
+ expires_at: 1607546106563
+ expires_in: 3599
+ first_issued_at: 1607542507563
+ id_token: "eyJhbGciOiJSUzI1NiIsImtpZCI6ImQ0Y2JhMjVlNTYzNjYwYTkwMDlkODIwYTFjMDIwMjIwNzA1NzRlODIiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiMTA2MjgxNDAwMDIyNy1yZTRnOXQ5cWNhcjFlYWJicmhma2hwYW9qOGtwdjRqNS5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImF1ZCI6IjEwNjI4MTQwMDAyMjctcmU0Zzl0OXFjYXIxZWFiYnJoZmtocGFvajhrcHY0ajUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDQ5NDI4NzMwOTA5NzkxMTEwMDIiLCJlbWFpbCI6ImxpdGVmYXJtZGV2MEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6Inh6QjlKNXdMcW1VU255cThYWWFhWEEiLCJuYW1lIjoibGl0ZWZhcm0gZGV2IiwicGljdHVyZSI6Imh0dHBzOi8vbGg1Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tSUNvUHJ5d0RBdDAvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQU1adXVjbEFfNU52Y21KYVdaUDRVbFl0cXdNSWg4UEpVdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoibGl0ZWZhcm0iLCJmYW1pbHlfbmFtZSI6ImRldiIsImxvY2FsZSI6ImVuLUdCIiwiaWF0IjoxNjA3NTQyNTA3LCJleHAiOjE2MDc1NDYxMDcsImp0aSI6ImU4MjkwYmZhZmM2OWJiMzBhMzdlZjFjZDA2ZmViYWRhMjNmOTRlZGIifQ.AlqFs0GbBOS_ir5qxHYj4XE3HMcuihmYyepPUhn_8yTqFuN1lTZ6q3kbwLBGfIQYAi_a1YMgIcdRMp9nq8sVpy4tElIxouCXfahxvhpQhmKQXJ3Sl91WZNV9L7w0rfCMnXRV1f7KOMUyEwAAjzzWWyUT2yaya-xYAyyLWuvGOdldBHTMIBWtIF94LvCgyYmQqw1XGm86zw1OGPNa9x_lWHnH3SJvKVVRDStEYLey_HI9T2Qfbd2n9PPcqYRETXrzLNCQhMYj2sIH6yE96Bwm_cCmhursQqiyYkcISa1XQEuYXk7WmW-PpQyC3KmW31pN4FKYQnBQwPYJklc3Ki_f1A"
+ idpId: "google"
+ login_hint: "AJDLj6JUa8yxXrhHdWRHIV0S13cAfzUd9_mqXX2hOmOQOH48fV9-ibdj4DsNe9MxdK39uVTNLls4qSIpa0KWHPfnPpznZJqgHA"
+ scope: "email profile https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email openid"
+ session_state: {extraQueryParams: {…}}
+ token_type: "Bearer"
+ }
+}
+ */
+
+export default GoogleLoginButton;
diff --git a/packages/webapp/src/containers/GoogleLoginButton/saga.js b/packages/webapp/src/containers/GoogleLoginButton/saga.js
index 3b763656a9..6a3f716c39 100644
--- a/packages/webapp/src/containers/GoogleLoginButton/saga.js
+++ b/packages/webapp/src/containers/GoogleLoginButton/saga.js
@@ -32,17 +32,21 @@ export function* loginWithGoogleSaga({ payload: google_id_token }) {
localStorage.setItem('id_token', id_token);
localStorage.setItem('litefarm_lang', user.language_preference);
if (id_token === '') {
- history.push({
- pathname: '/',
- state: { component: ENTER_PASSWORD_PAGE, user },
- });
+ history.push(
+ {
+ pathname: '/',
+ },
+ { component: ENTER_PASSWORD_PAGE, user },
+ );
} else {
yield put(loginSuccess(user));
if (isSignUp) {
- history.push({
- pathname: '/sso_signup_information',
- state: { user },
- });
+ history.push(
+ {
+ pathname: '/sso_signup_information',
+ },
+ { user },
+ );
} else {
history.push('/farm_selection');
}
diff --git a/packages/webapp/src/containers/Help/index.js b/packages/webapp/src/containers/Help/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Help/index.js
rename to packages/webapp/src/containers/Help/index.jsx
diff --git a/packages/webapp/src/containers/Home/index.js b/packages/webapp/src/containers/Home/index.js
deleted file mode 100644
index b0bea8a8e4..0000000000
--- a/packages/webapp/src/containers/Home/index.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import React, { useState } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import { getSeason } from './utils/season';
-import WeatherBoard from '../../containers/WeatherBoard';
-import PureHome from '../../components/Home';
-import { isAdminSelector, userFarmSelector } from '../userFarmSlice';
-import { useTranslation } from 'react-i18next';
-import FarmSwitchOutro from '../FarmSwitchOutro';
-import RequestConfirmationComponent from '../../components/Modals/RequestConfirmationModal';
-import { dismissHelpRequestModal, showHelpRequestModalSelector } from './homeSlice';
-import {
- chooseFarmFlowSelector,
- endExportModal,
- endSwitchFarmModal,
- switchFarmSelector,
-} from '../ChooseFarm/chooseFarmFlowSlice';
-import NotifyUpdatedFarmModal from '../../components/Modals/NotifyUpdatedFarmModal';
-import { showedSpotlightSelector } from '../showedSpotlightSlice';
-import { setSpotlightToShown } from '../Map/saga';
-import PreparingExportModal from '../../components/Modals/PreparingExportModal';
-import { doesCertifierSurveyExistSelector } from '../OrganicCertifierSurvey/slice';
-import { CertificationsModal } from '../../components/Modals/CertificationsModal';
-import { setIntroducingCertifications } from '../Navigation/navbarSlice';
-
-export default function Home({ history }) {
- const { t } = useTranslation();
- const userFarm = useSelector(userFarmSelector);
- const imgUrl = getSeason(userFarm?.grid_points?.lat);
- const { showSpotLight, showExportModal } = useSelector(chooseFarmFlowSelector);
- const dispatch = useDispatch();
- const showSwitchFarmModal = useSelector(switchFarmSelector);
- const dismissPopup = () => dispatch(endSwitchFarmModal(userFarm.farm_id));
- const dismissExportModal = () => dispatch(endExportModal(userFarm.farm_id));
-
- const showHelpRequestModal = useSelector(showHelpRequestModalSelector);
- const showRequestConfirmationModalOnClick = () => dispatch(dismissHelpRequestModal());
- const { introduce_map, navigation } = useSelector(showedSpotlightSelector);
- const showNotifyUpdatedFarmModal = !introduce_map && navigation;
-
- // TODO: remove after mini release LF-2131: Certification modal logic
- const doesCertifierSurveyExist = useSelector(doesCertifierSurveyExistSelector);
-
- const isAdmin = useSelector(isAdminSelector);
- const [showCertificationsModal, setShowCertificationsModal] = useState(
- !doesCertifierSurveyExist && isAdmin,
- );
- const onClickMaybeLater = () => {
- dispatch(setIntroducingCertifications(true));
- };
- const onClickCertificationsYes = () => {
- history.push('/certification/interested_in_organic');
- };
-
- return (
-
- {userFarm ? : null}
- {showSwitchFarmModal && !showSpotLight && }
-
- {showSwitchFarmModal && !showSpotLight && (
-
- )}
-
- {showHelpRequestModal && (
-
- )}
-
- {showNotifyUpdatedFarmModal && (
- dispatch(setSpotlightToShown('introduce_map'))}
- />
- )}
-
- {showExportModal && dismissExportModal(false)} />}
-
- {showCertificationsModal && (
- {
- setShowCertificationsModal(false);
- dispatch(setIntroducingCertifications(false));
- }}
- />
- )}
-
- );
-}
diff --git a/packages/webapp/src/containers/Home/index.jsx b/packages/webapp/src/containers/Home/index.jsx
new file mode 100644
index 0000000000..824f057132
--- /dev/null
+++ b/packages/webapp/src/containers/Home/index.jsx
@@ -0,0 +1,53 @@
+import React, { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import { getSeason } from './utils/season';
+import WeatherBoard from '../../containers/WeatherBoard';
+import PureHome from '../../components/Home';
+import { userFarmSelector } from '../userFarmSlice';
+import { useTranslation } from 'react-i18next';
+import FarmSwitchOutro from '../FarmSwitchOutro';
+import RequestConfirmationComponent from '../../components/Modals/RequestConfirmationModal';
+import { dismissHelpRequestModal, showHelpRequestModalSelector } from './homeSlice';
+import {
+ chooseFarmFlowSelector,
+ endExportModal,
+ endSwitchFarmModal,
+ switchFarmSelector,
+} from '../ChooseFarm/chooseFarmFlowSlice';
+
+import PreparingExportModal from '../../components/Modals/PreparingExportModal';
+import { getAlert } from '../Navigation/Alert/saga.js';
+
+export default function Home({ history }) {
+ const { t } = useTranslation();
+ const userFarm = useSelector(userFarmSelector);
+ const imgUrl = getSeason(userFarm?.grid_points?.lat);
+ const { showSpotLight, showExportModal } = useSelector(chooseFarmFlowSelector);
+ const dispatch = useDispatch();
+ const showSwitchFarmModal = useSelector(switchFarmSelector);
+ const dismissPopup = () => dispatch(endSwitchFarmModal(userFarm.farm_id));
+ const dismissExportModal = () => dispatch(endExportModal(userFarm.farm_id));
+
+ const showHelpRequestModal = useSelector(showHelpRequestModalSelector);
+ const showRequestConfirmationModalOnClick = () => dispatch(dismissHelpRequestModal());
+
+ useEffect(() => {
+ dispatch(getAlert());
+ }, []);
+
+ return (
+
+ {userFarm ? : null}
+ {showSwitchFarmModal && !showSpotLight && }
+
+ {showHelpRequestModal && (
+
+ )}
+
+ {showExportModal && dismissExportModal(false)} />}
+
+ );
+}
diff --git a/packages/webapp/src/containers/ImagePickerWrapper/index.js b/packages/webapp/src/containers/ImagePickerWrapper/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/ImagePickerWrapper/index.js
rename to packages/webapp/src/containers/ImagePickerWrapper/index.jsx
diff --git a/packages/webapp/src/containers/ImageWithAuthentication/index.js b/packages/webapp/src/containers/ImageWithAuthentication/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/ImageWithAuthentication/index.js
rename to packages/webapp/src/containers/ImageWithAuthentication/index.jsx
diff --git a/packages/webapp/src/containers/Insights/Biodiversity/index.js b/packages/webapp/src/containers/Insights/Biodiversity/index.js
deleted file mode 100644
index 964abee631..0000000000
--- a/packages/webapp/src/containers/Insights/Biodiversity/index.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import insightStyles from '../styles.module.scss';
-import PageTitle from '../../../components/PageTitle';
-import { biodiversitySelector } from '../selectors';
-import BiodiversitySpecies from '../../../components/Insights/BiodiversitySpecies';
-import { withTranslation } from 'react-i18next';
-import { Semibold } from '../../../components/Typography';
-
-class Biodiversity extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- render() {
- const { t } = this.props;
- let biodiversityData = this.props.biodiversityData['data'] || [];
- return (
-
-
{t('INSIGHTS.BIODIVERSITY.INFO')} }
- />
-
- {t('INSIGHTS.BIODIVERSITY.HEADER')}
-
-
- {biodiversityData.map((curr, index) => {
- return (
-
- );
- })}
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- biodiversityData: biodiversitySelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Biodiversity));
diff --git a/packages/webapp/src/containers/Insights/Biodiversity/index.jsx b/packages/webapp/src/containers/Insights/Biodiversity/index.jsx
new file mode 100644
index 0000000000..3a1958f905
--- /dev/null
+++ b/packages/webapp/src/containers/Insights/Biodiversity/index.jsx
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import React, { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import insightStyles from '../styles.module.scss';
+import PageTitle from '../../../components/PageTitle';
+import {
+ biodiversityErrorSelector,
+ biodiversityLoadingSelector,
+ biodiversitySelector,
+} from '../selectors';
+import BiodiversitySpecies from '../../../components/Insights/BiodiversitySpecies';
+import { useTranslation } from 'react-i18next';
+import { Semibold } from '../../../components/Typography';
+import { getBiodiversityData } from '../actions';
+import BiodiversityLoadingModal from '../../../components/Modals/BiodiversityLoadingModal/BiodiversityLoadingModal';
+import history from '../../../history';
+
+const Biodiversity = () => {
+ const biodiversityData = useSelector(biodiversitySelector);
+ const biodiversityLoading = useSelector(biodiversityLoadingSelector);
+ const biodiversityError = useSelector(biodiversityErrorSelector);
+
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const getMinutesSinceTime = (time) => {
+ return Math.round((Date.now() - time) / (1000 * 60));
+ };
+
+ useEffect(() => {
+ if (!(biodiversityData.timeFetched && getMinutesSinceTime(biodiversityData.timeFetched) < 30)) {
+ dispatch(getBiodiversityData());
+ }
+ dispatch(getBiodiversityData());
+ }, []);
+
+ const biodiversityInfoItems = biodiversityData.data.map((current, index) => {
+ return (
+
+ );
+ });
+
+ const dismissModal = () => {
+ history.push('/Insights');
+ };
+
+ return (
+
+
{t('INSIGHTS.BIODIVERSITY.INFO')} }
+ />
+
+ {t('INSIGHTS.BIODIVERSITY.HEADER')}
+
+
+ {biodiversityLoading || biodiversityError ? (
+
+ ) : (
+ biodiversityInfoItems
+ )}
+
+ );
+};
+
+export default Biodiversity;
diff --git a/packages/webapp/src/containers/Insights/Erosion/index.js b/packages/webapp/src/containers/Insights/Erosion/index.js
deleted file mode 100644
index f1f0f7db64..0000000000
--- a/packages/webapp/src/containers/Insights/Erosion/index.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import insightStyles from '../styles.module.scss';
-import PageTitle from '../../../components/PageTitle';
-class Erosion extends Component {
- constructor(props) {
- super(props);
- this.state = {};
- }
-
- render() {
- return (
-
- );
- }
-}
-
-const infoBoxBody = (
-
- Reducing erosion is great way to keep your soil healthy for future generations. You can find out
- how to reduce soil erosion here: www.usefullink.com
-
-);
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapDispatchToProps)(Erosion);
diff --git a/packages/webapp/src/containers/Insights/Erosion/index.jsx b/packages/webapp/src/containers/Insights/Erosion/index.jsx
new file mode 100644
index 0000000000..a5dd8a32ea
--- /dev/null
+++ b/packages/webapp/src/containers/Insights/Erosion/index.jsx
@@ -0,0 +1,41 @@
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import insightStyles from '../styles.module.scss';
+import PageTitle from '../../../components/PageTitle';
+
+class Erosion extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+const infoBoxBody = (
+
+ Reducing erosion is great way to keep your soil healthy for future generations. You can find out
+ how to reduce soil erosion here: www.usefullink.com
+
+);
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapDispatchToProps)(Erosion);
diff --git a/packages/webapp/src/containers/Insights/LabourHappiness/index.js b/packages/webapp/src/containers/Insights/LabourHappiness/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Insights/LabourHappiness/index.js
rename to packages/webapp/src/containers/Insights/LabourHappiness/index.jsx
diff --git a/packages/webapp/src/containers/Insights/NitrogenBalance/index.js b/packages/webapp/src/containers/Insights/NitrogenBalance/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Insights/NitrogenBalance/index.js
rename to packages/webapp/src/containers/Insights/NitrogenBalance/index.jsx
diff --git a/packages/webapp/src/containers/Insights/PeopleFed/index.js b/packages/webapp/src/containers/Insights/PeopleFed/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Insights/PeopleFed/index.js
rename to packages/webapp/src/containers/Insights/PeopleFed/index.jsx
diff --git a/packages/webapp/src/containers/Insights/Prices/index.js b/packages/webapp/src/containers/Insights/Prices/index.js
deleted file mode 100644
index f58ecccafd..0000000000
--- a/packages/webapp/src/containers/Insights/Prices/index.js
+++ /dev/null
@@ -1,166 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import insightStyles from '../styles.module.scss';
-import PageTitle from '../../../components/PageTitle';
-import { pricesDistanceSelector, pricesSelector } from '../selectors';
-import PriceCropContainer from '../../../components/Insights/PriceCropContainer';
-import { getPricesWithDistanceData, setPricesDistance } from '../actions';
-import PriceDistanceComponent from '../../../components/Insights/PriceDistanceComponent';
-import styles from './styles.module.scss';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { Text } from '../../../components/Typography';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-
-const MILE_TO_KILOMETER = 1.609;
-
-class Prices extends Component {
- constructor(props) {
- super(props);
- this.state = {
- currencySymbol: grabCurrencySymbol(),
- open: false,
- };
- this.handleChange = this.handleChange.bind(this);
- this.handleOpenCollapse = this.handleOpenCollapse.bind(this);
- }
-
- handleChange(distance) {
- this.props.dispatch(setPricesDistance(distance));
- }
-
- handleOpenCollapse() {
- this.setState({ open: !this.state.open });
- }
-
- componentDidMount() {
- if (this.props.pricesDistance && this.props.farm.grid_points) {
- this.props.dispatch(
- getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
- );
- }
- }
-
- componentDidUpdate(prevProps) {
- if (prevProps.pricesDistance !== this.props.pricesDistance && this.props.farm.grid_points) {
- this.props.dispatch(
- getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
- );
- }
- // TODO need rewrite
- if (
- this.props.farm?.units?.measurement === 'imperial' &&
- Number.isInteger(this.props.pricesDistance)
- ) {
- this.handleChange(5 * MILE_TO_KILOMETER);
- } else if (
- this.props.farm?.units?.measurement === 'metric' &&
- !Number.isInteger(this.props.pricesDistance)
- ) {
- this.handleChange(5);
- }
- }
-
- render() {
- const isImperial = this.props.farm && this.props.farm.units?.measurement === 'imperial';
- const distances = isImperial ? [5, 10, 20, 35] : [5, 10, 25, 50];
- const distanceToDisplay = isImperial
- ? this.props.pricesDistance / MILE_TO_KILOMETER
- : this.props.pricesDistance;
- const unit = isImperial ? 'mi' : 'km';
- const { currencySymbol } = this.state;
- const { pricesData } = this.props;
- const { data: cropsWithPriceInfo } = pricesData;
- const { t } = this.props;
- return (
-
-
{t('INSIGHTS.PRICES.INFO')} }
- />
- {this.props.pricesDistance && (
-
-
-
- {t('INSIGHTS.PRICES.NEARBY_FARMS', {
- count: this.props.pricesData['amountOfFarms'],
- })}
-
-
-
-
- {t('INSIGHTS.PRICES.SALES_FROM_DISTANCE_AWAY', {
- distance: distanceToDisplay,
- unit,
- })}
-
-
-
-
- {this.state.open && (
-
- {distances.map((distance, index) => {
- if (distanceToDisplay === distance) {
- return (
-
- {distance} {unit}
-
- );
- } else {
- return (
- {
- this.handleChange(isImperial ? distance * MILE_TO_KILOMETER : distance);
- }}
- className={'active ' + styles.distanceButton}
- key={'button-' + index}
- >
- {distance} {unit}
-
- );
- }
- })}
-
- )}
-
-
- )}
- {!this.props.farm.grid_points && {t('INSIGHTS.PRICES.NO_ADDRESS')}
}
- {cropsWithPriceInfo.map((cropInfo, index) => {
- const cropName = Object.keys(cropInfo)[0];
- const pricePoints = cropInfo[cropName]; // each month is a price point
- return (
-
- );
- })}
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- pricesData: pricesSelector(state),
- pricesDistance: pricesDistanceSelector(state),
- farm: userFarmSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Prices));
diff --git a/packages/webapp/src/containers/Insights/Prices/index.jsx b/packages/webapp/src/containers/Insights/Prices/index.jsx
new file mode 100644
index 0000000000..865924ee08
--- /dev/null
+++ b/packages/webapp/src/containers/Insights/Prices/index.jsx
@@ -0,0 +1,158 @@
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import insightStyles from '../styles.module.scss';
+import PageTitle from '../../../components/PageTitle';
+import { pricesDistanceSelector, pricesSelector } from '../selectors';
+import { getPricesWithDistanceData, setPricesDistance } from '../actions';
+import PriceDistanceComponent from '../../../components/Insights/PriceDistanceComponent';
+import styles from './styles.module.scss';
+import { userFarmSelector } from '../../userFarmSlice';
+import { withTranslation } from 'react-i18next';
+import { Text } from '../../../components/Typography';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+import { PriceCropCharts } from '../../../components/Insights/PriceCropCharts/PriceCropCharts';
+
+const MILE_TO_KILOMETER = 1.609;
+
+class Prices extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ currencySymbol: grabCurrencySymbol(),
+ open: false,
+ };
+ this.handleChange = this.handleChange.bind(this);
+ this.handleOpenCollapse = this.handleOpenCollapse.bind(this);
+ }
+
+ handleChange(distance) {
+ this.props.dispatch(setPricesDistance(distance));
+ }
+
+ handleOpenCollapse() {
+ this.setState({ open: !this.state.open });
+ }
+
+ componentDidMount() {
+ if (this.props.pricesDistance && this.props.farm.grid_points) {
+ this.props.dispatch(
+ getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
+ );
+ }
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.pricesDistance !== this.props.pricesDistance && this.props.farm.grid_points) {
+ this.props.dispatch(
+ getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
+ );
+ }
+ // TODO need rewrite
+ if (
+ this.props.farm?.units?.measurement === 'imperial' &&
+ Number.isInteger(this.props.pricesDistance)
+ ) {
+ this.handleChange(5 * MILE_TO_KILOMETER);
+ } else if (
+ this.props.farm?.units?.measurement === 'metric' &&
+ !Number.isInteger(this.props.pricesDistance)
+ ) {
+ this.handleChange(5);
+ }
+ }
+
+ render() {
+ const isImperial = this.props.farm && this.props.farm.units?.measurement === 'imperial';
+ const distances = isImperial ? [5, 10, 20, 35] : [5, 10, 25, 50];
+ const distanceToDisplay = isImperial
+ ? this.props.pricesDistance / MILE_TO_KILOMETER
+ : this.props.pricesDistance;
+ const unit = isImperial ? 'mi' : 'km';
+ const { currencySymbol } = this.state;
+ const { pricesData } = this.props;
+ const { data: cropsWithPriceInfo } = pricesData;
+ const { t } = this.props;
+ return (
+
+
{t('INSIGHTS.PRICES.INFO')} }
+ />
+ {this.props.pricesDistance && (
+
+
+
+ {t('INSIGHTS.PRICES.NEARBY_FARMS', {
+ count: this.props.pricesData['amountOfFarms'],
+ })}
+
+
+
+
+ {t('INSIGHTS.PRICES.SALES_FROM_DISTANCE_AWAY', {
+ distance: distanceToDisplay,
+ unit,
+ })}
+
+
+
+
+ {this.state.open && (
+
+ {distances.map((distance, index) => {
+ if (distanceToDisplay === distance) {
+ return (
+
+ {distance} {unit}
+
+ );
+ } else {
+ return (
+ {
+ this.handleChange(isImperial ? distance * MILE_TO_KILOMETER : distance);
+ }}
+ className={'active ' + styles.distanceButton}
+ key={'button-' + index}
+ >
+ {distance} {unit}
+
+ );
+ }
+ })}
+
+ )}
+
+
+ )}
+ {!this.props.farm.grid_points && {t('INSIGHTS.PRICES.NO_ADDRESS')}
}
+
+
+ );
+ }
+}
+
+const mapStateToProps = (state) => {
+ return {
+ pricesData: pricesSelector(state),
+ pricesDistance: pricesDistanceSelector(state),
+ farm: userFarmSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Prices));
diff --git a/packages/webapp/src/containers/Insights/SoilOM/index.js b/packages/webapp/src/containers/Insights/SoilOM/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Insights/SoilOM/index.js
rename to packages/webapp/src/containers/Insights/SoilOM/index.jsx
diff --git a/packages/webapp/src/containers/Insights/WaterBalance/index.js b/packages/webapp/src/containers/Insights/WaterBalance/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Insights/WaterBalance/index.js
rename to packages/webapp/src/containers/Insights/WaterBalance/index.jsx
diff --git a/packages/webapp/src/containers/Insights/actions.js b/packages/webapp/src/containers/Insights/actions.js
index 73bd41b937..6549a527c8 100644
--- a/packages/webapp/src/containers/Insights/actions.js
+++ b/packages/webapp/src/containers/Insights/actions.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (actions.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,6 +37,10 @@ import {
GET_FREQUENCY_WATER_BALANCE,
SET_FREQUENCY_WATER_BALANCE,
CREATE_FREQUENCY_WATER_BALANCE,
+ GET_BIODIVERSITY_LOADING,
+ SET_BIODIVERSITY_LOADING,
+ GET_BIODIVERSITY_ERROR,
+ SET_BIODIVERSITY_ERROR,
} from './constants';
export const getCropsSoldNutrition = () => {
@@ -87,7 +91,37 @@ export const getBiodiversityData = () => {
export const setBiodiversityData = (biodiversityData) => {
return {
type: SET_BIODIVERSITY_DATA,
- biodiversityData,
+ biodiversityData: {
+ ...biodiversityData,
+ timeFetched: Date.now(),
+ },
+ };
+};
+
+export const getBiodiversityLoading = () => {
+ return {
+ type: GET_BIODIVERSITY_LOADING,
+ };
+};
+
+export const setBiodiversityLoading = (biodiversityLoading) => {
+ return {
+ type: SET_BIODIVERSITY_LOADING,
+ biodiversityLoading,
+ };
+};
+
+export const getBiodiversityError = () => {
+ return {
+ type: GET_BIODIVERSITY_ERROR,
+ };
+};
+
+export const setBiodiversityError = (biodiversityError, timeFailed) => {
+ return {
+ type: SET_BIODIVERSITY_ERROR,
+ biodiversityError,
+ timeFailed,
};
};
diff --git a/packages/webapp/src/containers/Insights/constants.js b/packages/webapp/src/containers/Insights/constants.js
index bce771cbfd..6c19cfd151 100644
--- a/packages/webapp/src/containers/Insights/constants.js
+++ b/packages/webapp/src/containers/Insights/constants.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (constants.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,10 @@ export const SET_LABOUR_HAPPINESS_DATA = 'SET_LABOUR_HAPPINESS_DATA';
export const GET_BIODIVERSITY_DATA = 'GET_BIODIVERSITY_DATA';
export const SET_BIODIVERSITY_DATA = 'SET_BIODIVERSITY_DATA';
+export const GET_BIODIVERSITY_LOADING = 'GET_BIODIVERSITY_LOADING';
+export const SET_BIODIVERSITY_LOADING = 'SET_BIODIVERSITY_LOADING';
+export const GET_BIODIVERSITY_ERROR = 'GET_BIODIVERSITY_ERROR';
+export const SET_BIODIVERSITY_ERROR = 'SET_BIODIVERSITY_ERROR';
export const GET_PRICES_DATA = 'GET_PRICES_DATA';
export const GET_PRICES_WITH_DISTANCE_DATA = 'GET_PRICES_WITH_DISTANCE_DATA';
diff --git a/packages/webapp/src/containers/Insights/index.js b/packages/webapp/src/containers/Insights/index.js
deleted file mode 100644
index 3d8f3bceb0..0000000000
--- a/packages/webapp/src/containers/Insights/index.js
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import styles from './styles.module.scss';
-import history from '../../history';
-// images
-import people_fed from '../../assets/images/insights/people_fed.svg';
-import soil_om from '../../assets/images/insights/soil_om.svg';
-import labour_happiness from '../../assets/images/insights/labour_happiness.svg';
-import biodiversity from '../../assets/images/insights/biodiversity.svg';
-import prices from '../../assets/images/insights/prices.svg';
-import water_balance from '../../assets/images/insights/water_balance.svg';
-// import erosion from '../../assets/images/insights/erosion.svg';
-import nitrogen_balance from '../../assets/images/insights/nitrogen_balance.svg';
-//
-// actions
-import {
- getCropsSoldNutrition,
- getLabourHappinessData,
- getSoilOMData,
- getBiodiversityData,
- getWaterBalanceData,
- getNitrogenBalanceData,
- getFrequencyNitrogenBalance,
- getPricesWithDistanceData,
- getWaterBalanceSchedule,
-} from './actions';
-// selectors
-import {
- cropsNutritionSelector,
- labourHappinessSelector,
- soilOMSelector,
- biodiversitySelector,
- pricesSelector,
- waterBalanceSelector,
- nitrogenBalanceSelector,
- nitrogenFrequencySelector,
- pricesDistanceSelector,
- waterBalanceScheduleSelector,
-} from './selectors';
-import InfoBoxComponent from '../../components/InfoBoxComponent';
-import { BsChevronRight } from 'react-icons/all';
-import { userFarmSelector } from '../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { Title, Semibold, Text } from '../../components/Typography';
-const MILLIMETER_TO_INCH = 0.0393701;
-const KILOGRAM_TO_POUND = 2.20462;
-
-class Insights extends Component {
- constructor(props) {
- super(props);
- this.state = {
- items: [
- // {
- // label: props.t('INSIGHTS.PEOPLE_FED.TITLE'),
- // image: people_fed,
- // route: 'PeopleFed',
- // data_point: 'PeopleFed',
- // },
- {
- label: props.t('INSIGHTS.SOIL_OM.TITLE'),
- image: soil_om,
- route: 'SoilOM',
- data_point: 'SoilOM',
- },
- {
- label: props.t('INSIGHTS.LABOUR_HAPPINESS.TITLE'),
- image: labour_happiness,
- route: 'LabourHappiness',
- data_point: 'LabourHappiness',
- },
- {
- label: props.t('INSIGHTS.BIODIVERSITY.TITLE'),
- image: biodiversity,
- route: 'Biodiversity',
- data_point: 'Biodiversity',
- },
- {
- label: props.t('INSIGHTS.PRICES.TITLE'),
- image: prices,
- route: 'Prices',
- data_point: 'Prices',
- },
- // {
- // label: props.t('INSIGHTS.WATER_BALANCE.TITLE'),
- // image: water_balance,
- // route: 'WaterBalance',
- // data_point: 'WaterBalance',
- // },
- // {
- // label: props.t('INSIGHTS.NITROGEN_BALANCE.TITLE'),
- // image: nitrogen_balance,
- // route: 'NitrogenBalance',
- // data_point: 'NitrogenBalance',
- // },
- //{label: "Erosion", image: erosion, route: "Erosion", data_point: "Erosion"},
- ],
- };
-
- this.handleClick = this.handleClick.bind(this);
- this.renderItem = this.renderItem.bind(this);
- this.generateView = this.generateView.bind(this);
- }
-
- renderItem(item, index, currentData) {
- return (
-
-
this.handleClick(item.route)}
- >
-
-
-
- {item.label}
- {`${this.props.t('INSIGHTS.CURRENT')}: ${currentData ? currentData : 0}`}
-
-
-
-
-
-
- );
- }
-
- handleClick(route) {
- history.push('/Insights/' + route);
- }
-
- generateView(
- cropNutritionalData,
- soilOMData,
- labourHappinessData,
- biodiversityData,
- pricesData,
- waterBalanceData,
- nitrogenBalanceData,
- ) {
- const insightData = {};
- const isImperial = this.props.farm?.units?.measurement === 'imperial';
- insightData['PeopleFed'] = this.props.t('INSIGHTS.PEOPLE_FED.MEAL_COUNT', {
- count: cropNutritionalData.preview,
- });
- insightData['SoilOM'] = (soilOMData.preview || '0') + '%';
- insightData['LabourHappiness'] = labourHappinessData.preview
- ? labourHappinessData.preview + '/5'
- : this.props.t('INSIGHTS.UNAVAILABLE');
- insightData['Biodiversity'] = this.props.t('INSIGHTS.BIODIVERSITY.SPECIES_COUNT', {
- count: biodiversityData.preview,
- });
- insightData['Prices'] = pricesData.preview
- ? this.props.t('INSIGHTS.PRICES.PERCENT_OF_MARKET', { percentage: pricesData.preview })
- : this.props.t('INSIGHTS.UNAVAILABLE');
- insightData['WaterBalance'] = isImperial
- ? Number(waterBalanceData.preview) * MILLIMETER_TO_INCH + ' in'
- : waterBalanceData.preview + ' mm';
- insightData['NitrogenBalance'] = isImperial
- ? Number(nitrogenBalanceData.preview) * KILOGRAM_TO_POUND + ' lbs'
- : nitrogenBalanceData.preview + ' kg';
- return insightData;
- }
-
- componentDidMount() {
- //TODO fetch userFarm
- // this.props.dispatch(getCropsSoldNutrition());
- this.props.dispatch(getSoilOMData());
- this.props.dispatch(getLabourHappinessData());
- this.props.dispatch(getBiodiversityData());
- this.props.dispatch(
- getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
- );
- // this.props.dispatch(getWaterBalanceData());
- // this.props.dispatch(getWaterBalanceSchedule());
- // this.props.dispatch(getNitrogenBalanceData());
- // this.props.dispatch(getFrequencyNitrogenBalance());
- }
-
- render() {
- // @TODO currently just throwing in data from the props into generateView, should refactor the code to handle it better
- const {
- cropNutritionData,
- soilOMData,
- labourHappinessData,
- biodiversityData,
- pricesData,
- waterBalanceData,
- nitrogenBalanceData,
- } = this.props;
- let insightData = this.generateView(
- cropNutritionData,
- soilOMData,
- labourHappinessData,
- biodiversityData,
- pricesData,
- waterBalanceData,
- nitrogenBalanceData,
- );
- const { t } = this.props;
- return (
-
-
-
-
{t('INSIGHTS.TITLE')}
-
-
- {t('INSIGHTS.INFO')}
}
- />
-
-
-
-
-
- {this.state.items.map((item, index) => {
- return this.renderItem(item, index, insightData[item.data_point]);
- })}
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- farm: userFarmSelector(state),
- cropNutritionData: cropsNutritionSelector(state),
- soilOMData: soilOMSelector(state),
- labourHappinessData: labourHappinessSelector(state),
- biodiversityData: biodiversitySelector(state),
- pricesData: pricesSelector(state),
- waterBalanceData: waterBalanceSelector(state),
- waterBalanceSchedule: waterBalanceScheduleSelector(state),
- nitrogenBalanceData: nitrogenBalanceSelector(state),
- nitrogenFrequencyData: nitrogenFrequencySelector(state),
- pricesDistance: pricesDistanceSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Insights));
diff --git a/packages/webapp/src/containers/Insights/index.jsx b/packages/webapp/src/containers/Insights/index.jsx
new file mode 100644
index 0000000000..27e4651b6c
--- /dev/null
+++ b/packages/webapp/src/containers/Insights/index.jsx
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { useEffect, Component, useMemo } from 'react';
+import { connect, useDispatch, useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import styles from './styles.module.scss';
+import history from '../../history';
+// images
+import soil_om from '../../assets/images/insights/soil_om.svg';
+import labour_happiness from '../../assets/images/insights/labour_happiness.svg';
+import biodiversity from '../../assets/images/insights/biodiversity.svg';
+import prices from '../../assets/images/insights/prices.svg';
+// import erosion from '../../assets/images/insights/erosion.svg';
+//
+// actions
+import {
+ getBiodiversityData,
+ getLabourHappinessData,
+ getPricesWithDistanceData,
+ getSoilOMData,
+} from './actions';
+// selectors
+import {
+ biodiversityErrorSelector,
+ biodiversityLoadingSelector,
+ biodiversitySelector,
+ cropsNutritionSelector,
+ labourHappinessSelector,
+ nitrogenBalanceSelector,
+ nitrogenFrequencySelector,
+ pricesDistanceSelector,
+ pricesSelector,
+ soilOMSelector,
+ waterBalanceScheduleSelector,
+ waterBalanceSelector,
+} from './selectors';
+import InfoBoxComponent from '../../components/InfoBoxComponent';
+import { BsChevronRight } from 'react-icons/all';
+import { userFarmSelector } from '../userFarmSlice';
+import { Semibold, Text, Title } from '../../components/Typography';
+
+const MILLIMETER_TO_INCH = 0.0393701;
+const KILOGRAM_TO_POUND = 2.20462;
+
+const Insights = () => {
+ const farm = useSelector(userFarmSelector);
+ const pricesDistance = useSelector(pricesDistanceSelector);
+ const soilOMData = useSelector(soilOMSelector);
+ const labourHappinessData = useSelector(labourHappinessSelector);
+ const biodiversityData = useSelector(biodiversitySelector);
+ const pricesData = useSelector(pricesSelector);
+ const biodiversityLoading = useSelector(biodiversityLoadingSelector);
+ const biodiversityError = useSelector(biodiversityErrorSelector);
+
+ const dispatch = useDispatch();
+ const { t } = useTranslation();
+
+ const items = [
+ {
+ label: t('INSIGHTS.SOIL_OM.TITLE'),
+ image: soil_om,
+ route: 'SoilOM',
+ data_point: 'SoilOM',
+ },
+ {
+ label: t('INSIGHTS.LABOUR_HAPPINESS.TITLE'),
+ image: labour_happiness,
+ route: 'LabourHappiness',
+ data_point: 'LabourHappiness',
+ },
+ {
+ label: t('INSIGHTS.BIODIVERSITY.TITLE'),
+ image: biodiversity,
+ route: 'Biodiversity',
+ data_point: 'Biodiversity',
+ },
+ {
+ label: t('INSIGHTS.PRICES.TITLE'),
+ image: prices,
+ route: 'Prices',
+ data_point: 'Prices',
+ },
+ ];
+
+ useEffect(() => {
+ dispatch(getSoilOMData());
+ dispatch(getLabourHappinessData());
+ dispatch(getPricesWithDistanceData(farm.grid_points, pricesDistance));
+ if (
+ !(
+ biodiversityData.timeFetched &&
+ (Date.now() - biodiversityData.timeFetched) / (1000 * 60) < 30
+ )
+ ) {
+ dispatch(getBiodiversityData());
+ }
+ }, []);
+
+ const handleClick = (route) => {
+ history.push(`/Insights/${route}`);
+ };
+
+ const renderItem = (item, index, currentData) => (
+
+
handleClick(item.route)}
+ >
+
+
+ {item.label}
+ {`${t('INSIGHTS.CURRENT')}: ${currentData ?? 0}`}
+
+
+
+
+
+ );
+
+ const insightData = useMemo(() => {
+ const insightData = {};
+ insightData['SoilOM'] = (soilOMData.preview ?? '0') + '%';
+ insightData['LabourHappiness'] = labourHappinessData.preview
+ ? labourHappinessData.preview + '/5'
+ : t('INSIGHTS.UNAVAILABLE');
+ if (biodiversityLoading) {
+ insightData['Biodiversity'] = t('INSIGHTS.BIODIVERSITY.LOADING.PREVIEW');
+ } else if (biodiversityError) {
+ insightData['Biodiversity'] = t('INSIGHTS.BIODIVERSITY.ERROR.PREVIEW');
+ } else {
+ insightData['Biodiversity'] = t('INSIGHTS.BIODIVERSITY.SPECIES_COUNT', {
+ count: biodiversityData.preview,
+ });
+ }
+ insightData['prices'] = pricesData.preview
+ ? t('INSIGHTS.PRICES.PERCENT_OF_MARKET', { percentage: pricesData.preview })
+ : t('INSIGHTS.UNAVAILABLE');
+ return insightData;
+ }, [soilOMData, labourHappinessData, biodiversityData, pricesData]);
+
+ const renderedItems = useMemo(() => {
+ return (
+ insightData &&
+ items.map((item, index) => {
+ return renderItem(item, index, insightData[item.data_point]);
+ })
+ );
+ }, [insightData]);
+
+ return (
+
+
+
+
{t('INSIGHTS.TITLE')}
+
+
+ {t('INSIGHTS.INFO')}
}
+ />
+
+
+
+
+ {renderedItems}
+
+ );
+};
+
+// class Insight extends Component {
+// constructor(props) {
+// super(props);
+// this.state = {
+// items: [
+// // {
+// // label: props.t('INSIGHTS.PEOPLE_FED.TITLE'),
+// // image: people_fed,
+// // route: 'PeopleFed',
+// // data_point: 'PeopleFed',
+// // },
+// {
+// label: props.t('INSIGHTS.SOIL_OM.TITLE'),
+// image: soil_om,
+// route: 'SoilOM',
+// data_point: 'SoilOM',
+// },
+// {
+// label: props.t('INSIGHTS.LABOUR_HAPPINESS.TITLE'),
+// image: labour_happiness,
+// route: 'LabourHappiness',
+// data_point: 'LabourHappiness',
+// },
+// {
+// label: props.t('INSIGHTS.BIODIVERSITY.TITLE'),
+// image: biodiversity,
+// route: 'Biodiversity',
+// data_point: 'Biodiversity',
+// },
+// {
+// label: props.t('INSIGHTS.PRICES.TITLE'),
+// image: prices,
+// route: 'Prices',
+// data_point: 'Prices',
+// },
+// // {
+// // label: props.t('INSIGHTS.WATER_BALANCE.TITLE'),
+// // image: water_balance,
+// // route: 'WaterBalance',
+// // data_point: 'WaterBalance',
+// // },
+// // {
+// // label: props.t('INSIGHTS.NITROGEN_BALANCE.TITLE'),
+// // image: nitrogen_balance,
+// // route: 'NitrogenBalance',
+// // data_point: 'NitrogenBalance',
+// // },
+// //{label: "Erosion", image: erosion, route: "Erosion", data_point: "Erosion"},
+// ],
+// };
+//
+// this.handleClick = this.handleClick.bind(this);
+// this.renderItem = this.renderItem.bind(this);
+// this.generateView = this.generateView.bind(this);
+// }
+//
+// renderItem(item, index, currentData) {
+// return (
+//
+//
this.handleClick(item.route)}
+// >
+//
+//
+//
+// {item.label}
+// {`${this.props.t('INSIGHTS.CURRENT')}: ${currentData ? currentData : 0}`}
+//
+//
+//
+//
+//
+//
+// );
+// }
+//
+// handleClick(route) {
+// history.push('/Insights/' + route);
+// }
+//
+// generateView(
+// cropNutritionalData,
+// soilOMData,
+// labourHappinessData,
+// biodiversityData,
+// pricesData,
+// waterBalanceData,
+// nitrogenBalanceData,
+// ) {
+// const insightData = {};
+// const isImperial = this.props.farm?.units?.measurement === 'imperial';
+// insightData['PeopleFed'] = this.props.t('INSIGHTS.PEOPLE_FED.MEAL_COUNT', {
+// count: cropNutritionalData.preview,
+// });
+// insightData['SoilOM'] = (soilOMData.preview || '0') + '%';
+// insightData['LabourHappiness'] = labourHappinessData.preview
+// ? labourHappinessData.preview + '/5'
+// : this.props.t('INSIGHTS.UNAVAILABLE');
+// insightData['Biodiversity'] = this.props.t('INSIGHTS.BIODIVERSITY.SPECIES_COUNT', {
+// count: biodiversityData.preview,
+// });
+// insightData['Prices'] = pricesData.preview
+// ? this.props.t('INSIGHTS.PRICES.PERCENT_OF_MARKET', { percentage: pricesData.preview })
+// : this.props.t('INSIGHTS.UNAVAILABLE');
+// insightData['WaterBalance'] = isImperial
+// ? Number(waterBalanceData.preview) * MILLIMETER_TO_INCH + ' in'
+// : waterBalanceData.preview + ' mm';
+// insightData['NitrogenBalance'] = isImperial
+// ? Number(nitrogenBalanceData.preview) * KILOGRAM_TO_POUND + ' lbs'
+// : nitrogenBalanceData.preview + ' kg';
+// return insightData;
+// }
+//
+// componentDidMount() {
+// //TODO fetch userFarm
+// // this.props.dispatch(getCropsSoldNutrition());
+// this.props.dispatch(getSoilOMData());
+// this.props.dispatch(getLabourHappinessData());
+// this.props.dispatch(getBiodiversityData());
+// this.props.dispatch(
+// getPricesWithDistanceData(this.props.farm.grid_points, this.props.pricesDistance),
+// );
+// // this.props.dispatch(getWaterBalanceData());
+// // this.props.dispatch(getWaterBalanceSchedule());
+// // this.props.dispatch(getNitrogenBalanceData());
+// // this.props.dispatch(getFrequencyNitrogenBalance());
+// }
+//
+// render() {
+// // @TODO currently just throwing in data from the props into generateView, should refactor the code to handle it better
+// const {
+// cropNutritionData,
+// soilOMData,
+// labourHappinessData,
+// biodiversityData,
+// pricesData,
+// waterBalanceData,
+// nitrogenBalanceData,
+// } = this.props;
+// let insightData = this.generateView(
+// cropNutritionData,
+// soilOMData,
+// labourHappinessData,
+// biodiversityData,
+// pricesData,
+// waterBalanceData,
+// nitrogenBalanceData,
+// );
+// const { t } = this.props;
+// return (
+//
+//
+//
+//
{t('INSIGHTS.TITLE')}
+//
+//
+// {t('INSIGHTS.INFO')}
}
+// />
+//
+//
+//
+//
+//
+// {this.state.items.map((item, index) => {
+// return this.renderItem(item, index, insightData[item.data_point]);
+// })}
+//
+// );
+// }
+// }
+//
+// const mapStateToProps = (state) => {
+// return {
+// farm: userFarmSelector(state),
+// cropNutritionData: cropsNutritionSelector(state),
+// soilOMData: soilOMSelector(state),
+// labourHappinessData: labourHappinessSelector(state),
+// biodiversityData: biodiversitySelector(state),
+// pricesData: pricesSelector(state),
+// waterBalanceData: waterBalanceSelector(state),
+// waterBalanceSchedule: waterBalanceScheduleSelector(state),
+// nitrogenBalanceData: nitrogenBalanceSelector(state),
+// nitrogenFrequencyData: nitrogenFrequencySelector(state),
+// pricesDistance: pricesDistanceSelector(state),
+// };
+// };
+//
+// const mapDispatchToProps = (dispatch) => {
+// return {
+// dispatch,
+// };
+// };
+
+// export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Insights));
+export default Insights;
diff --git a/packages/webapp/src/containers/Insights/reducer.js b/packages/webapp/src/containers/Insights/reducer.js
index ee311e530c..ca3d1efc82 100644
--- a/packages/webapp/src/containers/Insights/reducer.js
+++ b/packages/webapp/src/containers/Insights/reducer.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (reducer.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,12 +18,14 @@ import {
SET_SOLD_OM_DATA,
SET_LABOUR_HAPPINESS_DATA,
SET_BIODIVERSITY_DATA,
+ SET_BIODIVERSITY_LOADING,
SET_PRICES_DATA,
SET_PRICES_DISTANCE,
SET_WATER_BALANCE_DATA,
SET_NITROGEN_BALANCE_DATA,
SET_FREQUENCY_NITROGEN_BALANCE,
SET_FREQUENCY_WATER_BALANCE,
+ SET_BIODIVERSITY_ERROR,
} from './constants';
const initialState = {
@@ -31,6 +33,8 @@ const initialState = {
soilOMData: { preview: 0, data: [] },
labourHappinessData: { preview: 0, data: [] },
biodiversityData: { preview: 0, data: [] },
+ biodiversityLoading: false,
+ biodiversityError: false,
pricesData: { preview: 0, amountOfFarms: 0, data: [] },
waterBalanceData: { preview: 0, data: [] },
waterBalanceSchedule: {},
@@ -61,30 +65,50 @@ function insightReducer(state = initialState, action) {
biodiversityData: action.biodiversityData,
});
+ case SET_BIODIVERSITY_LOADING:
+ return Object.assign({}, state, {
+ biodiversityLoading: action.biodiversityLoading,
+ });
+
+ case SET_BIODIVERSITY_ERROR:
+ return Object.assign({}, state, {
+ biodiversityError: action.biodiversityError,
+ biodiversityData: {
+ ...state.biodiversityData,
+ timeFetched: action.timeFailed,
+ },
+ });
+
case SET_PRICES_DATA:
return Object.assign({}, state, {
pricesData: action.pricesData,
});
+
case SET_WATER_BALANCE_DATA:
return Object.assign({}, state, {
waterBalanceData: action.waterBalanceData,
});
+
case SET_FREQUENCY_WATER_BALANCE:
return Object.assign({}, state, {
waterBalanceSchedule: action.waterBalanceSchedule,
});
+
case SET_NITROGEN_BALANCE_DATA:
return Object.assign({}, state, {
nitrogenBalanceData: action.nitrogenBalanceData,
});
+
case SET_FREQUENCY_NITROGEN_BALANCE:
return Object.assign({}, state, {
nitrogenFrequencyData: action.data,
});
+
case SET_PRICES_DISTANCE:
return Object.assign({}, state, {
pricesDistance: action.distance,
});
+
default:
return state;
}
diff --git a/packages/webapp/src/containers/Insights/saga.js b/packages/webapp/src/containers/Insights/saga.js
index faa558db0a..81f493d5e8 100644
--- a/packages/webapp/src/containers/Insights/saga.js
+++ b/packages/webapp/src/containers/Insights/saga.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (saga.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,6 +17,8 @@ import apiConfig from '../../apiConfig';
import { call, put, select, takeLatest, takeLeading } from 'redux-saga/effects';
import {
setBiodiversityData,
+ setBiodiversityError,
+ setBiodiversityLoading,
setCropsSoldNutritionInState,
setFrequencyNitrogenBalance,
setLabourHappinessData,
@@ -43,6 +45,7 @@ import {
} from './constants';
import { loginSelector } from '../userFarmSlice';
import { axios, getHeader } from '../saga';
+import { biodiversitySelector } from './selectors';
export function* getCropsSoldNutrition() {
const { insightUrl } = apiConfig;
@@ -91,16 +94,28 @@ export function* getLabourHappinessData() {
}
export function* getBiodiversityData() {
+ console.log('Getting biodiversity data');
+ yield put(setBiodiversityLoading(true));
+ yield put(setBiodiversityError(false));
const { insightUrl } = apiConfig;
let { user_id, farm_id } = yield select(loginSelector);
- const header = getHeader(user_id, farm_id);
+ const defaultHeader = getHeader(user_id, farm_id);
+ const header = {
+ ...defaultHeader,
+ headers: { Connection: 'Keep-Alive', 'Keep-Alive': 'timeout=60', ...defaultHeader.headers },
+ };
try {
const result = yield call(axios.get, insightUrl + '/biodiversity/' + farm_id, header);
if (result) {
+ console.log(result);
+ yield put(setBiodiversityLoading(false));
yield put(setBiodiversityData(result.data));
}
} catch (e) {
+ console.log(e);
+ yield put(setBiodiversityLoading(false));
+ yield put(setBiodiversityError(true, Date.now()));
console.log('failed to fetch biodiversity data from db');
}
}
diff --git a/packages/webapp/src/containers/Insights/selectors.js b/packages/webapp/src/containers/Insights/selectors.js
index e6e90c22e4..9e96b8e250 100644
--- a/packages/webapp/src/containers/Insights/selectors.js
+++ b/packages/webapp/src/containers/Insights/selectors.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (selectors.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,6 +28,16 @@ const labourHappinessSelector = createSelector(
const biodiversitySelector = createSelector(insightSelector, (state) => state.biodiversityData);
+const biodiversityLoadingSelector = createSelector(
+ insightSelector,
+ (state) => state.biodiversityLoading,
+);
+
+const biodiversityErrorSelector = createSelector(
+ insightSelector,
+ (state) => state.biodiversityError,
+);
+
const pricesSelector = createSelector(insightSelector, (state) => state.pricesData);
const pricesDistanceSelector = createSelector(insightSelector, (state) => state.pricesDistance);
@@ -54,6 +64,8 @@ export {
soilOMSelector,
labourHappinessSelector,
biodiversitySelector,
+ biodiversityLoadingSelector,
+ biodiversityErrorSelector,
pricesSelector,
pricesDistanceSelector,
waterBalanceSelector,
diff --git a/packages/webapp/src/containers/InviteSignUp/index.js b/packages/webapp/src/containers/InviteSignUp/index.js
deleted file mode 100644
index cab86c9fd3..0000000000
--- a/packages/webapp/src/containers/InviteSignUp/index.js
+++ /dev/null
@@ -1,104 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PureInviteSignup from '../../components/InviteSignup';
-import jwt from 'jsonwebtoken';
-import { useTranslation } from 'react-i18next';
-import GoogleLogin from 'react-google-login';
-
-import Button from '../../components/Form/Button';
-import { isChrome } from '../../util';
-
-function InviteSignUp({ history }) {
- const invite_token = history.location.state;
- const GOOGLE = 1;
- const LITEFARM = 2;
- const [selectedKey, setSelectedKey] = useState(0);
- const { i18n, t } = useTranslation(['translation', 'common']);
- const [email, setEmail] = useState();
- const [gender, setGender] = useState();
- const [birth_year, setBirthYear] = useState();
- const [showError, setShowError] = useState();
- useEffect(() => {
- if (!invite_token) {
- history.push('/');
- } else {
- const { email, gender, birth_year } = getTokenContent(invite_token);
- setEmail(email);
- setGender(gender);
- setBirthYear(birth_year);
- }
- }, []);
-
- function getTokenContent(token) {
- const decoded = jwt.decode(token);
- return decoded;
- }
-
- const onClick = (selectedKey) => {
- setSelectedKey(selectedKey);
- };
-
- const onSuccessGoogle = (res) => {
- if (res.profileObj.email === email) {
- history.push('/accept_invitation/create_account', {
- email,
- google_id_token: res.tokenObj.id_token,
- invite_token,
- name: res.profileObj.name,
- gender,
- birth_year,
- });
- } else {
- setShowError(true);
- }
- };
- const onFailureGoogle = (res) => {
- console.log(res);
- };
- const onClickGoogle = (renderProps) => () => {
- if (selectedKey === GOOGLE) {
- renderProps.onClick();
- } else {
- const { email, first_name, last_name } = getTokenContent(invite_token);
- history.push('/accept_invitation/create_account', {
- invite_token,
- email,
- name: `${first_name} ${last_name}`,
- gender,
- birth_year,
- });
- }
- };
- const clientId = process.env.REACT_APP_GOOGLE_OAUTH_CLIENT_ID;
-
- return (
- <>
- (
-
- {t('common:PROCEED')}
-
- )}
- onSuccess={onSuccessGoogle}
- onFailure={onFailureGoogle}
- clientId={clientId}
- >
- {t('SIGNUP.GOOGLE_BUTTON')}
-
- }
- showError={showError}
- selectedKey={selectedKey}
- email={email}
- onClick={onClick}
- isChrome={isChrome()}
- />
- >
- );
-}
-
-export default InviteSignUp;
diff --git a/packages/webapp/src/containers/InviteSignUp/index.jsx b/packages/webapp/src/containers/InviteSignUp/index.jsx
new file mode 100644
index 0000000000..0546c37de6
--- /dev/null
+++ b/packages/webapp/src/containers/InviteSignUp/index.jsx
@@ -0,0 +1,104 @@
+import React, { useEffect, useState } from 'react';
+import PureInviteSignup from '../../components/InviteSignup';
+import jwt from '@tsndr/cloudflare-worker-jwt';
+import { useTranslation } from 'react-i18next';
+import GoogleLogin from 'react-google-login';
+
+import Button from '../../components/Form/Button';
+import { isChrome } from '../../util';
+
+function InviteSignUp({ history }) {
+ const invite_token = history.location.state;
+ const GOOGLE = 1;
+ const LITEFARM = 2;
+ const [selectedKey, setSelectedKey] = useState(0);
+ const { i18n, t } = useTranslation(['translation', 'common']);
+ const [email, setEmail] = useState();
+ const [gender, setGender] = useState();
+ const [birth_year, setBirthYear] = useState();
+ const [showError, setShowError] = useState();
+ useEffect(() => {
+ if (!invite_token) {
+ history.push('/');
+ } else {
+ const { email, gender, birth_year } = getTokenContent(invite_token);
+ setEmail(email);
+ setGender(gender);
+ setBirthYear(birth_year);
+ }
+ }, []);
+
+ function getTokenContent(token) {
+ const decoded = jwt.decode(token);
+ return decoded;
+ }
+
+ const onClick = (selectedKey) => {
+ setSelectedKey(selectedKey);
+ };
+
+ const onSuccessGoogle = (res) => {
+ if (res.profileObj.email === email) {
+ history.push('/accept_invitation/create_account', {
+ email,
+ google_id_token: res.tokenObj.id_token,
+ invite_token,
+ name: res.profileObj.name,
+ gender,
+ birth_year,
+ });
+ } else {
+ setShowError(true);
+ }
+ };
+ const onFailureGoogle = (res) => {
+ console.log(res);
+ };
+ const onClickGoogle = (renderProps) => () => {
+ if (selectedKey === GOOGLE) {
+ renderProps.onClick();
+ } else {
+ const { email, first_name, last_name } = getTokenContent(invite_token);
+ history.push('/accept_invitation/create_account', {
+ invite_token,
+ email,
+ name: `${first_name} ${last_name}`,
+ gender,
+ birth_year,
+ });
+ }
+ };
+ const clientId = import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID;
+
+ return (
+ <>
+ (
+
+ {t('common:PROCEED')}
+
+ )}
+ onSuccess={onSuccessGoogle}
+ onFailure={onFailureGoogle}
+ clientId={clientId}
+ >
+ {t('SIGNUP.GOOGLE_BUTTON')}
+
+ }
+ showError={showError}
+ selectedKey={selectedKey}
+ email={email}
+ onClick={onClick}
+ isChrome={isChrome()}
+ />
+ >
+ );
+}
+
+export default InviteSignUp;
diff --git a/packages/webapp/src/containers/InviteUser/index.js b/packages/webapp/src/containers/InviteUser/index.js
deleted file mode 100644
index c228d0b354..0000000000
--- a/packages/webapp/src/containers/InviteUser/index.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import React, { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-
-import { addPseudoWorker, getRoles, inviteUserToFarm } from './saga';
-import history from '../../history';
-import PureInviteUser from '../../components/InviteUser';
-import { rolesSelector } from '../Profile/People/slice';
-import { loginSelector } from '../userFarmSlice';
-import { useTranslation } from 'react-i18next';
-
-const { v4: uuidv4 } = require('uuid');
-
-function InviteUser() {
- const dispatch = useDispatch();
- const { farm_id } = useSelector(loginSelector);
- const roles = useSelector(rolesSelector);
- const { t } = useTranslation('role');
- const dropDownMap = {
- 1: t('role:OWNER'),
- 2: t('role:MANAGER'),
- 3: t('role:WORKER'),
- 5: t('role:EXTENSION_OFFICER'),
- };
- const roleOptions = roles.map(({ role_id }) => ({ value: role_id, label: dropDownMap[role_id] }));
- const onGoBack = () => {
- history.push({
- pathname: '/Profile',
- state: 'people',
- });
- };
-
- const onInvite = (userInfo) => {
- const {
- role,
- email,
- wage: amount,
- first_name,
- last_name,
- gender,
- birth_year,
- phone_number,
- } = userInfo;
- // Pseudo worker is a worker with no email filled out
- const isPseudo = role === 3 && email.trim().length === 0;
- // const amount = pay.amount && pay.amount.trim().length > 0 ? Number(pay.amount) : 0; // TODO: convert this to null to indicate no wage is entered
- if (!isPseudo) {
- const user = {
- email,
- first_name,
- last_name,
- farm_id,
- role_id: Number(role),
- wage: {
- type: 'hourly',
- amount,
- },
- gender,
- birth_year,
- phone_number,
- };
- !user.birth_year && delete user.birth_year;
- !user.phone_number && delete user.phone_number;
-
- dispatch(inviteUserToFarm(user));
- } else {
- const pseudoId = uuidv4();
- const user = {
- email: pseudoId + '@pseudo.com',
- first_name,
- last_name,
- farm_id,
- wage: {
- type: 'hourly',
- amount,
- },
- profile_picture: 'https://cdn.auth0.com/avatars/na.png',
- user_id: pseudoId,
- gender,
- birth_year,
- phone_number,
- };
- !user.birth_year && delete user.birth_year;
- !user.phone_number && delete user.phone_number;
-
- dispatch(addPseudoWorker(user));
- }
-
- history.push({
- pathname: '/Profile',
- state: 'people',
- });
- };
-
- useEffect(() => {
- dispatch(getRoles());
- }, []);
-
- return ;
-}
-
-export default InviteUser;
diff --git a/packages/webapp/src/containers/InviteUser/index.jsx b/packages/webapp/src/containers/InviteUser/index.jsx
new file mode 100644
index 0000000000..1015608798
--- /dev/null
+++ b/packages/webapp/src/containers/InviteUser/index.jsx
@@ -0,0 +1,101 @@
+import React, { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+
+import { addPseudoWorker, getRoles, inviteUserToFarm } from './saga';
+import history from '../../history';
+import PureInviteUser from '../../components/InviteUser';
+import { rolesSelector } from '../Profile/People/slice';
+import { loginSelector } from '../userFarmSlice';
+import { useTranslation } from 'react-i18next';
+import { v4 as uuidv4 } from 'uuid';
+
+function InviteUser() {
+ const dispatch = useDispatch();
+ const { farm_id } = useSelector(loginSelector);
+ const roles = useSelector(rolesSelector);
+ const { t } = useTranslation('role');
+ const dropDownMap = {
+ 1: t('role:OWNER'),
+ 2: t('role:MANAGER'),
+ 3: t('role:WORKER'),
+ 5: t('role:EXTENSION_OFFICER'),
+ };
+ const roleOptions = roles.map(({ role_id }) => ({ value: role_id, label: dropDownMap[role_id] }));
+ const onGoBack = () => {
+ history.push({
+ pathname: '/people',
+ });
+ };
+
+ const onInvite = (userInfo) => {
+ const {
+ role,
+ email,
+ wage: amount,
+ first_name,
+ last_name,
+ gender,
+ language,
+ birth_year,
+ phone_number,
+ } = userInfo;
+ // Pseudo worker is a worker with no email filled out
+ const isPseudo = role === 3 && email.trim().length === 0;
+ // const amount = pay.amount && pay.amount.trim().length > 0 ? Number(pay.amount) : 0; // TODO: convert this to null to indicate no wage is entered
+ if (!isPseudo) {
+ const user = {
+ email,
+ first_name,
+ last_name,
+ farm_id,
+ role_id: Number(role),
+ wage: {
+ type: 'hourly',
+ amount,
+ },
+ gender,
+ language,
+ birth_year,
+ phone_number,
+ };
+ !user.birth_year && delete user.birth_year;
+ !user.phone_number && delete user.phone_number;
+
+ dispatch(inviteUserToFarm(user));
+ } else {
+ const pseudoId = uuidv4();
+ const user = {
+ email: pseudoId + '@pseudo.com',
+ first_name,
+ last_name,
+ farm_id,
+ wage: {
+ type: 'hourly',
+ amount,
+ },
+ profile_picture: 'https://cdn.auth0.com/avatars/na.png',
+ user_id: pseudoId,
+ gender,
+ language,
+ birth_year,
+ phone_number,
+ };
+ !user.birth_year && delete user.birth_year;
+ !user.phone_number && delete user.phone_number;
+
+ dispatch(addPseudoWorker(user));
+ }
+
+ history.push({
+ pathname: '/people',
+ });
+ };
+
+ useEffect(() => {
+ dispatch(getRoles());
+ }, []);
+
+ return ;
+}
+
+export default InviteUser;
diff --git a/packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithLiteFarm/index.js b/packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithLiteFarm/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithLiteFarm/index.js
rename to packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithLiteFarm/index.jsx
diff --git a/packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithSSO/index.js b/packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithSSO/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithSSO/index.js
rename to packages/webapp/src/containers/InvitedUserCreateAccount/InvitedUserCreateAccountWithSSO/index.jsx
diff --git a/packages/webapp/src/containers/InvitedUserCreateAccount/index.js b/packages/webapp/src/containers/InvitedUserCreateAccount/index.js
deleted file mode 100644
index 1211fb8358..0000000000
--- a/packages/webapp/src/containers/InvitedUserCreateAccount/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import InvitedUserCreateAccountWithSSO from './InvitedUserCreateAccountWithSSO';
-import InvitedUserCreateAccountWithLiteFarm from './InvitedUserCreateAccountWithLiteFarm';
-
-export default function InvitedUserCreateAccount({ history }) {
- const { google_id_token } = history.location.state;
- return google_id_token ? (
-
- ) : (
-
- );
-}
-
-InvitedUserCreateAccount.prototype = {
- history: PropTypes.object,
-};
diff --git a/packages/webapp/src/containers/InvitedUserCreateAccount/index.jsx b/packages/webapp/src/containers/InvitedUserCreateAccount/index.jsx
new file mode 100644
index 0000000000..9f1bf581a7
--- /dev/null
+++ b/packages/webapp/src/containers/InvitedUserCreateAccount/index.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import InvitedUserCreateAccountWithSSO from './InvitedUserCreateAccountWithSSO';
+import InvitedUserCreateAccountWithLiteFarm from './InvitedUserCreateAccountWithLiteFarm';
+
+export default function InvitedUserCreateAccount({ history }) {
+ return !!history?.location?.state?.google_id_token ? (
+
+ ) : (
+
+ );
+}
+
+InvitedUserCreateAccount.prototype = {
+ history: PropTypes.object,
+};
diff --git a/packages/webapp/src/containers/InvitedUserCreateAccount/saga.js b/packages/webapp/src/containers/InvitedUserCreateAccount/saga.js
index 55239f780d..bb9d6f63ea 100644
--- a/packages/webapp/src/containers/InvitedUserCreateAccount/saga.js
+++ b/packages/webapp/src/containers/InvitedUserCreateAccount/saga.js
@@ -8,12 +8,12 @@ import {
} from '../userFarmSlice';
import history from '../../history';
import { getFirstNameLastName } from '../../util';
-import { purgeState } from '../../index';
import i18n from '../../locales/i18n';
import { axios } from '../saga';
import { startInvitationFlowWithSpotLight } from '../ChooseFarm/chooseFarmFlowSlice';
import { enqueueErrorSnackbar } from '../Snackbar/snackbarSlice';
import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+import { purgeState } from '../../store/store';
const acceptInvitationWithSSOUrl = () => `${url}/user/accept_invitation`;
const acceptInvitationWithLiteFarmUrl = () => `${url}/user/accept_invitation`;
@@ -55,12 +55,11 @@ export function* acceptInvitationWithSSOSaga({
} catch (e) {
yield put(onLoadingUserFarmsFail(e));
if (e.response.status === 401) {
- const translateKey =
- e.response.data === 'Invitation link is used'
- ? 'SIGNUP.USED_INVITATION_LINK_ERROR'
- : 'SIGNUP.EXPIRED_INVITATION_LINK_ERROR';
history.push(`/?email=${encodeURIComponent(userForm.email)}`, {
- error: i18n.t(translateKey),
+ error:
+ e.response.data === 'Invitation link is used'
+ ? i18n.t('SIGNUP.USED_INVITATION_LINK_ERROR')
+ : i18n.t('SIGNUP.EXPIRED_INVITATION_LINK_ERROR'),
});
} else {
yield put(enqueueErrorSnackbar(i18n.t('message:LOGIN.ERROR.LOGIN_FAIL')));
@@ -101,12 +100,11 @@ export function* acceptInvitationWithLiteFarmSaga({ payload: { invite_token, use
} catch (e) {
yield put(onLoadingUserFarmsFail(e));
if (e.response.status === 401) {
- const translateKey =
- e.response.data === 'Invitation link is used'
- ? 'SIGNUP.USED_INVITATION_LINK_ERROR'
- : 'SIGNUP.EXPIRED_INVITATION_LINK_ERROR';
history.push(`/?email=${encodeURIComponent(userForm.email)}`, {
- error: i18n.t(translateKey),
+ error:
+ e.response.data === 'Invitation link is used'
+ ? i18n.t('SIGNUP.USED_INVITATION_LINK_ERROR')
+ : i18n.t('SIGNUP.EXPIRED_INVITATION_LINK_ERROR'),
});
} else {
yield put(enqueueErrorSnackbar(i18n.t('message:LOGIN.ERROR.LOGIN_FAIL')));
diff --git a/packages/webapp/src/containers/JoinFarmSuccessScreen/index.js b/packages/webapp/src/containers/JoinFarmSuccessScreen/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/JoinFarmSuccessScreen/index.js
rename to packages/webapp/src/containers/JoinFarmSuccessScreen/index.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/PostBarn.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/saga.js
index 5b11e4532b..eb41d637a1 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/BarnDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postBarnLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.BARN'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.BARN')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editBarnLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.BARN')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteBarnLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/PostCeremonialArea.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga.js
index 94959112dd..606aefffe8 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postCeremonialLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.CA'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.CA')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editCeremonialLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.CA')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteCeremonialLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/PostFarmSiteBoundary.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga.js
index 7bd90d28eb..501e674c83 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postFarmSiteBoundaryLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.FSB'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.FSB')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -79,14 +81,16 @@ export function* editFarmSiteBoundaryLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.FSB')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -108,14 +112,16 @@ export function* deleteFarmSiteBoundaryLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/EditField.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/EditField.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/EditField.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/EditField.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/PostField.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/PostField.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/PostField.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/PostField.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/saga.js
index 0d161c5fa6..683d720bc5 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/FieldDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postFieldLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.FIELD'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.FIELD')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editFieldLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.FIELD')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -107,14 +111,16 @@ export function* deleteFieldLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/PostGarden.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/saga.js
index 038cd3eed0..90d4a4d101 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/GardenDetailForm/saga.js
@@ -35,16 +35,18 @@ export function* postGardenLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.GARDEN'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.GARDEN')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -77,14 +79,16 @@ export function* editGardenLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.GARDEN')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -109,14 +113,16 @@ export function* deleteGardenLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/PostGreenhouse.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga.js
index c9954f2d6b..ea5eabac97 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga.js
@@ -39,16 +39,18 @@ export function* postGreenhouseLocationSaga({ payload: data }) {
]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.GREENHOUSE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -81,14 +83,16 @@ export function* editGreenhouseLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.GREENHOUSE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -113,14 +117,16 @@ export function* deleteGreenhouseLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/PostNaturalArea.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga.js
index a6338703bb..312358d4fe 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postNaturalAreaLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.NA'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.NA')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editNaturalAreaLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.NA')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteNaturalAreaLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/PostResidence.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga.js
index 6c4c3efd01..7ebf7e6814 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga.js
@@ -39,16 +39,18 @@ export function* postResidenceLocationSaga({ payload: data }) {
]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.RESIDENCE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -81,14 +83,16 @@ export function* editResidenceLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.RESIDENCE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -113,14 +117,16 @@ export function* deleteResidenceLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater.js
rename to packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/PostSurfaceWater.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga.js
index 0bc40ee754..08183f8138 100644
--- a/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga.js
@@ -39,16 +39,18 @@ export function* postSurfaceWaterLocationSaga({ payload: data }) {
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.SURFACE_WATER')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -81,14 +83,16 @@ export function* editSurfaceWaterLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.SURFACE_WATER')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -113,14 +117,16 @@ export function* deleteSurfaceWaterLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone.js b/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone.js b/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/PostBufferZone.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga.js
index 4331995520..8cbc3a1d81 100644
--- a/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postBufferZoneLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.BZ'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.back();
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.BZ')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editBufferZoneLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.BZ')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteBufferZoneLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/EditFence.js b/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/EditFence.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/EditFence.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/EditFence.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/PostFence.js b/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/PostFence.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/PostFence.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/PostFence.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/saga.js
index 961fbdb2a9..1dec60bf29 100644
--- a/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/LineDetails/FenceDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postFenceLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.FENCE'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.back();
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.FENCE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editFenceLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.FENCE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -107,14 +111,16 @@ export function* deleteFenceLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse.js b/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse.js b/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse.js
rename to packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/PostWatercourse.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/saga.js
index 547fac4e59..535a7bc19a 100644
--- a/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/LineDetails/WatercourseDetailForm/saga.js
@@ -39,16 +39,18 @@ export function* postWatercourseLocationSaga({ payload: data }) {
]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.back();
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.WATERCOURSE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -81,14 +83,16 @@ export function* editWatercourseLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.WATERCOURSE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -113,14 +117,16 @@ export function* deleteWatercourseLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.js b/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.js
deleted file mode 100644
index f4fb60d07f..0000000000
--- a/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
-import PureCropList from '../../../components/CropListPage';
-import { isAdminSelector } from '../../userFarmSlice';
-import { cropLocationByIdSelector } from '../../locationSlice';
-import {
- currentManagementPlansByLocationIdSelector,
- expiredManagementPlansByLocationIdSelector,
- plannedManagementPlansByLocationIdSelector,
-} from '../../Task/TaskCrops/managementPlansWithLocationSelector';
-
-function LocationManagementPlan({ history, match }) {
- const [filter, setFilter] = useState();
- const isAdmin = useSelector(isAdminSelector);
- const { location_id } = match.params;
- const activeCrops = useSelector(currentManagementPlansByLocationIdSelector(location_id));
- const pastCrops = useSelector(expiredManagementPlansByLocationIdSelector(location_id));
- const plannedCrops = useSelector(plannedManagementPlansByLocationIdSelector(location_id));
-
- const onFilterChange = (e) => {
- setFilter(e.target.value.toLowerCase());
- };
-
- const onAddCrop = () => {
- history.push(`/crop_catalogue`);
- };
- const location = useSelector(cropLocationByIdSelector(location_id));
-
- return (
- <>
-
- >
- );
-}
-
-const filteredManagementPlans = (filter, managementPlans) => {
- const filtered = filter
- ? managementPlans.filter(
- (managementPlan) =>
- managementPlan?.crop_variety?.toLowerCase()?.includes(filter) ||
- managementPlan?.crop_common_name?.toLowerCase()?.includes(filter),
- )
- : managementPlans;
- return filtered;
-};
-
-export default LocationManagementPlan;
diff --git a/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.jsx b/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.jsx
new file mode 100644
index 0000000000..d6e858ccca
--- /dev/null
+++ b/packages/webapp/src/containers/LocationDetails/LocationManagementPlan/index.jsx
@@ -0,0 +1,70 @@
+import React, { useState } from 'react';
+import { useSelector } from 'react-redux';
+import PureCropList from '../../../components/CropListPage';
+import { isAdminSelector } from '../../userFarmSlice';
+import { cropLocationByIdSelector } from '../../locationSlice';
+import {
+ currentManagementPlansByLocationIdSelector,
+ expiredManagementPlansByLocationIdSelector,
+ plannedManagementPlansByLocationIdSelector,
+} from '../../Task/TaskCrops/managementPlansWithLocationSelector';
+import { useTranslation } from 'react-i18next';
+
+function LocationManagementPlan({ history, match, location }) {
+ const [filter, setFilter] = useState();
+ const isAdmin = useSelector(isAdminSelector);
+ const { location_id } = match.params;
+ const activeCrops = useSelector(currentManagementPlansByLocationIdSelector(location_id));
+ const pastCrops = useSelector(expiredManagementPlansByLocationIdSelector(location_id));
+ const plannedCrops = useSelector(plannedManagementPlansByLocationIdSelector(location_id));
+ const { t } = useTranslation();
+
+ const onFilterChange = (e) => {
+ setFilter(e.target.value.toLowerCase());
+ };
+
+ const onAddCrop = () => {
+ history.push(`/crop_catalogue`);
+ };
+ const { name } = useSelector(cropLocationByIdSelector(location_id));
+
+ return (
+ <>
+
+ >
+ );
+}
+
+const check = (name, filter) => {
+ return (
+ name?.toLowerCase().includes(filter) ||
+ name
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/\p{Diacritic}/gu, '')
+ .includes(filter)
+ );
+};
+
+const filteredManagementPlans = (filter, managementPlans, t) => {
+ return filter
+ ? managementPlans.filter(
+ (managementPlan) =>
+ check(managementPlan?.crop_variety?.crop_variety_name, filter) ||
+ check(t(`crop:${managementPlan?.crop_variety?.crop_translation_key}`), filter),
+ )
+ : managementPlans;
+};
+
+export default LocationManagementPlan;
diff --git a/packages/webapp/src/containers/LocationDetails/LocationTasks/index.jsx b/packages/webapp/src/containers/LocationDetails/LocationTasks/index.jsx
new file mode 100644
index 0000000000..118bff03b3
--- /dev/null
+++ b/packages/webapp/src/containers/LocationDetails/LocationTasks/index.jsx
@@ -0,0 +1,65 @@
+import React, { useMemo } from 'react';
+import {
+ manualFilteredTaskCardContentSelector,
+ taskCardContentSelector,
+ getTaskStatus,
+} from '../../Task/taskCardContentSelector';
+import { isAdminSelector, userFarmSelector } from '../../userFarmSlice';
+import { useSelector } from 'react-redux';
+import {
+ cropLocationByIdSelector,
+ locationByIdSelector,
+ locationsSelector,
+} from '../../locationSlice';
+import PureLocationTasks from '../../../components/LocationTasks';
+
+export default function LocationTasks({ history, match, location: { pathname } }) {
+ const isAdmin = useSelector(isAdminSelector);
+ const { user_id, farm_id } = useSelector(userFarmSelector);
+ const { location_id } = match.params;
+ const location = useSelector(locationByIdSelector(location_id));
+
+ const areCropEnabled = ['field', 'garden', 'greenhouse', 'buffer_zone'];
+
+ const hasCrops = areCropEnabled.includes(pathname.split('/')[1]);
+
+ const filter = (taskList) => {
+ const activeStatus = ['planned', 'late'];
+ return taskList.filter(
+ (t) =>
+ t.locations.find((loc) => loc.location_id === location_id) &&
+ activeStatus.includes(getTaskStatus(t)),
+ );
+ };
+
+ const locationTasks = useSelector(manualFilteredTaskCardContentSelector(filter));
+
+ const { tasks, count } = useMemo(() => {
+ return locationTasks.reduce(
+ (previous, current) => {
+ previous.count++;
+ if (!Object.keys(previous.tasks).includes(current.date)) {
+ previous.tasks[current.date] = [current];
+ } else {
+ previous.tasks[current.date].push(current);
+ }
+ return previous;
+ },
+ { count: 0, tasks: {} },
+ );
+ }, [locationTasks]);
+
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/EditGate.js b/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/EditGate.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/EditGate.js
rename to packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/EditGate.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/PostGate.js b/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/PostGate.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/PostGate.js
rename to packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/PostGate.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/saga.js
index dbbe6cf75e..c957910563 100644
--- a/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/PointDetails/GateDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postGateLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.GATE'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.back();
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.GATE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editGateLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.GATE')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteGateLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve.js b/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve.js
rename to packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve.js b/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve.jsx
similarity index 100%
rename from packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve.js
rename to packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/PostWaterValve.jsx
diff --git a/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/saga.js b/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/saga.js
index 3b0281bd9e..d2110a6839 100644
--- a/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/saga.js
+++ b/packages/webapp/src/containers/LocationDetails/PointDetails/WaterValveDetailForm/saga.js
@@ -36,16 +36,18 @@ export function* postWaterValveLocationSaga({ payload: data }) {
setSuccessMessage([i18n.t('FARM_MAP.MAP_FILTER.WV'), i18n.t('message:MAP.SUCCESS_POST')]),
);
yield put(canShowSuccessHeader(true));
- history.goBack();
+ history.back();
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_POST')} ${i18n
.t('FARM_MAP.MAP_FILTER.WV')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -75,14 +77,16 @@ export function* editWaterValveLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: `${i18n.t('message:MAP.FAIL_PATCH')} ${i18n
.t('FARM_MAP.MAP_FILTER.WV')
.toLowerCase()}`,
},
- });
+ );
console.log(e);
}
}
@@ -104,14 +108,16 @@ export function* deleteWaterValveLocationSaga({ payload: data }) {
yield put(canShowSuccessHeader(true));
history.push({ pathname: '/map' });
} catch (e) {
- history.push({
- path: history.location.pathname,
- state: {
+ history.push(
+ {
+ pathname: history.location.pathname,
+ },
+ {
error: {
retire: true,
},
},
- });
+ );
console.log(e);
}
}
diff --git a/packages/webapp/src/containers/Map/LocationSelectionModal/index.js b/packages/webapp/src/containers/Map/LocationSelectionModal/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Map/LocationSelectionModal/index.js
rename to packages/webapp/src/containers/Map/LocationSelectionModal/index.jsx
diff --git a/packages/webapp/src/containers/Map/constants.js b/packages/webapp/src/containers/Map/constants.js
index e721752961..279c2cb2f7 100644
--- a/packages/webapp/src/containers/Map/constants.js
+++ b/packages/webapp/src/containers/Map/constants.js
@@ -1,12 +1,10 @@
-require('dotenv').config();
-
export const DEFAULT_CENTER = {
lat: 49.24966,
lng: -123.237421,
};
export const DEFAULT_ZOOM = 15;
-export const GMAPS_API_KEY = process.env.REACT_APP_GOOGLE_MAPS_API_KEY;
-export const ENVIRONMENT = process.env.NODE_ENV;
+export const GMAPS_API_KEY = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;
+export const ENVIRONMENT = import.meta.env.NODE_ENV;
export const getAreaLocationTypes = () => [
locationEnum.barn,
diff --git a/packages/webapp/src/containers/Map/index.js b/packages/webapp/src/containers/Map/index.js
deleted file mode 100644
index a817f1379a..0000000000
--- a/packages/webapp/src/containers/Map/index.js
+++ /dev/null
@@ -1,470 +0,0 @@
-import React, { useEffect, useRef, useState } from 'react';
-import ReactDOM from 'react-dom';
-import { useTranslation } from 'react-i18next';
-import styles from './styles.module.scss';
-import GoogleMap from 'google-map-react';
-import { DEFAULT_ZOOM, GMAPS_API_KEY, isArea, isLine, locationEnum } from './constants';
-import { useDispatch, useSelector } from 'react-redux';
-import { measurementSelector, userFarmSelector } from '../userFarmSlice';
-import html2canvas from 'html2canvas';
-import { sendMapToEmail, setSpotlightToShown } from './saga';
-import {
- canShowSuccessHeader,
- setShowSuccessHeaderSelector,
- setSuccessMessageSelector,
-} from '../mapSlice';
-import { showedSpotlightSelector } from '../showedSpotlightSlice';
-
-import PureMapHeader from '../../components/Map/Header';
-import { PureSnackbarWithoutBorder } from '../../components/PureSnackbar';
-import PureMapFooter from '../../components/Map/Footer';
-import ExportMapModal from '../../components/Modals/ExportMapModal';
-import DrawAreaModal from '../../components/Map/Modals/DrawArea';
-import DrawLineModal from '../../components/Map/Modals/DrawLine';
-import AdjustAreaModal from '../../components/Map/Modals/AdjustArea';
-import AdjustLineModal from '../../components/Map/Modals/AdjustLine';
-import CustomZoom from '../../components/Map/CustomZoom';
-import CustomCompass from '../../components/Map/CustomCompass';
-import DrawingManager from '../../components/Map/DrawingManager';
-import useWindowInnerHeight from '../hooks/useWindowInnerHeight';
-import useDrawingManager from './useDrawingManager';
-
-import useMapAssetRenderer from './useMapAssetRenderer';
-import { getLocations } from '../saga';
-import {
- availableFilterSettingsSelector,
- mapFilterSettingSelector,
- setMapFilterHideAll,
- setMapFilterSetting,
- setMapFilterShowAll,
-} from './mapFilterSettingSlice';
-import {
- hookFormPersistedPathsSetSelector,
- hookFormPersistSelector,
- resetAndUnLockFormData,
- setPersistedPaths,
- upsertFormData,
-} from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import LocationSelectionModal from './LocationSelectionModal';
-import { useMaxZoom } from './useMaxZoom';
-
-export default function Map({ history }) {
- const windowInnerHeight = useWindowInnerHeight();
- const { farm_name, grid_points, is_admin, farm_id } = useSelector(userFarmSelector);
- const filterSettings = useSelector(mapFilterSettingSelector);
- const showedSpotlight = useSelector(showedSpotlightSelector);
- const roadview = !filterSettings.map_background;
- const dispatch = useDispatch();
- const system = useSelector(measurementSelector);
- const overlayData = useSelector(hookFormPersistSelector);
-
- const lineTypesWithWidth = [locationEnum.buffer_zone, locationEnum.watercourse];
- const { t } = useTranslation();
- const showHeader = useSelector(setShowSuccessHeaderSelector);
- const [showSuccessHeader, setShowSuccessHeader] = useState(false);
- const [showZeroAreaWarning, setZeroAreaWarning] = useState(false);
- const successMessage = useSelector(setSuccessMessageSelector);
-
- const initialLineData = {
- [locationEnum.watercourse]: {
- width: 1,
- buffer_width: 15,
- },
- [locationEnum.buffer_zone]: {
- width: 8,
- },
- };
- const persistedPathsSet = useSelector(hookFormPersistedPathsSetSelector);
- useEffect(() => {
- return () => {
- persistedPathsSet.size &&
- !persistedPathsSet.has(history.location.pathname) &&
- dispatch(resetAndUnLockFormData());
- };
- }, [persistedPathsSet]);
- useEffect(() => {
- if (!history.location.isStepBack) {
- dispatch(resetAndUnLockFormData());
- }
- return () => {
- dispatch(canShowSuccessHeader(false));
- };
- }, []);
-
- const [
- drawingState,
- {
- initDrawingState,
- startDrawing,
- finishDrawing,
- resetDrawing,
- closeDrawer,
- getOverlayInfo,
- reconstructOverlay,
- setLineWidth,
- setShowAdjustAreaSpotlightModal,
- setShowAdjustLineSpotlightModal,
- },
- ] = useDrawingManager();
-
- useEffect(() => {
- dispatch(getLocations());
- }, []);
-
- useEffect(() => {
- if (showHeader) setShowSuccessHeader(true);
- }, [showHeader]);
-
- const [showMapFilter, setShowMapFilter] = useState(false);
- const [showAddDrawer, setShowAddDrawer] = useState(false);
- const [showExportModal, setShowExportModal] = useState(false);
- const [showDrawAreaSpotlightModal, setShowDrawAreaSpotlightModal] = useState(false);
- const [showDrawLineSpotlightModal, setShowDrawLineSpotlightModal] = useState(false);
-
- const getMapOptions = (maps) => {
- return {
- styles: [
- {
- featureType: 'poi.business',
- elementType: 'labels',
- stylers: [
- {
- visibility: 'off',
- },
- ],
- },
- ],
- gestureHandling: 'greedy',
- disableDoubleClickZoom: false,
- minZoom: 1,
- maxZoom: 80,
- tilt: 0,
- mapTypeId: !roadview ? maps.MapTypeId.SATELLITE : maps.MapTypeId.ROADMAP,
- mapTypeControlOptions: {
- style: maps.MapTypeControlStyle.HORIZONTAL_BAR,
- position: maps.ControlPosition.BOTTOM_CENTER,
- mapTypeIds: [maps.MapTypeId.ROADMAP, maps.MapTypeId.SATELLITE],
- },
- clickableIcons: false,
- streetViewControl: false,
- scaleControl: false,
- mapTypeControl: false,
- panControl: false,
- zoomControl: false,
- rotateControl: false,
- fullscreenControl: false,
- };
- };
- const { drawAssets } = useMapAssetRenderer({ isClickable: !drawingState.type });
- const { getMaxZoom } = useMaxZoom();
- const handleGoogleMapApi = (map, maps) => {
- getMaxZoom(maps);
- maps.Polygon.prototype.getPolygonBounds = function () {
- var bounds = new maps.LatLngBounds();
- this.getPath().forEach(function (element, index) {
- bounds.extend(element);
- });
- return bounds;
- };
- maps.Polygon.prototype.getAveragePoint = function () {
- const latLngArray = this.getPath().getArray();
- let latSum = 0;
- let lngSum = 0;
- for (const latLng of latLngArray) {
- latSum += latLng.lat();
- lngSum += latLng.lng();
- }
- return new maps.LatLng(latSum / latLngArray.length, lngSum / latLngArray.length);
- };
-
- // Create drawing manager
- let drawingManagerInit = new maps.drawing.DrawingManager({
- drawingMode: null,
- drawingControl: false,
- drawingControlOptions: {
- position: maps.ControlPosition.TOP_CENTER,
- drawingModes: [
- maps.drawing.OverlayType.POLYGON,
- maps.drawing.OverlayType.POLYLINE,
- maps.drawing.OverlayType.MARKER,
- ],
- },
- map: map,
- });
-
- maps.event.addListener(drawingManagerInit, 'polygoncomplete', function (polygon) {
- const polygonAreaCheck = (path) => {
- if (Math.round(maps.geometry.spherical.computeArea(path)) === 0) setZeroAreaWarning(true);
- else setZeroAreaWarning(false);
- };
- const path = polygon.getPath();
- polygonAreaCheck(path);
- maps.event.addListener(path, 'set_at', function () {
- polygonAreaCheck(this);
- });
- maps.event.addListener(path, 'insert_at', function () {
- polygonAreaCheck(this);
- });
- });
- maps.event.addListener(drawingManagerInit, 'overlaycomplete', function (drawing) {
- finishDrawing(drawing, maps, map);
- this.setDrawingMode();
- });
- initDrawingState(map, maps, drawingManagerInit, {
- POLYGON: maps.drawing.OverlayType.POLYGON,
- POLYLINE: maps.drawing.OverlayType.POLYLINE,
- MARKER: maps.drawing.OverlayType.MARKER,
- });
-
- // Adding custom map components
- const zoomControlDiv = document.createElement('div');
- ReactDOM.render(
- map.setZoom(map.getZoom() + 1)}
- onClickZoomOut={() => map.setZoom(map.getZoom() - 1)}
- />,
- zoomControlDiv,
- );
- map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(zoomControlDiv);
-
- const compassControlDiv = document.createElement('div');
- ReactDOM.render( , compassControlDiv);
- map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(compassControlDiv);
-
- // Drawing locations on map
- let mapBounds = new maps.LatLngBounds();
- drawAssets(map, maps, mapBounds);
-
- if (history.location.isStepBack) {
- reconstructOverlay();
- }
-
- if (history.location.cameraInfo) {
- const { zoom, location } = history.location.cameraInfo;
- if (zoom && location) {
- map.setZoom(zoom);
- map.setCenter(location);
- }
- }
- };
-
- const handleClickAdd = () => {
- setShowExportModal(false);
- setShowMapFilter(false);
- setShowAddDrawer(!showAddDrawer);
- };
-
- const handleClickExport = () => {
- setShowExportModal(!showExportModal);
- setShowMapFilter(false);
- setShowAddDrawer(false);
- };
-
- const handleClickFilter = () => {
- setShowExportModal(false);
- setShowAddDrawer(false);
- setShowMapFilter(!showMapFilter);
- };
-
- const handleFilterMenuClick = (locationType) => {
- if (locationType === 'show_all') {
- dispatch(setMapFilterShowAll(farm_id));
- } else if (locationType === 'hide_all') {
- dispatch(setMapFilterHideAll(farm_id));
- } else {
- const payload = {};
- payload[locationType] = !filterSettings[locationType];
- payload.farm_id = farm_id;
- dispatch(setMapFilterSetting(payload));
- }
- };
-
- const availableFilterSettings = useSelector(availableFilterSettingsSelector);
-
- const handleAddMenuClick = (locationType) => {
- setZeroAreaWarning(false);
- if (isArea(locationType) && !showedSpotlight.draw_area) {
- setShowDrawAreaSpotlightModal(true);
- } else if (isLine(locationType) && !showedSpotlight.draw_line) {
- setShowDrawLineSpotlightModal(true);
- }
- isLineWithWidth(locationType) && dispatch(upsertFormData(initialLineData[locationType]));
- const submitPath = `/create_location/${locationType}`;
- dispatch(setPersistedPaths([submitPath, '/map']));
- startDrawing(locationType);
- };
-
- const mapWrapperRef = useRef();
-
- const handleShowVideo = () => {
- history.push('/map/videos');
- };
-
- const handleCloseSuccessHeader = () => {
- dispatch(canShowSuccessHeader(false));
- setShowSuccessHeader(false);
- };
-
- const handleDownload = () => {
- html2canvas(mapWrapperRef.current, { useCORS: true }).then((canvas) => {
- const link = document.createElement('a');
- link.download = `${farm_name}-export-${new Date().toISOString()}.png`;
- link.href = canvas.toDataURL();
- link.click();
- });
- };
-
- const handleShare = () => {
- html2canvas(mapWrapperRef.current, { useCORS: true }).then((canvas) => {
- const fileDataURL = canvas.toDataURL();
- dispatch(sendMapToEmail(fileDataURL));
- });
- };
-
- const handleConfirm = () => {
- if (!isLineWithWidth()) {
- const locationData = getOverlayInfo();
- dispatch(upsertFormData(locationData));
- history.push(`/create_location/${drawingState.type}`);
- }
- };
-
- const handleLineConfirm = (lineData) => {
- const data = { ...getOverlayInfo(), ...lineData };
- dispatch(upsertFormData(data));
- history.push(`/create_location/${drawingState.type}`);
- };
-
- const isLineWithWidth = (type = drawingState.type) => {
- return lineTypesWithWidth.includes(type);
- };
-
- const { showAdjustAreaSpotlightModal, showAdjustLineSpotlightModal } = drawingState;
- return (
- <>
- {!showMapFilter && !showAddDrawer && !drawingState.type && !showSuccessHeader && (
-
- )}
- {showSuccessHeader && (
-
- )}
-
-
-
- handleGoogleMapApi(map, maps)}
- options={getMapOptions}
- />
-
- {drawingState.type && (
-
- {
- setZeroAreaWarning(false);
- resetDrawing(true);
- dispatch(resetAndUnLockFormData());
- closeDrawer();
- }}
- onClickTryAgain={() => {
- setZeroAreaWarning(false);
- resetDrawing();
- startDrawing(drawingState.type);
- }}
- onClickConfirm={handleConfirm}
- showZeroAreaWarning={showZeroAreaWarning}
- confirmLine={handleLineConfirm}
- updateLineWidth={setLineWidth}
- system={system}
- lineData={overlayData}
- typeOfLine={drawingState.type}
- />
-
- )}
-
-
-
- {!drawingState.type && (
-
dispatch(setSpotlightToShown('map'))}
- onClickAdd={handleClickAdd}
- onClickExport={handleClickExport}
- showModal={showExportModal}
- setShowMapFilter={setShowMapFilter}
- showMapFilter={showMapFilter}
- setShowAddDrawer={setShowAddDrawer}
- showAddDrawer={showAddDrawer}
- handleClickFilter={handleClickFilter}
- filterSettings={filterSettings}
- onFilterMenuClick={handleFilterMenuClick}
- onAddMenuClick={handleAddMenuClick}
- availableFilterSettings={availableFilterSettings}
- />
- )}
- {showExportModal && (
- setShowExportModal(false)}
- />
- )}
- {showDrawAreaSpotlightModal && (
- {
- setShowDrawAreaSpotlightModal(false);
- dispatch(setSpotlightToShown('draw_area'));
- }}
- />
- )}
- {showDrawLineSpotlightModal && (
- {
- setShowDrawLineSpotlightModal(false);
- dispatch(setSpotlightToShown('draw_line'));
- }}
- />
- )}
- {showAdjustAreaSpotlightModal && (
- {
- setShowAdjustAreaSpotlightModal(false);
- dispatch(setSpotlightToShown('adjust_area'));
- }}
- />
- )}
- {showAdjustLineSpotlightModal && (
- {
- setShowAdjustLineSpotlightModal(false);
- dispatch(setSpotlightToShown('adjust_line'));
- }}
- />
- )}
-
- >
- );
-}
diff --git a/packages/webapp/src/containers/Map/index.jsx b/packages/webapp/src/containers/Map/index.jsx
new file mode 100644
index 0000000000..698ff37728
--- /dev/null
+++ b/packages/webapp/src/containers/Map/index.jsx
@@ -0,0 +1,486 @@
+import React, { useEffect, useRef, useState } from 'react';
+import ReactDOM from 'react-dom';
+import { useTranslation } from 'react-i18next';
+import styles from './styles.module.scss';
+import GoogleMap from 'google-map-react';
+import { saveAs } from 'file-saver';
+import { DEFAULT_ZOOM, GMAPS_API_KEY, isArea, isLine, locationEnum } from './constants';
+import { useDispatch, useSelector } from 'react-redux';
+import { measurementSelector, userFarmSelector } from '../userFarmSlice';
+import html2canvas from 'html2canvas';
+import { sendMapToEmail, setSpotlightToShown } from './saga';
+import {
+ canShowSuccessHeader,
+ setShowSuccessHeaderSelector,
+ setSuccessMessageSelector,
+} from '../mapSlice';
+import { showedSpotlightSelector } from '../showedSpotlightSlice';
+
+import PureMapHeader from '../../components/Map/Header';
+import { PureSnackbarWithoutBorder } from '../../components/PureSnackbar';
+import PureMapFooter from '../../components/Map/Footer';
+import ExportMapModal from '../../components/Modals/ExportMapModal';
+import DrawAreaModal from '../../components/Map/Modals/DrawArea';
+import DrawLineModal from '../../components/Map/Modals/DrawLine';
+import AdjustAreaModal from '../../components/Map/Modals/AdjustArea';
+import AdjustLineModal from '../../components/Map/Modals/AdjustLine';
+import CustomZoom from '../../components/Map/CustomZoom';
+import CustomCompass from '../../components/Map/CustomCompass';
+import DrawingManager from '../../components/Map/DrawingManager';
+import useWindowInnerHeight from '../hooks/useWindowInnerHeight';
+import useDrawingManager from './useDrawingManager';
+
+import useMapAssetRenderer from './useMapAssetRenderer';
+import { getLocations } from '../saga';
+import {
+ availableFilterSettingsSelector,
+ mapFilterSettingSelector,
+ setMapFilterHideAll,
+ setMapFilterSetting,
+ setMapFilterShowAll,
+} from './mapFilterSettingSlice';
+import {
+ hookFormPersistedPathsSetSelector,
+ hookFormPersistSelector,
+ resetAndUnLockFormData,
+ setPersistedPaths,
+ upsertFormData,
+} from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import LocationSelectionModal from './LocationSelectionModal';
+import { useMaxZoom } from './useMaxZoom';
+
+export default function Map({ history }) {
+ const windowInnerHeight = useWindowInnerHeight();
+ const { farm_name, grid_points, is_admin, farm_id } = useSelector(userFarmSelector);
+ const filterSettings = useSelector(mapFilterSettingSelector);
+ const showedSpotlight = useSelector(showedSpotlightSelector);
+ const roadview = !filterSettings.map_background;
+ const dispatch = useDispatch();
+ const system = useSelector(measurementSelector);
+ const overlayData = useSelector(hookFormPersistSelector);
+
+ const lineTypesWithWidth = [locationEnum.buffer_zone, locationEnum.watercourse];
+ const { t } = useTranslation();
+ const showHeader = useSelector(setShowSuccessHeaderSelector);
+ const [showSuccessHeader, setShowSuccessHeader] = useState(false);
+ const [showZeroAreaWarning, setZeroAreaWarning] = useState(false);
+ const successMessage = useSelector(setSuccessMessageSelector);
+
+ const [showingConfirmButtons, setShowingConfirmButtons] = useState(
+ history?.location?.state?.hideLocationPin ?? false,
+ );
+
+ const initialLineData = {
+ [locationEnum.watercourse]: {
+ width: 1,
+ buffer_width: 15,
+ },
+ [locationEnum.buffer_zone]: {
+ width: 8,
+ },
+ };
+ const persistedPathsSet = useSelector(hookFormPersistedPathsSetSelector);
+ useEffect(() => {
+ return () => {
+ persistedPathsSet.size &&
+ !persistedPathsSet.has(history.location.pathname) &&
+ dispatch(resetAndUnLockFormData());
+ };
+ }, [persistedPathsSet]);
+ useEffect(() => {
+ if (!history.location.state?.isStepBack) {
+ dispatch(resetAndUnLockFormData());
+ }
+ return () => {
+ dispatch(canShowSuccessHeader(false));
+ };
+ }, []);
+
+ const [
+ drawingState,
+ {
+ initDrawingState,
+ startDrawing,
+ finishDrawing,
+ resetDrawing,
+ closeDrawer,
+ getOverlayInfo,
+ reconstructOverlay,
+ setLineWidth,
+ setShowAdjustAreaSpotlightModal,
+ setShowAdjustLineSpotlightModal,
+ },
+ ] = useDrawingManager();
+
+ useEffect(() => {
+ dispatch(getLocations());
+ }, []);
+
+ useEffect(() => {
+ if (showHeader) setShowSuccessHeader(true);
+ }, [showHeader]);
+
+ const [showMapFilter, setShowMapFilter] = useState(false);
+ const [showAddDrawer, setShowAddDrawer] = useState(false);
+ const [showExportModal, setShowExportModal] = useState(false);
+ const [showDrawAreaSpotlightModal, setShowDrawAreaSpotlightModal] = useState(false);
+ const [showDrawLineSpotlightModal, setShowDrawLineSpotlightModal] = useState(false);
+
+ const getMapOptions = (maps) => {
+ return {
+ styles: [
+ {
+ featureType: 'poi.business',
+ elementType: 'labels',
+ stylers: [
+ {
+ visibility: 'off',
+ },
+ ],
+ },
+ ],
+ gestureHandling: 'greedy',
+ disableDoubleClickZoom: false,
+ minZoom: 1,
+ maxZoom: 80,
+ tilt: 0,
+ mapTypeId: !roadview ? maps.MapTypeId.SATELLITE : maps.MapTypeId.ROADMAP,
+ mapTypeControlOptions: {
+ style: maps.MapTypeControlStyle.HORIZONTAL_BAR,
+ position: maps.ControlPosition.BOTTOM_CENTER,
+ mapTypeIds: [maps.MapTypeId.ROADMAP, maps.MapTypeId.SATELLITE],
+ },
+ clickableIcons: false,
+ streetViewControl: false,
+ scaleControl: false,
+ mapTypeControl: false,
+ panControl: false,
+ zoomControl: false,
+ rotateControl: false,
+ fullscreenControl: false,
+ };
+ };
+ const { drawAssets } = useMapAssetRenderer({
+ isClickable: !drawingState.type,
+ drawingState: drawingState,
+ showingConfirmButtons: showingConfirmButtons,
+ });
+ const { getMaxZoom } = useMaxZoom();
+ const handleGoogleMapApi = (map, maps) => {
+ getMaxZoom(maps);
+ maps.Polygon.prototype.getPolygonBounds = function () {
+ var bounds = new maps.LatLngBounds();
+ this.getPath().forEach(function (element, index) {
+ bounds.extend(element);
+ });
+ return bounds;
+ };
+ maps.Polygon.prototype.getAveragePoint = function () {
+ const latLngArray = this.getPath().getArray();
+ let latSum = 0;
+ let lngSum = 0;
+ for (const latLng of latLngArray) {
+ latSum += latLng.lat();
+ lngSum += latLng.lng();
+ }
+ return new maps.LatLng(latSum / latLngArray.length, lngSum / latLngArray.length);
+ };
+
+ // Create drawing manager
+ let drawingManagerInit = new maps.drawing.DrawingManager({
+ drawingMode: null,
+ drawingControl: false,
+ drawingControlOptions: {
+ position: maps.ControlPosition.TOP_CENTER,
+ drawingModes: [
+ maps.drawing.OverlayType.POLYGON,
+ maps.drawing.OverlayType.POLYLINE,
+ maps.drawing.OverlayType.MARKER,
+ ],
+ },
+ map: map,
+ });
+
+ maps.event.addListener(drawingManagerInit, 'polygoncomplete', function (polygon) {
+ const polygonAreaCheck = (path) => {
+ if (Math.round(maps.geometry.spherical.computeArea(path)) === 0) setZeroAreaWarning(true);
+ else setZeroAreaWarning(false);
+ };
+ const path = polygon.getPath();
+ polygonAreaCheck(path);
+ maps.event.addListener(path, 'set_at', function () {
+ polygonAreaCheck(this);
+ });
+ maps.event.addListener(path, 'insert_at', function () {
+ polygonAreaCheck(this);
+ });
+ });
+ maps.event.addListener(drawingManagerInit, 'overlaycomplete', function (drawing) {
+ setShowingConfirmButtons(true);
+ finishDrawing(drawing, maps, map);
+ this.setDrawingMode();
+ });
+ initDrawingState(map, maps, drawingManagerInit, {
+ POLYGON: maps.drawing.OverlayType.POLYGON,
+ POLYLINE: maps.drawing.OverlayType.POLYLINE,
+ MARKER: maps.drawing.OverlayType.MARKER,
+ });
+
+ // Adding custom map components
+ const zoomControlDiv = document.createElement('div');
+ ReactDOM.render(
+ map.setZoom(map.getZoom() + 1)}
+ onClickZoomOut={() => map.setZoom(map.getZoom() - 1)}
+ />,
+ zoomControlDiv,
+ );
+ map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(zoomControlDiv);
+
+ const compassControlDiv = document.createElement('div');
+ ReactDOM.render( , compassControlDiv);
+ map.controls[maps.ControlPosition.RIGHT_BOTTOM].push(compassControlDiv);
+
+ // Drawing locations on map
+ let mapBounds = new maps.LatLngBounds();
+ drawAssets(map, maps, mapBounds);
+
+ if (history.location.state?.isStepBack) {
+ reconstructOverlay();
+ }
+
+ if (history.location.state?.cameraInfo) {
+ const { zoom, location } = history.location.state.cameraInfo;
+ if (zoom && location) {
+ map.setZoom(zoom);
+ map.setCenter(location);
+ }
+ }
+ };
+
+ const handleClickAdd = () => {
+ setShowExportModal(false);
+ setShowMapFilter(false);
+ setShowAddDrawer(!showAddDrawer);
+ };
+
+ const handleClickExport = () => {
+ setShowExportModal(!showExportModal);
+ setShowMapFilter(false);
+ setShowAddDrawer(false);
+ };
+
+ const handleClickFilter = () => {
+ setShowExportModal(false);
+ setShowAddDrawer(false);
+ setShowMapFilter(!showMapFilter);
+ };
+
+ const handleFilterMenuClick = (locationType) => {
+ if (locationType === 'show_all') {
+ dispatch(setMapFilterShowAll(farm_id));
+ } else if (locationType === 'hide_all') {
+ dispatch(setMapFilterHideAll(farm_id));
+ } else {
+ const payload = {};
+ payload[locationType] = !filterSettings[locationType];
+ payload.farm_id = farm_id;
+ dispatch(setMapFilterSetting(payload));
+ }
+ };
+
+ const availableFilterSettings = useSelector(availableFilterSettingsSelector);
+
+ const handleAddMenuClick = (locationType) => {
+ setZeroAreaWarning(false);
+ if (isArea(locationType) && !showedSpotlight.draw_area) {
+ setShowDrawAreaSpotlightModal(true);
+ } else if (isLine(locationType) && !showedSpotlight.draw_line) {
+ setShowDrawLineSpotlightModal(true);
+ }
+ isLineWithWidth(locationType) && dispatch(upsertFormData(initialLineData[locationType]));
+ const submitPath = `/create_location/${locationType}`;
+ dispatch(setPersistedPaths([submitPath, '/map']));
+ startDrawing(locationType);
+ };
+
+ const mapWrapperRef = useRef();
+
+ const handleShowVideo = () => {
+ history.push('/map/videos');
+ };
+
+ const handleCloseSuccessHeader = () => {
+ dispatch(canShowSuccessHeader(false));
+ setShowSuccessHeader(false);
+ };
+
+ const handleDownload = () => {
+ html2canvas(mapWrapperRef.current, { useCORS: true }).then((canvas) => {
+ canvas.toBlob((blob) => {
+ saveAs(blob, `${farm_name}-export-${new Date().toISOString()}.png`);
+ });
+ });
+ };
+
+ const handleShare = () => {
+ html2canvas(mapWrapperRef.current, { useCORS: true }).then((canvas) => {
+ const fileDataURL = canvas.toDataURL();
+ dispatch(sendMapToEmail(fileDataURL));
+ });
+ };
+
+ const handleConfirm = () => {
+ setShowingConfirmButtons(false);
+ if (!isLineWithWidth()) {
+ const locationData = getOverlayInfo();
+ dispatch(upsertFormData(locationData));
+ history.push(`/create_location/${drawingState.type}`);
+ }
+ };
+
+ const handleLineConfirm = (lineData) => {
+ setShowingConfirmButtons(false);
+ const data = { ...getOverlayInfo(), ...lineData };
+ dispatch(upsertFormData(data));
+ history.push(`/create_location/${drawingState.type}`);
+ };
+
+ const isLineWithWidth = (type = drawingState.type) => {
+ return lineTypesWithWidth.includes(type);
+ };
+
+ const { showAdjustAreaSpotlightModal, showAdjustLineSpotlightModal } = drawingState;
+ return (
+ <>
+ {!showMapFilter && !showAddDrawer && !drawingState.type && !showSuccessHeader && (
+
+ )}
+ {showSuccessHeader && (
+
+ )}
+
+
+
+ handleGoogleMapApi(map, maps)}
+ options={getMapOptions}
+ />
+
+ {drawingState.type && (
+
+ {
+ setZeroAreaWarning(false);
+ resetDrawing(true);
+ dispatch(resetAndUnLockFormData());
+ closeDrawer();
+ setShowingConfirmButtons(false);
+ }}
+ onClickTryAgain={() => {
+ setZeroAreaWarning(false);
+ resetDrawing();
+ startDrawing(drawingState.type);
+ setShowingConfirmButtons(false);
+ }}
+ onClickConfirm={handleConfirm}
+ showZeroAreaWarning={showZeroAreaWarning}
+ confirmLine={handleLineConfirm}
+ updateLineWidth={setLineWidth}
+ system={system}
+ lineData={overlayData}
+ typeOfLine={drawingState.type}
+ />
+
+ )}
+
+
+
+ {!drawingState.type && (
+
dispatch(setSpotlightToShown('map'))}
+ onClickAdd={handleClickAdd}
+ onClickExport={handleClickExport}
+ showModal={showExportModal}
+ setShowMapFilter={setShowMapFilter}
+ showMapFilter={showMapFilter}
+ setShowAddDrawer={setShowAddDrawer}
+ showAddDrawer={showAddDrawer}
+ handleClickFilter={handleClickFilter}
+ filterSettings={filterSettings}
+ onFilterMenuClick={handleFilterMenuClick}
+ onAddMenuClick={handleAddMenuClick}
+ availableFilterSettings={availableFilterSettings}
+ />
+ )}
+ {showExportModal && (
+ setShowExportModal(false)}
+ />
+ )}
+ {showDrawAreaSpotlightModal && (
+ {
+ setShowDrawAreaSpotlightModal(false);
+ dispatch(setSpotlightToShown('draw_area'));
+ }}
+ />
+ )}
+ {showDrawLineSpotlightModal && (
+ {
+ setShowDrawLineSpotlightModal(false);
+ dispatch(setSpotlightToShown('draw_line'));
+ }}
+ />
+ )}
+ {showAdjustAreaSpotlightModal && (
+ {
+ setShowAdjustAreaSpotlightModal(false);
+ dispatch(setSpotlightToShown('adjust_area'));
+ }}
+ />
+ )}
+ {showAdjustLineSpotlightModal && (
+ {
+ setShowAdjustLineSpotlightModal(false);
+ dispatch(setSpotlightToShown('adjust_line'));
+ }}
+ />
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Map/saga.js b/packages/webapp/src/containers/Map/saga.js
index 98b3e60828..5b5e980692 100644
--- a/packages/webapp/src/containers/Map/saga.js
+++ b/packages/webapp/src/containers/Map/saga.js
@@ -56,16 +56,18 @@ export function* sendMapToEmailSaga({ payload: fileDataURL }) {
export const setSpotlightToShown = createAction(`setSpotlightToShownSaga`);
-export function* setSpotlightToShownSaga({ payload: spotlight }) {
+export function* setSpotlightToShownSaga({ payload: spotlights }) {
try {
const { user_id } = yield select(loginSelector);
const header = getHeader(user_id);
let patchContent = {};
- patchContent[spotlight] = true;
- patchContent[`${spotlight}_end`] = new Date().toISOString();
- yield put(spotlightLoading());
- yield put(patchSpotlightFlagsSuccess({ [spotlight]: true }));
- const result = yield call(axios.patch, showedSpotlightUrl(), patchContent, header);
+ for (const spotlight of spotlights) {
+ patchContent[spotlight] = true;
+ patchContent[`${spotlight}_end`] = new Date().toISOString();
+ yield put(spotlightLoading());
+ yield put(patchSpotlightFlagsSuccess({ [spotlight]: true }));
+ }
+ yield call(axios.patch, showedSpotlightUrl(), patchContent, header);
} catch (error) {
yield put(patchSpotlightFlagsFailure());
console.log('failed to patch spotlight flags');
diff --git a/packages/webapp/src/containers/Map/styles.module.scss b/packages/webapp/src/containers/Map/styles.module.scss
index 50d84a2213..6ceedc83bd 100644
--- a/packages/webapp/src/containers/Map/styles.module.scss
+++ b/packages/webapp/src/containers/Map/styles.module.scss
@@ -48,11 +48,6 @@
height: 100%;
}
-.mapFooter {
- order: 3;
- z-index: 101;
-}
-
:export {
primaryColour: #349289;
defaultColour: #ffffff;
@@ -141,3 +136,7 @@
align-items: center;
}
+.farmPointLabel {
+ position: relative;
+ margin-top: 50px;
+}
diff --git a/packages/webapp/src/containers/Map/useMapAssetRenderer.js b/packages/webapp/src/containers/Map/useMapAssetRenderer.js
index d856c745e8..fcf79a2dd5 100644
--- a/packages/webapp/src/containers/Map/useMapAssetRenderer.js
+++ b/packages/webapp/src/containers/Map/useMapAssetRenderer.js
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
import styles, { defaultColour } from './styles.module.scss';
import { areaStyles, hoverIcons, icons, lineStyles } from './mapStyles';
import { useEffect, useRef, useState } from 'react';
@@ -18,11 +33,14 @@ import useSelectionHandler from './useSelectionHandler';
import MarkerClusterer from '@googlemaps/markerclustererplus';
import { useMaxZoom } from './useMaxZoom';
+import MapPin from '../../assets/images/map/map_pin.svg';
+import { userFarmSelector } from '../userFarmSlice';
+
/**
*
* Do not modify, copy or reuse
*/
-const useMapAssetRenderer = ({ isClickable }) => {
+const useMapAssetRenderer = ({ isClickable, showingConfirmButtons, drawingState }) => {
const { handleSelection, dismissSelectionModal } = useSelectionHandler();
const dispatch = useDispatch();
const filterSettings = useSelector(mapFilterSettingSelector);
@@ -34,6 +52,9 @@ const useMapAssetRenderer = ({ isClickable }) => {
return nextAssetGeometries;
};
+ const [farmLocationMarker, setFarmLocationMarker] = useState(null);
+ const [farmMap, setFarmMap] = useState();
+
const [assetGeometries, setAssetGeometries] = useState(initAssetGeometriesState());
//TODO get prev filter state from redux
const [prevFilterState, setPrevFilterState] = useState(filterSettings);
@@ -78,13 +99,14 @@ const useMapAssetRenderer = ({ isClickable }) => {
const areaAssets = useSelector(sortedAreaSelector);
const lineAssets = useSelector(lineSelector);
const pointAssets = useSelector(pointSelector);
+ const { grid_points } = useSelector(userFarmSelector);
const assetFunctionMap = (assetType) => {
- return !!isArea(assetType)
+ return isArea(assetType)
? isNoFillArea(assetType)
? drawNoFillArea
: drawArea
- : !!isLine(assetType)
+ : isLine(assetType)
? drawLine
: drawPoint;
};
@@ -158,6 +180,16 @@ const useMapAssetRenderer = ({ isClickable }) => {
markerClusterRef.current = markerCluster;
};
+ useEffect(() => {
+ if (drawingState.isActive) {
+ farmLocationMarker?.setMap(null);
+ } else if (showingConfirmButtons) {
+ farmLocationMarker?.setMap(null);
+ } else {
+ farmLocationMarker?.setMap(farmMap ?? null);
+ }
+ }, [drawingState.isActive, showingConfirmButtons, farmLocationMarker]);
+
const drawAssets = (map, maps, mapBounds) => {
maps.event.addListenerOnce(map, 'idle', function () {
markerClusterRef?.current?.repaint();
@@ -178,6 +210,19 @@ const useMapAssetRenderer = ({ isClickable }) => {
);
hasLocation = assetsWithLocations.length > 0;
+ if (!hasLocation) {
+ setFarmMap(map);
+ const locationMarker = new maps.Marker({
+ icon: MapPin,
+ position: grid_points,
+ map: map,
+ clickable: false,
+ crossOnDrag: false,
+ });
+ setFarmLocationMarker(locationMarker);
+ mapBounds.extend(grid_points);
+ }
+
assetsWithLocations.forEach((idx) => {
const locationType = assets[idx].type !== undefined ? assets[idx].type : idx;
assets[idx].type === undefined
diff --git a/packages/webapp/src/containers/Navigation/Alert/alertSlice.js b/packages/webapp/src/containers/Navigation/Alert/alertSlice.js
new file mode 100644
index 0000000000..01e40b5d78
--- /dev/null
+++ b/packages/webapp/src/containers/Navigation/Alert/alertSlice.js
@@ -0,0 +1,51 @@
+import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
+import { loginSelector } from '../../userFarmSlice';
+import { createSelector } from 'reselect';
+
+// Generate a set of reusable reducers and selectors to manage normalized store data.
+const alertAdapter = createEntityAdapter({
+ selectId: (alert) => alert.farm_id,
+});
+
+// Given an initial state, object full of case reducers (for specific action types), and slice name,
+// generate a slice reducer with action creators, types corresponding to the reducers and state.
+const alertSlice = createSlice({
+ name: 'alertReducer',
+ initialState: alertAdapter.getInitialState(),
+ reducers: {
+ onLoadingAlertStart: (state, { payload: farm_id }) => {
+ alertAdapter.upsertOne(state, { farm_id, loading: true });
+ },
+ onLoadingAlertFail: (state, { payload: { error, farm_id } }) => {
+ alertAdapter.upsertOne(state, { farm_id, loading: false, loaded: true, error });
+ },
+ setAlertCount: (state, { payload }) => {
+ alertAdapter.upsertOne(state, {
+ loading: false,
+ error: null,
+ loaded: true,
+ ...payload,
+ });
+ },
+ },
+});
+
+export const { onLoadingAlertStart, onLoadingAlertFail, setAlertCount } = alertSlice.actions;
+
+export default alertSlice.reducer;
+
+export const alertReducerSelector = (state) => state.entitiesReducer[alertSlice.name];
+
+const alertSelectors = alertAdapter.getSelectors((state) => state.entitiesReducer[alertSlice.name]);
+
+// A component will re-render only when the selector's value has changed.
+// Create a selector that ...
+export const alertSelector = createSelector(
+ // ... calls these selectors ...
+ [alertSelectors.selectEntities, loginSelector],
+ // ... and passes the results to this ...
+ (alertEntities, { farm_id }) => {
+ // ... so that we re-render when there are changes to the alert entities.
+ return alertEntities[farm_id] || {};
+ },
+);
diff --git a/packages/webapp/src/containers/Navigation/Alert/index.jsx b/packages/webapp/src/containers/Navigation/Alert/index.jsx
new file mode 100644
index 0000000000..8b64012632
--- /dev/null
+++ b/packages/webapp/src/containers/Navigation/Alert/index.jsx
@@ -0,0 +1,17 @@
+import React, { useEffect } from 'react';
+import PureAlert from '../../../components/Navigation/NavBar/Alert';
+import { useDispatch, useSelector } from 'react-redux';
+import { alertSelector } from './alertSlice';
+import { getAlert } from './saga';
+
+export default function Alert() {
+ const { error, loaded, count } = useSelector(alertSelector);
+ const dispatch = useDispatch();
+ useEffect(() => {
+ dispatch(getAlert());
+ }, []);
+
+ return loaded && !error && count ? : ;
+}
+
+Alert.propTypes = {};
diff --git a/packages/webapp/src/containers/Navigation/Alert/saga.js b/packages/webapp/src/containers/Navigation/Alert/saga.js
new file mode 100644
index 0000000000..f480c7f8c1
--- /dev/null
+++ b/packages/webapp/src/containers/Navigation/Alert/saga.js
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+import { take, put, call, select, takeLatest } from 'redux-saga/effects';
+import { createAction } from '@reduxjs/toolkit';
+import { eventChannel, END } from 'redux-saga';
+import { axios, getHeader } from '../../saga';
+import { userFarmSelector } from '../../userFarmSlice';
+import {
+ setAlertCount,
+ onLoadingAlertFail,
+ onLoadingAlertStart,
+ alertSelector,
+} from './alertSlice';
+import { notificationsUrl, alertsUrl } from '../../../apiConfig';
+import { v4 as uuidv4 } from 'uuid';
+
+let channel;
+let subscribedFarmId;
+
+function subscribeToChannel(sseUrl) {
+ return eventChannel((emitter) => {
+ const subscription = new EventSource(sseUrl);
+
+ subscription.onmessage = (event) => {
+ const alert = JSON.parse(event.data);
+ emitter(alert);
+ };
+
+ const unsubscribe = () => {
+ subscription.close();
+ channel = undefined;
+ };
+
+ return unsubscribe;
+ });
+}
+
+function getNotifications(user_id, farm_id) {
+ return axios.get(notificationsUrl, getHeader(user_id, farm_id));
+}
+
+function countAlerts(notifications) {
+ return notifications.reduce((prev, notification) => prev + (notification.alert ? 1 : 0), 0);
+}
+
+export const getAlert = createAction('getAlertSaga');
+
+export function* getAlertSaga() {
+ let subscriberId = localStorage.getItem('subscriberId');
+ if (!subscriberId) {
+ subscriberId = uuidv4();
+ localStorage.setItem('subscriberId', subscriberId);
+ }
+
+ let farm_id, user_id;
+ try {
+ while (true) {
+ const userFarm = yield select(userFarmSelector);
+ farm_id = userFarm.farm_id;
+ user_id = userFarm.user_id;
+
+ // Tell the store this saga is loading.
+ yield put(onLoadingAlertStart(farm_id));
+
+ // Set up subscription to server-sent events.
+ if (!channel || farm_id !== subscribedFarmId) {
+ if (channel) channel.close();
+ subscribedFarmId = farm_id;
+ channel = yield call(
+ subscribeToChannel,
+ `${alertsUrl}?user_id=${user_id}&farm_id=${farm_id}&subscriber_id=${subscriberId}`,
+ );
+ }
+
+ // Call API to get notifications; count alerts and store result
+ const notifications = yield call(getNotifications, user_id, farm_id);
+ const count = countAlerts(notifications.data);
+ yield put(setAlertCount({ farm_id, count }));
+
+ try {
+ while (true) {
+ // For each server-sent event, update the alert count.
+ const { count } = yield select(alertSelector);
+ const message = yield take(channel);
+ yield put(setAlertCount({ farm_id, count: Math.max(0, count + message.delta) }));
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ } catch (error) {
+ yield put(onLoadingAlertFail({ error, farm_id }));
+ console.log(error);
+ }
+}
+
+export default function* alertSaga() {
+ yield takeLatest(getAlert.type, getAlertSaga);
+}
diff --git a/packages/webapp/src/containers/Navigation/ProfileFloater.test.js b/packages/webapp/src/containers/Navigation/ProfileFloater.test.js
deleted file mode 100644
index f91916bb95..0000000000
--- a/packages/webapp/src/containers/Navigation/ProfileFloater.test.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react';
-import { render, fireEvent, screen, act } from '@testing-library/react';
-import '@testing-library/jest-dom';
-import PureProfileFloater from '../../components/ProfileFloater';
-
-describe('Profile Floater Container', () => {
- it('should render properly', () => {
- render(
-
- Test
- ,
- );
- expect(screen.getByText(/test/i)).toBeDefined();
- });
-
- it('should call logout on logout click', () => {
- const logout = jest.fn();
- render(
-
- test
- ,
- );
- act(() => {
- fireEvent.click(screen.getByText(/test/i));
- });
- expect(screen.getByText(/log out/i)).toBeDefined();
- act(() => {
- fireEvent.click(screen.getByText(/log out/i));
- });
- expect(logout).toHaveBeenCalled();
- });
-});
diff --git a/packages/webapp/src/containers/Navigation/index.js b/packages/webapp/src/containers/Navigation/index.js
deleted file mode 100644
index c1ca4851fb..0000000000
--- a/packages/webapp/src/containers/Navigation/index.js
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Suspense } from 'react';
-import { connect } from 'react-redux';
-import NoFarmNavBar from '../../components/Navigation/NoFarmNavBar';
-
-import { chooseFarmFlowSelector } from '../ChooseFarm/chooseFarmFlowSlice';
-import PureNavBar from '../../components/Navigation/NavBar';
-import { isAdminSelector, userFarmLengthSelector, userFarmSelector } from '../userFarmSlice';
-import { isAuthenticated } from '../../util/jwt';
-import { showedSpotlightSelector } from '../showedSpotlightSlice';
-import { setSpotlightToShown } from '../Map/saga';
-
-const NavBar = (props) => {
- const { history, farm, farmState, dispatch, numberOfUserFarm, isAdmin, showedSpotlight } = props;
- const { isInvitationFlow } = farmState;
- const { navigation } = showedSpotlight;
- const isFarmSelected =
- isAuthenticated() && farm && farm.has_consent && farm?.step_five === true && !isInvitationFlow;
- const resetSpotlight = () => {
- dispatch(setSpotlightToShown('navigation'));
- };
- return isFarmSelected ? (
- }>
- 1}
- history={history}
- showFinances={isAdmin}
- />
-
- ) : (
-
- );
-};
-
-const mapStateToProps = (state) => {
- return {
- farm: userFarmSelector(state),
- farmState: chooseFarmFlowSelector(state),
- numberOfUserFarm: userFarmLengthSelector(state),
- isAdmin: isAdminSelector(state),
- showedSpotlight: showedSpotlightSelector(state),
- };
-};
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(NavBar);
diff --git a/packages/webapp/src/containers/Navigation/index.jsx b/packages/webapp/src/containers/Navigation/index.jsx
new file mode 100644
index 0000000000..fa07e808be
--- /dev/null
+++ b/packages/webapp/src/containers/Navigation/index.jsx
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React, { Suspense } from 'react';
+import { connect } from 'react-redux';
+import NoFarmNavBar from '../../components/Navigation/NoFarmNavBar';
+
+import { chooseFarmFlowSelector } from '../ChooseFarm/chooseFarmFlowSlice';
+import PureNavBar from '../../components/Navigation/NavBar';
+import { isAdminSelector, userFarmLengthSelector, userFarmSelector } from '../userFarmSlice';
+import { isAuthenticated } from '../../util/jwt';
+import { showedSpotlightSelector } from '../showedSpotlightSlice';
+import { setSpotlightToShown } from '../Map/saga';
+
+const NavBar = (props) => {
+ const { history, farm, farmState, dispatch, numberOfUserFarm, isAdmin, showedSpotlight } = props;
+ const { isInvitationFlow } = farmState;
+ const { navigation, notification } = showedSpotlight;
+ const isFarmSelected =
+ isAuthenticated() && farm && farm.has_consent && farm?.step_five === true && !isInvitationFlow;
+ const resetSpotlight = () => {
+ dispatch(setSpotlightToShown(['notification', 'navigation']));
+ };
+
+ return isFarmSelected ? (
+ }>
+ 1}
+ history={history}
+ showFinances={isAdmin}
+ />
+
+ ) : (
+
+ );
+};
+
+const mapStateToProps = (state) => {
+ return {
+ farm: userFarmSelector(state),
+ farmState: chooseFarmFlowSelector(state),
+ numberOfUserFarm: userFarmLengthSelector(state),
+ isAdmin: isAdminSelector(state),
+ showedSpotlight: showedSpotlightSelector(state),
+ };
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return {
+ dispatch,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(NavBar);
diff --git a/packages/webapp/src/containers/Navigation/navbarSlice.js b/packages/webapp/src/containers/Navigation/navbarSlice.js
deleted file mode 100644
index 095dd45400..0000000000
--- a/packages/webapp/src/containers/Navigation/navbarSlice.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { createSlice } from '@reduxjs/toolkit';
-import { createSelector } from 'reselect';
-// import { getDateInputFormat } from '../util/moment';
-
-export const initialState = {
- introducingCertifications: false,
-};
-
-const navbarSliceReducer = createSlice({
- name: 'navbarReducer',
- initialState,
- reducers: {
- resetReducer: (state) => initialState,
- setIntroducingCertifications: (state, { payload: introducingCertifications }) => {
- state.introducingCertifications = introducingCertifications;
- },
- },
-});
-
-export const { resetReducer, setIntroducingCertifications } = navbarSliceReducer.actions;
-export default navbarSliceReducer.reducer;
-
-const navbarReducerSelector = (state) => {
- return state?.tempStateReducer[navbarSliceReducer.name];
-};
-
-export const isIntroducingCertificationsSelector = createSelector(
- [navbarReducerSelector],
- (navbarReducer) => navbarReducer.introducingCertifications,
-);
diff --git a/packages/webapp/src/containers/Notification/NotificationCard/index.jsx b/packages/webapp/src/containers/Notification/NotificationCard/index.jsx
new file mode 100644
index 0000000000..e0111aedd1
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/NotificationCard/index.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { PureNotificationCard } from '../../../components/Card/NotificationCard/NotificationCard';
+
+const NotificationCard = ({
+ alert,
+ status,
+ title,
+ body,
+ variables,
+ context,
+ created_at,
+ onClick,
+ classes = { card: {} },
+ ...props
+}) => {
+ return (
+ <>
+
+ >
+ );
+};
+
+NotificationCard.propTypes = {
+ alert: PropTypes.bool,
+ status: PropTypes.oneOf(['Unread', 'Read', 'Archived']),
+ translation_key: PropTypes.string,
+ variables: PropTypes.array,
+ context: PropTypes.object,
+ onClick: PropTypes.func,
+};
+
+export default NotificationCard;
diff --git a/packages/webapp/src/containers/Notification/NotificationReadOnly/index.jsx b/packages/webapp/src/containers/Notification/NotificationReadOnly/index.jsx
new file mode 100644
index 0000000000..9058beea64
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/NotificationReadOnly/index.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import PureNotificationReadOnly from '../../../components/Notifications';
+import { notificationSelector } from '../../notificationSlice';
+
+export default function NotificationReadOnly({ history, match }) {
+ const { notification_id } = match.params;
+ const notification = useSelector(notificationSelector(notification_id));
+ const onGoBack = () => {
+ history.push('/notifications');
+ };
+
+ return (
+ <>
+
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/Notification/constants.js b/packages/webapp/src/containers/Notification/constants.js
new file mode 100644
index 0000000000..4e24542f8f
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/constants.js
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+// Notification Types:
+export const WEEKLY_UNASSIGNED_TASKS = 'WEEKLY_UNASSIGNED_TASKS';
+export const DAILY_TASKS_DUE_TODAY = 'DAILY_TASKS_DUE_TODAY';
diff --git a/packages/webapp/src/containers/Notification/index.jsx b/packages/webapp/src/containers/Notification/index.jsx
new file mode 100644
index 0000000000..bc6819e1cd
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/index.jsx
@@ -0,0 +1,91 @@
+import Layout from '../../components/Layout';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../components/PageTitle/v2';
+import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
+import { Semibold } from '../../components/Typography';
+import { useDispatch, useSelector } from 'react-redux';
+import React, { useEffect, useState } from 'react';
+import { notificationsSelector } from '../notificationSlice';
+import NotificationCard from './NotificationCard';
+import { getNotification, readNotification, clearAlerts } from './saga';
+import useStringFilteredNotifications from './useStringFilteredNotifications';
+
+/**
+ * Renders a list view of notification cards.
+ * @param {} param0
+ * @returns {ReactComponent}
+ */
+export default function NotificationPage() {
+ const { t } = useTranslation();
+
+ // Get the data.
+ const cardContents = useSelector(notificationsSelector);
+
+ const dispatch = useDispatch();
+ useEffect(() => {
+ dispatch(getNotification());
+ }, []);
+
+ const [filterString, setFilterString] = useState('');
+ const filterStringOnChange = (e) => setFilterString(e.target.value);
+ const notifications = useStringFilteredNotifications(cardContents, filterString);
+ const alertIds = notifications
+ .filter((notification) => notification.alert)
+ .map((notification) => notification.notification_id);
+ if (alertIds.length) dispatch(clearAlerts(alertIds));
+
+ return (
+
+
+
+
+
+ {notifications.length > 0 ? (
+ notifications
+ .sort((a, b) => {
+ return new Date(b.created_at) - new Date(a.created_at);
+ })
+ .map((notification) => {
+ return (
+ dispatch(readNotification(notification.notification_id))}
+ {...notification}
+ />
+ );
+ })
+ ) : (
+
+ {t('NOTIFICATION.NONE_TO_DISPLAY')}
+
+ )}
+
+ );
+}
+
+/**
+ * @typedef Notification
+ * @desc The data for a notification sent to the current user.
+ * @type {object}
+ * @property {uuid} notification_id - A unique identifier for the object.
+ * @property {boolean} alert - Indicates if the notification is being presented to the user for the first time.
+ * @property {userNotificationStatusType} status - The notification's status.
+ * @property {string} translation_key - The translation key for the notification, which must contain subkeys for the title and body.
+ * @property {InterpolationVariable[]} variables - An array of translation interpolation variables.
+ * @property {string} entity_type - The type of entity that the notification refers to, e.g., 'task'.
+ * @property {string} entity_id - A unique identifier for the specific entity_type instance that the notification refers to.
+ * @property {object} context - A dictionary of context-specific data for the notification.
+ * @property {string} created_at - The creation time of the notification.
+ */
diff --git a/packages/webapp/src/containers/Notification/saga.js b/packages/webapp/src/containers/Notification/saga.js
new file mode 100644
index 0000000000..27c45c9382
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/saga.js
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+import { put, call, select, takeEvery } from 'redux-saga/effects';
+import { createAction } from '@reduxjs/toolkit';
+import { axios, getHeader } from '../saga';
+import { userFarmSelector } from '../userFarmSlice';
+import {
+ onLoadingNotificationStart,
+ getNotificationSuccess /*, clearAlerts as clearAlertsReducer*/,
+} from '../notificationSlice';
+import { notificationsUrl, clearAlertsUrl } from '../../apiConfig';
+import history from '../../history';
+
+export const getNotification = createAction('getNotificationSaga');
+
+export function* getNotificationSaga() {
+ const { user_id, farm_id } = yield select(userFarmSelector);
+ const header = getHeader(user_id, farm_id);
+ try {
+ yield put(onLoadingNotificationStart(user_id, farm_id));
+ const result = yield call(axios.get, notificationsUrl, header);
+ yield put(getNotificationSuccess(result.data));
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+export const readNotification = createAction('readNotificationSaga');
+
+export function* readNotificationSaga({ payload }) {
+ const { user_id, farm_id } = yield select(userFarmSelector);
+ const header = getHeader(user_id, farm_id);
+ try {
+ yield call(
+ axios.patch,
+ notificationsUrl,
+ { notification_ids: [payload], status: 'Read' },
+ header,
+ );
+ history.push(`/notifications/${payload}/read_only`);
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+export const clearAlerts = createAction('clearAlertsSaga');
+
+export function* clearAlertsSaga({ payload }) {
+ const { user_id, farm_id } = yield select(userFarmSelector);
+ const header = getHeader(user_id, farm_id);
+ try {
+ // TODO figure out why this patch is sometimes performed more than once for single action dispatch.
+ yield call(axios.patch, clearAlertsUrl, { notification_ids: payload }, header);
+ } catch (e) {
+ console.error(e);
+ }
+}
+
+export default function* notificationSaga() {
+ yield takeEvery(getNotification.type, getNotificationSaga);
+ yield takeEvery(readNotification.type, readNotificationSaga);
+ yield takeEvery(clearAlerts.type, clearAlertsSaga);
+}
diff --git a/packages/webapp/src/containers/Notification/useStringFilteredNotifications.js b/packages/webapp/src/containers/Notification/useStringFilteredNotifications.js
new file mode 100644
index 0000000000..0f86b33b63
--- /dev/null
+++ b/packages/webapp/src/containers/Notification/useStringFilteredNotifications.js
@@ -0,0 +1,36 @@
+import { useMemo } from 'react';
+import { useTranslation } from 'react-i18next';
+
+export default function useStringFilteredNotifications(notifications, filterString) {
+ const { t } = useTranslation();
+ return useMemo(() => {
+ const lowerCaseFilter = filterString?.toLowerCase() || '';
+ const check = (names) => {
+ for (const name of names) {
+ if (
+ name
+ ?.toLowerCase()
+ .normalize('NFD')
+ .replace(/[\u0300-\u036f]/g, '')
+ .includes(lowerCaseFilter)
+ )
+ return true;
+ }
+ return false;
+ };
+
+ return notifications.filter((notification) => {
+ const tOptions = notification.variables?.reduce((optionsSoFar, currentOption) => {
+ let options = { ...optionsSoFar };
+ options[currentOption.name] = currentOption.translate
+ ? t(currentOption.value)
+ : currentOption.value;
+ return options;
+ }, {});
+ return check([
+ t(notification.title.translation_key),
+ t(notification.body.translation_key, tOptions),
+ ]);
+ });
+ }, [notifications, filterString]);
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/OnboradingCertificationSelection.js b/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/OnboradingCertificationSelection.jsx
similarity index 100%
rename from packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/OnboradingCertificationSelection.js
rename to packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/OnboradingCertificationSelection.jsx
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.js b/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.js
deleted file mode 100644
index af2abb57d6..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import React from 'react';
-import { PureCertificationSelection } from '../../../components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection';
-import { useSelector } from 'react-redux';
-import history from '../../../history';
-import { certificationsSelector } from '../certificationSlice';
-import { certifierSurveySelector } from '../slice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useGetCertifiers } from '../useCertifiers';
-
-export default function CertificationSelection() {
- const survey = useSelector(certifierSurveySelector);
-
- const certifications = useSelector(certificationsSelector);
-
- const requestCertifierPath = '/certification/certifier/request';
- const selectCertifierPath = '/certification/certifier/selection';
- const interestedInOrganicPath = '/certification/interested_in_organic';
- const getCertifiers = useGetCertifiers();
- const onSubmit = (data) => {
- const certifiers = getCertifiers(data.certification_id);
- if (data.certification_id === 0 || certifiers.length === 0) {
- history.push(requestCertifierPath);
- } else {
- history.push(selectCertifierPath);
- }
- };
-
- const onGoBack = () => {
- history.push(interestedInOrganicPath);
- };
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.jsx
new file mode 100644
index 0000000000..f23cf738a5
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/CertificationSelection/UpdateCertificationSelection.jsx
@@ -0,0 +1,45 @@
+import React from 'react';
+import {
+ PureCertificationSelection,
+} from '../../../components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection';
+import { useSelector } from 'react-redux';
+import history from '../../../history';
+import { certificationsSelector } from '../certificationSlice';
+import { certifierSurveySelector } from '../slice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useGetCertifiers } from '../useCertifiers';
+
+export default function CertificationSelection() {
+ const survey = useSelector(certifierSurveySelector);
+
+ const certifications = useSelector(certificationsSelector);
+
+ const requestCertifierPath = '/certification/certifier/request';
+ const selectCertifierPath = '/certification/certifier/selection';
+ const interestedInOrganicPath = '/certification/interested_in_organic';
+ const getCertifiers = useGetCertifiers();
+ const onSubmit = (data) => {
+ const certifiers = getCertifiers(data.certification_id);
+ if (data.certification_id === 0 || certifiers.length === 0) {
+ history.push(requestCertifierPath);
+ } else {
+ history.push(selectCertifierPath);
+ }
+ };
+
+ const onGoBack = () => {
+ history.push(interestedInOrganicPath);
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/OnboradingCertifierSelectionMenu.js b/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/OnboradingCertifierSelectionMenu.jsx
similarity index 100%
rename from packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/OnboradingCertifierSelectionMenu.js
rename to packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/OnboradingCertifierSelectionMenu.jsx
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.js b/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.js
deleted file mode 100644
index 534b97976c..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import { PureCertifierSelectionScreen } from '../../../components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen';
-import { useDispatch, useSelector } from 'react-redux';
-import history from '../../../history';
-import { certifiersByCertificationSelector } from '../certifierSlice';
-import { certifierSurveySelector } from '../slice';
-import { setCertifierId } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { useCertificationName } from '../useCertificationName';
-
-export default function CertifierSelectionMenu() {
- const survey = useSelector(certifierSurveySelector);
- const summaryPath = '/certification/summary';
- const certificationSelectionPath = '/certification/selection';
- const requestCertifierPath = '/certification/certifier/request';
- const { persistedData } = useHookFormPersist(() => ({}), [
- summaryPath,
- certificationSelectionPath,
- requestCertifierPath,
- ]);
- const certification_id = persistedData.certification_id ?? survey.certification_id;
- const { certificationName } = useCertificationName();
- const certifiers = useSelector(certifiersByCertificationSelector(certification_id));
- const dispatch = useDispatch();
-
- const onSubmit = () => {
- history.push(summaryPath);
- };
-
- const onBack = () => {
- history.push(certificationSelectionPath);
- };
- const onRequestCertifier = () => {
- history.push(requestCertifierPath);
- };
- const onSelectCertifier = (certifier_id) => {
- dispatch(setCertifierId(certifier_id));
- };
-
- const certifier_id = persistedData.requested_certifier
- ? undefined
- : persistedData.certifier_id || survey.certifier_id;
-
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.jsx
new file mode 100644
index 0000000000..38f83f6fc4
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/CertifierSelectionMenu/UpdateCertifierSelectionMenu.jsx
@@ -0,0 +1,57 @@
+import React from 'react';
+import {
+ PureCertifierSelectionScreen,
+} from '../../../components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen';
+import { useDispatch, useSelector } from 'react-redux';
+import history from '../../../history';
+import { certifiersByCertificationSelector } from '../certifierSlice';
+import { certifierSurveySelector } from '../slice';
+import { setCertifierId } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { useCertificationName } from '../useCertificationName';
+
+export default function CertifierSelectionMenu() {
+ const survey = useSelector(certifierSurveySelector);
+ const summaryPath = '/certification/summary';
+ const certificationSelectionPath = '/certification/selection';
+ const requestCertifierPath = '/certification/certifier/request';
+ const { persistedData } = useHookFormPersist(() => ({}), [
+ summaryPath,
+ certificationSelectionPath,
+ requestCertifierPath,
+ ]);
+ const certification_id = persistedData.certification_id ?? survey.certification_id;
+ const { certificationName } = useCertificationName();
+ const certifiers = useSelector(certifiersByCertificationSelector(certification_id));
+ const dispatch = useDispatch();
+
+ const onSubmit = () => {
+ history.push(summaryPath);
+ };
+
+ const onBack = () => {
+ history.push(certificationSelectionPath);
+ };
+ const onRequestCertifier = () => {
+ history.push(requestCertifierPath);
+ };
+ const onSelectCertifier = (certifier_id) => {
+ dispatch(setCertifierId(certifier_id));
+ };
+
+ const certifier_id = persistedData.requested_certifier
+ ? undefined
+ : persistedData.certifier_id || survey.certifier_id;
+
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.js b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.js
deleted file mode 100644
index 85f4580fde..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React, { useEffect } from 'react';
-import { PureInterestedOrganic } from '../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
-import { useDispatch, useSelector } from 'react-redux';
-import history from '../../../history';
-import { certifierSurveySelector } from '../slice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { getOrganicSurveyReqBody } from '../SetCertificationSummary/utils/getOrganicSurveyReqBody';
-import {
- getAllSupportedCertifications,
- getAllSupportedCertifiers,
- getCertificationSurveys,
- postOrganicCertifierSurvey,
- putOrganicCertifierSurvey,
-} from '../saga';
-import { setInterested } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-
-export default function OnboardingInterestedOrganic() {
- const survey = useSelector(certifierSurveySelector);
- const dispatch = useDispatch();
-
- const consentPath = '/consent';
- const onGoBack = () => {
- history.push(consentPath);
- };
- const certificationSelectionPath = '/certification/selection';
- const outroPath = '/outro';
- useEffect(() => {
- dispatch(getCertificationSurveys());
- dispatch(getAllSupportedCertifications());
- dispatch(getAllSupportedCertifiers());
- }, []);
-
- const onSubmit = (data) => {
- if (data.interested) {
- dispatch(setInterested(data.interested));
- history.push(certificationSelectionPath);
- } else {
- const callback = () => history.push(outroPath);
- if (survey.survey_id) {
- dispatch(
- putOrganicCertifierSurvey({
- survey: getOrganicSurveyReqBody({
- interested: false,
- survey_id: survey.survey_id,
- }),
- callback,
- }),
- );
- } else {
- dispatch(
- postOrganicCertifierSurvey({
- survey: getOrganicSurveyReqBody({ interested: false }),
- callback,
- }),
- );
- }
- }
- };
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.jsx
new file mode 100644
index 0000000000..e67c734c9c
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/OnboardingInterestedOrganic.jsx
@@ -0,0 +1,72 @@
+import React, { useEffect } from 'react';
+import {
+ PureInterestedOrganic,
+} from '../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
+import { useDispatch, useSelector } from 'react-redux';
+import history from '../../../history';
+import { certifierSurveySelector } from '../slice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { getOrganicSurveyReqBody } from '../SetCertificationSummary/utils/getOrganicSurveyReqBody';
+import {
+ getAllSupportedCertifications,
+ getAllSupportedCertifiers,
+ getCertificationSurveys,
+ postOrganicCertifierSurvey,
+ putOrganicCertifierSurvey,
+} from '../saga';
+import { setInterested } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+
+export default function OnboardingInterestedOrganic() {
+ const survey = useSelector(certifierSurveySelector);
+ const dispatch = useDispatch();
+
+ const consentPath = '/consent';
+ const onGoBack = () => {
+ history.push(consentPath);
+ };
+ const certificationSelectionPath = '/certification/selection';
+ const outroPath = '/outro';
+ useEffect(() => {
+ dispatch(getCertificationSurveys());
+ dispatch(getAllSupportedCertifications());
+ dispatch(getAllSupportedCertifiers());
+ }, []);
+
+ const onSubmit = (data) => {
+ if (data.interested) {
+ dispatch(setInterested(data.interested));
+ history.push(certificationSelectionPath);
+ } else {
+ const callback = () => history.push(outroPath);
+ if (survey.survey_id) {
+ dispatch(
+ putOrganicCertifierSurvey({
+ survey: getOrganicSurveyReqBody({
+ interested: false,
+ survey_id: survey.survey_id,
+ }),
+ callback,
+ }),
+ );
+ } else {
+ dispatch(
+ postOrganicCertifierSurvey({
+ survey: getOrganicSurveyReqBody({ interested: false }),
+ callback,
+ }),
+ );
+ }
+ }
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.js b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.js
deleted file mode 100644
index 1343fc49ac..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import { PureInterestedOrganic } from '../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
-import { useDispatch, useSelector } from 'react-redux';
-import history from '../../../history';
-import { certifierSurveySelector } from '../slice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { getOrganicSurveyReqBody } from '../SetCertificationSummary/utils/getOrganicSurveyReqBody';
-import { putOrganicCertifierSurvey } from '../saga';
-
-export default function UpdateInterestedOrganic() {
- const survey = useSelector(certifierSurveySelector);
- const dispatch = useDispatch();
-
- const goBackPath = '/certification';
- const onGoBack = () => {
- history.push(goBackPath);
- };
- const certificationSelectionPath = '/certification/selection';
-
- const onSubmit = (data) => {
- if (data.interested) {
- history.push(certificationSelectionPath);
- } else {
- const reqBody = getOrganicSurveyReqBody({ interested: false, survey_id: survey.survey_id });
- const callback = () => history.push('/certification', { success: true });
- dispatch(putOrganicCertifierSurvey({ survey: reqBody, callback }));
- }
- };
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.jsx
new file mode 100644
index 0000000000..ac81b10517
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/InterestedOrganic/UpdateInterestedOrganic.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import {
+ PureInterestedOrganic,
+} from '../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
+import { useDispatch, useSelector } from 'react-redux';
+import history from '../../../history';
+import { certifierSurveySelector } from '../slice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { getOrganicSurveyReqBody } from '../SetCertificationSummary/utils/getOrganicSurveyReqBody';
+import { putOrganicCertifierSurvey } from '../saga';
+
+export default function UpdateInterestedOrganic() {
+ const survey = useSelector(certifierSurveySelector);
+ const dispatch = useDispatch();
+
+ const goBackPath = '/certification';
+ const onGoBack = () => {
+ history.push(goBackPath);
+ };
+ const certificationSelectionPath = '/certification/selection';
+
+ const onSubmit = (data) => {
+ if (data.interested) {
+ history.push(certificationSelectionPath);
+ } else {
+ const reqBody = getOrganicSurveyReqBody({ interested: false, survey_id: survey.survey_id });
+ const callback = () => history.push('/certification', { success: true });
+ dispatch(putOrganicCertifierSurvey({ survey: reqBody, callback }));
+ }
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/OnboardingRequestCertifier.js b/packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/OnboardingRequestCertifier.jsx
similarity index 100%
rename from packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/OnboardingRequestCertifier.js
rename to packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/OnboardingRequestCertifier.jsx
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier.js b/packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier.jsx
similarity index 100%
rename from packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier.js
rename to packages/webapp/src/containers/OrganicCertifierSurvey/RequestCertifier/UpdateRequestCertifier.jsx
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.js b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.js
deleted file mode 100644
index 5fc1aa22dc..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import React from 'react';
-import { PureSetCertificationSummary } from '../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
-import { useDispatch, useSelector } from 'react-redux';
-import { useCertificationName } from '../useCertificationName';
-import { useCertifiers } from '../useCertifiers';
-import { useCertifierName } from '../useCertifierName';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { getOrganicSurveyReqBody } from './utils/getOrganicSurveyReqBody';
-import { postOrganicCertifierSurvey, putOrganicCertifierSurvey } from '../saga';
-import { certifierSurveySelector } from '../slice';
-
-export default function OnboardingSetCertificationSummary({ history }) {
- const survey = useSelector(certifierSurveySelector);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const requestCertifierPath = '/certification/certifier/request';
- const selectCertifierPath = '/certification/certifier/selection';
- const outroPath = '/outro';
- const dispatch = useDispatch();
- const onSubmit = () => {
- const callback = () => history.push('/outro', { success: true });
- if (survey.survey_id) {
- dispatch(
- putOrganicCertifierSurvey({
- survey: getOrganicSurveyReqBody({ ...survey, ...persistedFormData }),
- callback,
- }),
- );
- } else {
- dispatch(
- postOrganicCertifierSurvey({
- survey: getOrganicSurveyReqBody(persistedFormData),
- callback,
- }),
- );
- }
- };
- const { certifierName, isRequestedCertifier } = useCertifierName();
- const { certificationName } = useCertificationName();
- const certifiers = useCertifiers();
- const onGoBack = () => {
- isRequestedCertifier || certifiers.length < 1
- ? history.push(requestCertifierPath)
- : history.push(selectCertifierPath);
- };
-
- useHookFormPersist(() => ({}), [requestCertifierPath, selectCertifierPath, outroPath]);
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.jsx
new file mode 100644
index 0000000000..87877ad849
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/OnboardingSetCertificationSummary.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import {
+ PureSetCertificationSummary,
+} from '../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
+import { useDispatch, useSelector } from 'react-redux';
+import { useCertificationName } from '../useCertificationName';
+import { useCertifiers } from '../useCertifiers';
+import { useCertifierName } from '../useCertifierName';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { getOrganicSurveyReqBody } from './utils/getOrganicSurveyReqBody';
+import { postOrganicCertifierSurvey, putOrganicCertifierSurvey } from '../saga';
+import { certifierSurveySelector } from '../slice';
+
+export default function OnboardingSetCertificationSummary({ history }) {
+ const survey = useSelector(certifierSurveySelector);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const requestCertifierPath = '/certification/certifier/request';
+ const selectCertifierPath = '/certification/certifier/selection';
+ const outroPath = '/outro';
+ const dispatch = useDispatch();
+ const onSubmit = () => {
+ const callback = () => history.push('/outro', { success: true });
+ if (survey.survey_id) {
+ dispatch(
+ putOrganicCertifierSurvey({
+ survey: getOrganicSurveyReqBody({ ...survey, ...persistedFormData }),
+ callback,
+ }),
+ );
+ } else {
+ dispatch(
+ postOrganicCertifierSurvey({
+ survey: getOrganicSurveyReqBody(persistedFormData),
+ callback,
+ }),
+ );
+ }
+ };
+ const { certifierName, isRequestedCertifier } = useCertifierName();
+ const { certificationName } = useCertificationName();
+ const certifiers = useCertifiers();
+ const onGoBack = () => {
+ isRequestedCertifier || certifiers.length < 1
+ ? history.push(requestCertifierPath)
+ : history.push(selectCertifierPath);
+ };
+
+ useHookFormPersist(() => ({}), [requestCertifierPath, selectCertifierPath, outroPath]);
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.js b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.js
deleted file mode 100644
index fd44a73e3c..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import { PureSetCertificationSummary } from '../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
-import { useDispatch, useSelector } from 'react-redux';
-import { useCertificationName } from '../useCertificationName';
-import { useCertifiers } from '../useCertifiers';
-import { useCertifierName } from '../useCertifierName';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { getOrganicSurveyReqBody } from './utils/getOrganicSurveyReqBody';
-import { putOrganicCertifierSurvey } from '../saga';
-
-export default function UpdateSetCertificationSummary({ history }) {
- const persistedFormData = useSelector(hookFormPersistSelector);
- const requestCertifierPath = '/certification/certifier/request';
- const selectCertifierPath = '/certification/certifier/selection';
- const dispatch = useDispatch();
- const onSubmit = () => {
- const data = getOrganicSurveyReqBody(persistedFormData);
- const callback = () => history.push('/certification', { success: true });
- dispatch(putOrganicCertifierSurvey({ survey: data, callback }));
- };
- const { certifierName, isRequestedCertifier } = useCertifierName();
- const { certificationName } = useCertificationName();
- const certifiers = useCertifiers();
- const onGoBack = () => {
- isRequestedCertifier || certifiers.length < 1
- ? history.push(requestCertifierPath)
- : history.push(selectCertifierPath);
- };
-
- useHookFormPersist(() => ({}), [requestCertifierPath, selectCertifierPath]);
- return (
-
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.jsx
new file mode 100644
index 0000000000..2b9b6803da
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/SetCertificationSummary/UpdateSetCertificationSummary.jsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import {
+ PureSetCertificationSummary,
+} from '../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
+import { useDispatch, useSelector } from 'react-redux';
+import { useCertificationName } from '../useCertificationName';
+import { useCertifiers } from '../useCertifiers';
+import { useCertifierName } from '../useCertifierName';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { getOrganicSurveyReqBody } from './utils/getOrganicSurveyReqBody';
+import { putOrganicCertifierSurvey } from '../saga';
+
+export default function UpdateSetCertificationSummary({ history }) {
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const requestCertifierPath = '/certification/certifier/request';
+ const selectCertifierPath = '/certification/certifier/selection';
+ const dispatch = useDispatch();
+ const onSubmit = () => {
+ const data = getOrganicSurveyReqBody(persistedFormData);
+ const callback = () => history.push('/certification', { success: true });
+ dispatch(putOrganicCertifierSurvey({ survey: data, callback }));
+ };
+ const { certifierName, isRequestedCertifier } = useCertifierName();
+ const { certificationName } = useCertificationName();
+ const certifiers = useCertifiers();
+ const onGoBack = () => {
+ isRequestedCertifier || certifiers.length < 1
+ ? history.push(requestCertifierPath)
+ : history.push(selectCertifierPath);
+ };
+
+ useHookFormPersist(() => ({}), [requestCertifierPath, selectCertifierPath]);
+ return (
+
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.js b/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.js
deleted file mode 100644
index ba34f50179..0000000000
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { useDispatch, useSelector } from 'react-redux';
-import { certifierSurveySelector } from '../slice';
-import PureViewSupportedCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification';
-import PureViewUnsupportedCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification';
-import PureViewNotInterestedInCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification';
-
-import { certifierSelector } from '../certifierSlice';
-import { useEffect } from 'react';
-import {
- getAllSupportedCertifications,
- getAllSupportedCertifiers,
- getCertificationSurveys,
-} from '../saga';
-import { useTranslation } from 'react-i18next';
-import { resetAndUnLockFormData } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { useCertificationName } from '../useCertificationName';
-
-export default function ViewCertification({ history }) {
- const { t } = useTranslation();
- const dispatch = useDispatch();
- useEffect(() => {
- dispatch(getCertificationSurveys());
- dispatch(getAllSupportedCertifications());
- dispatch(getAllSupportedCertifiers());
- }, []);
- const { interested } = useSelector(certifierSurveySelector);
- const survey = useSelector(certifierSurveySelector);
- const { certificationName } = useCertificationName();
- const certifier = useSelector(certifierSelector);
- const isNotSupported = survey?.requested_certification || survey?.requested_certifier;
- const onExport = () => {
- history.push('/certification/report_period');
- };
- const onAddCertification = () => {
- dispatch(resetAndUnLockFormData());
- history.push('/certification/interested_in_organic');
- };
- const onChangePreference = onAddCertification;
- const showSuccessSnackBar = history.location?.state?.success;
-
- return (
- <>
- {!interested ? (
-
- ) : isNotSupported ? (
-
- ) : (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.jsx b/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.jsx
new file mode 100644
index 0000000000..d508d6f0ce
--- /dev/null
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/ViewCertification/ViewCertification.jsx
@@ -0,0 +1,66 @@
+import { useDispatch, useSelector } from 'react-redux';
+import { certifierSurveySelector } from '../slice';
+import PureViewSupportedCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification';
+import PureViewUnsupportedCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification';
+import PureViewNotInterestedInCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification';
+
+import { certifierSelector } from '../certifierSlice';
+import { useEffect } from 'react';
+import { getAllSupportedCertifications, getAllSupportedCertifiers, getCertificationSurveys } from '../saga';
+import { useTranslation } from 'react-i18next';
+import { resetAndUnLockFormData } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { useCertificationName } from '../useCertificationName';
+
+export default function ViewCertification({ history }) {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+ useEffect(() => {
+ dispatch(getCertificationSurveys());
+ dispatch(getAllSupportedCertifications());
+ dispatch(getAllSupportedCertifiers());
+ }, []);
+ const { interested } = useSelector(certifierSurveySelector);
+ const survey = useSelector(certifierSurveySelector);
+ const { certificationName } = useCertificationName();
+ const certifier = useSelector(certifierSelector);
+ const isNotSupported = survey?.requested_certification || survey?.requested_certifier;
+ const onExport = () => {
+ history.push('/certification/report_period');
+ };
+ const onAddCertification = () => {
+ dispatch(resetAndUnLockFormData());
+ history.push('/certification/interested_in_organic');
+ };
+ const onChangePreference = onAddCertification;
+ const showSuccessSnackBar = history.location?.state?.success;
+
+ return (
+ <>
+ {!interested ? (
+
+ ) : isNotSupported ? (
+
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/packages/webapp/src/containers/OrganicCertifierSurvey/slice.js b/packages/webapp/src/containers/OrganicCertifierSurvey/slice.js
index 69969e8fa8..1d1f8247a6 100644
--- a/packages/webapp/src/containers/OrganicCertifierSurvey/slice.js
+++ b/packages/webapp/src/containers/OrganicCertifierSurvey/slice.js
@@ -78,11 +78,6 @@ export const certifierSurveySelector = (state) => {
return farm_id ? certifierSurveySelectors.selectById(state, farm_id) || {} : {};
};
-export const doesCertifierSurveyExistSelector = createSelector(
- [certifierSurveySelector],
- (certifierSurvey) => certifierSurvey?.hasOwnProperty('survey_id'),
-);
-
export const certifierSurveyStatusSelector = createSelector(
[certifierSurveyReducerSelector],
({ loading, error }) => {
diff --git a/packages/webapp/src/containers/Outro/index.js b/packages/webapp/src/containers/Outro/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/Outro/index.js
rename to packages/webapp/src/containers/Outro/index.jsx
diff --git a/packages/webapp/src/containers/PasswordResetAccount/index.js b/packages/webapp/src/containers/PasswordResetAccount/index.js
deleted file mode 100644
index 55be6a6c9b..0000000000
--- a/packages/webapp/src/containers/PasswordResetAccount/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { useDispatch } from 'react-redux';
-import PureResetPasswordAccount from '../../components/PasswordResetAccount';
-import { resetPassword } from './saga';
-import jwt from 'jsonwebtoken';
-import ResetSuccessModal from '../../components/Modals/ResetPasswordSuccess';
-import { useTranslation } from 'react-i18next';
-import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
-
-function PasswordResetAccount({ history }) {
- const dispatch = useDispatch();
- const reset_token = history.location.state;
- const [email, setEmail] = useState('');
- const [showModal, setShowModal] = useState(false);
- const { i18n } = useTranslation();
- const onSubmit = (data) => {
- const { password } = data;
- dispatch(resetPassword({ reset_token, password, onPasswordResetSuccess, email }));
- };
-
- useEffect(() => {
- if (!reset_token) {
- history.push('/');
- } else {
- setEmail(getEmailFromToken(reset_token));
- }
- }, []);
-
- const getEmailFromToken = (reset_token) => {
- const decoded = jwt.decode(reset_token);
- if (getLanguageFromLocalStorage() !== decoded.language_preference) {
- localStorage.setItem('litefarm_lang', decoded.language_preference);
- i18n.changeLanguage(getLanguageFromLocalStorage());
- }
- return decoded.email;
- };
-
- const [hasTimeoutStarted, setHasTimeoutStarted] = useState(false);
- const onPasswordResetSuccess = () => {
- setShowModal(true);
- setHasTimeoutStarted(true);
- };
- useEffect(() => {
- let timeout;
- if (hasTimeoutStarted) {
- timeout = setTimeout(() => {
- history.push('/farm_selection');
- }, 10000);
- }
- return () => clearTimeout(timeout);
- }, [hasTimeoutStarted]);
-
- const modalOnClick = () => {
- history.push('/farm_selection');
- setShowModal(false);
- };
-
- return (
- <>
- {reset_token && }
- {showModal && }
- >
- );
-}
-
-export default PasswordResetAccount;
diff --git a/packages/webapp/src/containers/PasswordResetAccount/index.jsx b/packages/webapp/src/containers/PasswordResetAccount/index.jsx
new file mode 100644
index 0000000000..f6fa8ba1b0
--- /dev/null
+++ b/packages/webapp/src/containers/PasswordResetAccount/index.jsx
@@ -0,0 +1,66 @@
+import React, { useEffect, useState } from 'react';
+import { useDispatch } from 'react-redux';
+import PureResetPasswordAccount from '../../components/PasswordResetAccount';
+import { resetPassword } from './saga';
+import jwt from '@tsndr/cloudflare-worker-jwt';
+import ResetSuccessModal from '../../components/Modals/ResetPasswordSuccess';
+import { useTranslation } from 'react-i18next';
+import { getLanguageFromLocalStorage } from '../../util/getLanguageFromLocalStorage';
+
+function PasswordResetAccount({ history }) {
+ const dispatch = useDispatch();
+ const reset_token = history.location.state;
+ const [email, setEmail] = useState('');
+ const [showModal, setShowModal] = useState(false);
+ const { i18n } = useTranslation();
+ const onSubmit = (data) => {
+ const { password } = data;
+ dispatch(resetPassword({ reset_token, password, onPasswordResetSuccess, email }));
+ };
+
+ useEffect(() => {
+ if (!reset_token) {
+ history.push('/');
+ } else {
+ setEmail(getEmailFromToken(reset_token));
+ }
+ }, []);
+
+ const getEmailFromToken = (reset_token) => {
+ const decoded = jwt.decode(reset_token);
+ if (getLanguageFromLocalStorage() !== decoded.language_preference) {
+ localStorage.setItem('litefarm_lang', decoded.language_preference);
+ i18n.changeLanguage(getLanguageFromLocalStorage());
+ }
+ return decoded.email;
+ };
+
+ const [hasTimeoutStarted, setHasTimeoutStarted] = useState(false);
+ const onPasswordResetSuccess = () => {
+ setShowModal(true);
+ setHasTimeoutStarted(true);
+ };
+ useEffect(() => {
+ let timeout;
+ if (hasTimeoutStarted) {
+ timeout = setTimeout(() => {
+ history.push('/farm_selection');
+ }, 10000);
+ }
+ return () => clearTimeout(timeout);
+ }, [hasTimeoutStarted]);
+
+ const modalOnClick = () => {
+ history.push('/farm_selection');
+ setShowModal(false);
+ };
+
+ return (
+ <>
+ {reset_token && }
+ {showModal && }
+ >
+ );
+}
+
+export default PasswordResetAccount;
diff --git a/packages/webapp/src/containers/PasswordResetAccount/saga.js b/packages/webapp/src/containers/PasswordResetAccount/saga.js
index ac2be5355f..4bd9caa0f1 100644
--- a/packages/webapp/src/containers/PasswordResetAccount/saga.js
+++ b/packages/webapp/src/containers/PasswordResetAccount/saga.js
@@ -18,7 +18,7 @@ import { call, put, takeLeading } from 'redux-saga/effects';
import { url } from '../../apiConfig';
import history from '../../history';
import { loginSuccess } from '../userFarmSlice';
-import jwt from 'jsonwebtoken';
+import jwt from '@tsndr/cloudflare-worker-jwt';
import { axios } from '../saga';
const resetPasswordUrl = () => `${url}/password_reset`;
diff --git a/packages/webapp/src/containers/Profile/Account/Account.js b/packages/webapp/src/containers/Profile/Account/Account.js
deleted file mode 100644
index 279f20f837..0000000000
--- a/packages/webapp/src/containers/Profile/Account/Account.js
+++ /dev/null
@@ -1,146 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import { updateUser } from '../../saga';
-import styles from './styles.module.scss';
-import defaultStyles from '../styles.module.scss';
-import { actions, Control, Form } from 'react-redux-form';
-import { Button } from 'react-bootstrap';
-import { userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { integerOnKeyDown } from '../../../components/Form/Input';
-import { getLanguageFromLocalStorage } from '../../../util/getLanguageFromLocalStorage';
-
-class Account extends Component {
- constructor() {
- super();
- this.state = { selectedLanguage: getLanguageFromLocalStorage() };
- }
-
- componentDidMount() {
- const { dispatch, users } = this.props;
- if (users) {
- dispatch(actions.change('profileForms.userInfo.first_name', users.first_name));
- dispatch(actions.change('profileForms.userInfo.last_name', users.last_name));
- dispatch(actions.change('profileForms.userInfo.email', users.email));
- dispatch(actions.change('profileForms.userInfo.phone_number', users.phone_number));
- dispatch(actions.change('profileForms.userInfo.address', users.address));
- }
- }
-
- componentDidUpdate(prevProps) {
- // Typical usage (don't forget to compare props):
- if (this.props.users !== prevProps.users) {
- const { dispatch, users } = this.props;
- if (users) {
- dispatch(actions.change('profileForms.userInfo.first_name', users.first_name));
- dispatch(actions.change('profileForms.userInfo.last_name', users.last_name));
- dispatch(actions.change('profileForms.userInfo.email', users.email));
- dispatch(actions.change('profileForms.userInfo.phone_number', users.phone_number));
- dispatch(actions.change('profileForms.userInfo.user_address', users.user_address));
- }
- }
- }
-
- changeLanguage = (event) => {
- this.setState({ selectedLanguage: event.target.value });
- };
-
- handleSubmit(updated_user, user) {
- const { user_id, farm_id } = user;
- const { selectedLanguage } = this.state;
- const language_preference = selectedLanguage.includes('-')
- ? selectedLanguage.split('-')[0]
- : selectedLanguage;
-
- const newUser = {
- ...updated_user,
- user_id,
- language_preference,
- };
- newUser.user_address = newUser.user_address ? newUser.user_address : '';
- delete newUser.profile_picture;
- this.props.dispatch(updateUser(newUser));
- }
-
- render() {
- const { users } = this.props;
- const { selectedLanguage } = this.state;
- return (
-
-
- {this.props.t('PROFILE.ACCOUNT.PERSONAL_INFORMATION')}
-
-
-
- );
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-const mapStateToProps = (state) => {
- return {
- users: userFarmSelector(state),
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Account));
diff --git a/packages/webapp/src/containers/Profile/Account/index.js b/packages/webapp/src/containers/Profile/Account/index.js
deleted file mode 100644
index dd2ef036fe..0000000000
--- a/packages/webapp/src/containers/Profile/Account/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export default function Account() {}
diff --git a/packages/webapp/src/containers/Profile/Account/index.jsx b/packages/webapp/src/containers/Profile/Account/index.jsx
new file mode 100644
index 0000000000..4cad9a3a04
--- /dev/null
+++ b/packages/webapp/src/containers/Profile/Account/index.jsx
@@ -0,0 +1,14 @@
+import PureAccount from '../../../components/Profile/Account';
+import { useDispatch, useSelector } from 'react-redux';
+import { userFarmSelector } from '../../userFarmSlice';
+import { updateUser } from '../../saga';
+import { getProcessedFormData } from '../../hooks/useHookFormPersist/utils';
+
+export default function Account({ history }) {
+ const userFarm = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+ const onSubmit = (data) => {
+ dispatch(updateUser(getProcessedFormData(data)));
+ };
+ return ;
+}
diff --git a/packages/webapp/src/containers/Profile/Account/styles.module.scss b/packages/webapp/src/containers/Profile/Account/styles.module.scss
deleted file mode 100644
index cc2e1c705e..0000000000
--- a/packages/webapp/src/containers/Profile/Account/styles.module.scss
+++ /dev/null
@@ -1,58 +0,0 @@
-.formContainer {
- label {
- font-family: 'Avenir', sans-serif;
- font-weight: normal;
- min-width: 120px;
- width: 40%;
- margin-bottom: 0;
- }
- input {
- flex-grow: 1;
- height: 30px;
- border: 1px solid #c3c0c0;
- border-radius: 3px;
- min-width: 0;
- padding-left: 8px;
- }
- input::-webkit-inner-spin-button,
- input::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
- .center {
- margin-top: 30px;
- text-align: center;
- }
-}
-.labelContainer {
- display: flex;
- margin-bottom: 24px;
- height: 30px;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- align-items: center;
-}
-
-.headerTitle {
- margin-top: 24px;
- margin-bottom: 24px;
-}
-
-@media only screen and (max-width: 421px) {
- .formContainer {
- margin-bottom: 24px;
- height: 30px;
-
- label {
- min-width: 88px;
- font-family: 'Avenir', sans-serif;
- font-weight: normal;
- }
-
- input {
- height: 30px;
- flex-grow: 1;
- }
- }
-}
diff --git a/packages/webapp/src/containers/Profile/EditUser.jsx b/packages/webapp/src/containers/Profile/EditUser.jsx
new file mode 100644
index 0000000000..5c6d00bcf9
--- /dev/null
+++ b/packages/webapp/src/containers/Profile/EditUser.jsx
@@ -0,0 +1,41 @@
+import PureEditUser from '../../components/Profile/EditUser';
+import { useDispatch, useSelector } from 'react-redux';
+import { isAdminSelector, userFarmEntitiesSelector, userFarmSelector } from '../userFarmSlice';
+import { deactivateUser, invitePseudoUser, reactivateUser, updateUserFarm } from './People/saga';
+
+export default function EditUser({ history, match }) {
+ const { farm_id } = useSelector(userFarmSelector);
+ const isAdmin = useSelector(isAdminSelector);
+ const dispatch = useDispatch();
+ const userFarmsEntities = useSelector(userFarmEntitiesSelector);
+ const { user_id } = match.params;
+ const userFarm = userFarmsEntities[farm_id]?.[user_id];
+
+ const getReqBody = data => {
+ const role_id = Number(data.role_id?.value);
+ const reqBody = {
+ ...data,
+ user_id,
+ role_id,
+ wage: { amount: data.wage.amount, type: userFarm.wage?.type || 'hourly' },
+ };
+ if (role_id === userFarm.role_id) delete reqBody.role_id;
+ if (data.wage?.amount === userFarm.wage?.amount) delete reqBody.wage;
+ return reqBody;
+ };
+
+ const onUpdate = data => {
+ dispatch(updateUserFarm(getReqBody(data)));
+ };
+ const onInvite = data => {
+ dispatch(invitePseudoUser(getReqBody(data)));
+ };
+ const onRevoke = () => {
+ dispatch(deactivateUser(user_id));
+ };
+ const onActivate = () => {
+ dispatch(reactivateUser(user_id));
+ };
+ return ;
+}
diff --git a/packages/webapp/src/containers/Profile/Farm/Farm.jsx b/packages/webapp/src/containers/Profile/Farm/Farm.jsx
new file mode 100644
index 0000000000..0710b843cc
--- /dev/null
+++ b/packages/webapp/src/containers/Profile/Farm/Farm.jsx
@@ -0,0 +1,15 @@
+import PureFarm from '../../../components/Profile/Farm';
+import { useDispatch, useSelector } from 'react-redux';
+import { isAdminSelector, userFarmSelector } from '../../userFarmSlice';
+import { putFarm } from '../../saga';
+import { getProcessedFormData } from '../../hooks/useHookFormPersist/utils';
+
+export default function Farm({ history }) {
+ const isAdmin = useSelector(isAdminSelector);
+ const userFarm = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+ const onSubmit = (data) => {
+ dispatch(putFarm(getProcessedFormData(data)));
+ };
+ return ;
+}
diff --git a/packages/webapp/src/containers/Profile/Farm/actions.js b/packages/webapp/src/containers/Profile/Farm/actions.js
deleted file mode 100644
index d668c3c137..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/actions.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import {
- GET_FARM_DATA_SCHEDULE,
- SEND_FARM_DATA_REQUEST,
- SET_FARM_DATA_SCHEDULE,
-} from './constants';
-
-export const sendFarmDataRequst = () => {
- return {
- type: SEND_FARM_DATA_REQUEST,
- };
-};
-
-export const getFarmSchedule = () => {
- return {
- type: GET_FARM_DATA_SCHEDULE,
- };
-};
-
-export const setFarmSchedule = (data) => {
- return {
- type: SET_FARM_DATA_SCHEDULE,
- data,
- };
-};
diff --git a/packages/webapp/src/containers/Profile/Farm/constants.js b/packages/webapp/src/containers/Profile/Farm/constants.js
deleted file mode 100644
index 17e737d725..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/constants.js
+++ /dev/null
@@ -1,3 +0,0 @@
-export const SEND_FARM_DATA_REQUEST = 'SEND_FARM_DATA_REQUEST';
-export const GET_FARM_DATA_SCHEDULE = 'GET_FARM_DATA_SCHEDULE';
-export const SET_FARM_DATA_SCHEDULE = 'SET_FARM_DATA_SCHEDULE';
diff --git a/packages/webapp/src/containers/Profile/Farm/index.js b/packages/webapp/src/containers/Profile/Farm/index.js
deleted file mode 100644
index be8f9858c3..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/index.js
+++ /dev/null
@@ -1,175 +0,0 @@
-/* eslint-disable */
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import styles from './styles.module.scss';
-import defaultStyles from '../styles.module.scss';
-import { actions, Control, Form } from 'react-redux-form';
-import { Button } from 'react-bootstrap';
-import { getFarmSchedule, sendFarmDataRequst } from './actions';
-import { farmDataSelector } from './selector';
-import { isAdminSelector, userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import { putFarm } from '../../saga';
-import { integerOnKeyDown } from '../../../components/Form/Input';
-
-class Farm extends Component {
- constructor(props) {
- super(props);
- this.state = {
- request_pending_text:
- 'Farm Data requested by an admin, the process can take up to 20 minutes, please wait before sending another request.',
- request_text: 'Get Farm Raw Data',
- enableRequest: true,
- showData: false,
- };
- this.sendRequest = this.sendRequest.bind(this);
- }
-
- componentDidMount() {
- const { farm, isAdmin } = this.props;
- isAdmin && this.props.dispatch(getFarmSchedule());
- if (farm) {
- this.props.dispatch(actions.change('profileForms.farmInfo.currency', farm.units.currency));
- this.props.dispatch(
- actions.change('profileForms.farmInfo.farm_phone_number', farm.farm_phone_number || ''),
- );
- }
- }
-
- handleSubmit(updated_farm, farm) {
- const newFarm = {};
- newFarm.farm_name = updated_farm.farm_name;
- newFarm.address = updated_farm.address;
- newFarm.grid_points = updated_farm.gridPoints;
- newFarm.farm_phone_number = updated_farm.farm_phone_number;
- newFarm.units = {
- measurement: updated_farm.unit,
- currency: farm.units.currency,
- };
- newFarm.farm_id = farm.farm_id;
- newFarm.user_id = farm.user_id;
-
- this.props.dispatch(putFarm(newFarm));
- }
-
- sendRequest() {
- this.setState({
- enableRequest: false,
- });
- this.props.dispatch(sendFarmDataRequst());
- }
-
- closeDataModal = () => {
- this.setState({ showData: false });
- };
- openDataModal = () => {
- this.setState({ showData: true });
- };
-
- render() {
- const { farm, schedule } = this.props;
- const { request_text, request_pending_text, enableRequest } = this.state;
- const { role_id } = this.props.farm;
- const OWNER = 1;
- const MANAGER = 2;
- const OFFICER = 5;
- const disabled = ![OWNER, MANAGER, OFFICER].includes(role_id);
- return (
-
-
- {farm && farm.farm_name && (
-
- )}
-
-
- );
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-const mapStateToProps = (state) => {
- return {
- farm: userFarmSelector(state),
- schedule: farmDataSelector(state),
- isAdmin: isAdminSelector(state),
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Farm));
diff --git a/packages/webapp/src/containers/Profile/Farm/reducer.js b/packages/webapp/src/containers/Profile/Farm/reducer.js
deleted file mode 100644
index 414998ccd2..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/reducer.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { SET_FARM_DATA_SCHEDULE } from './constants';
-
-const initialState = {
- farm_data_schedule: null,
-};
-
-function farmReducer(state = initialState, action) {
- switch (action.type) {
- case SET_FARM_DATA_SCHEDULE:
- return Object.assign({}, state, {
- farm_data_schedule: action.data,
- });
- default:
- return state;
- }
-}
-
-export default farmReducer;
diff --git a/packages/webapp/src/containers/Profile/Farm/saga.js b/packages/webapp/src/containers/Profile/Farm/saga.js
deleted file mode 100644
index e7d2388471..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/saga.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { GET_FARM_DATA_SCHEDULE, SEND_FARM_DATA_REQUEST } from './constants';
-import { setFarmSchedule } from './actions';
-import { call, put, select, takeLatest, takeLeading } from 'redux-saga/effects';
-import apiConfig from '../../../apiConfig';
-import { loginSelector } from '../../userFarmSlice';
-import { axios, getHeader } from '../../saga';
-import { enqueueSuccessSnackbar } from '../../Snackbar/snackbarSlice';
-
-export function* sendRequestSaga() {
- const { farmDataUrl } = apiConfig;
- let { user_id, farm_id } = yield select(loginSelector);
- const header = getHeader(user_id, farm_id);
-
- try {
- const result = yield call(
- axios.post,
- farmDataUrl + '?farm_id=' + farm_id + '&user_id=' + user_id,
- {},
- header,
- );
- if (result) {
- yield put(enqueueSuccessSnackbar('Request success'));
- }
- } catch (e) {
- console.log('failed to request');
- }
-}
-
-export function* getFarmDataScheduleSaga() {
- const { farmDataUrl } = apiConfig;
- let { user_id, farm_id } = yield select(loginSelector);
- const header = getHeader(user_id, farm_id);
-
- try {
- const result = yield call(axios.get, farmDataUrl + `/${farm_id}`, header);
- if (result.data) {
- yield put(setFarmSchedule(result.data));
- }
- } catch (e) {
- console.log('failed to fetch users from database');
- }
-}
-
-export default function* farmDataSaga() {
- yield takeLeading(SEND_FARM_DATA_REQUEST, sendRequestSaga);
- yield takeLatest(GET_FARM_DATA_SCHEDULE, getFarmDataScheduleSaga);
-}
diff --git a/packages/webapp/src/containers/Profile/Farm/selector.js b/packages/webapp/src/containers/Profile/Farm/selector.js
deleted file mode 100644
index 58d00dcc37..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/selector.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { createSelector } from 'reselect/es';
-
-const farmReducer = (state) => state.farmReducer;
-
-const farmDataSelector = createSelector(farmReducer, (state) => state);
-
-export { farmDataSelector };
diff --git a/packages/webapp/src/containers/Profile/Farm/styles.module.scss b/packages/webapp/src/containers/Profile/Farm/styles.module.scss
deleted file mode 100644
index 43c339c208..0000000000
--- a/packages/webapp/src/containers/Profile/Farm/styles.module.scss
+++ /dev/null
@@ -1,97 +0,0 @@
-.formContainer {
- label {
- font-family: 'Avenir', sans-serif;
- font-weight: normal;
- min-width: 120px;
- width: 40%;
- margin-bottom: 0;
- }
- input {
- flex-grow: 1;
- height: 30px;
- border: 1px solid #c3c0c0;
- border-radius: 3px;
- min-width: 0;
- padding-left: 8px;
- }
- input::-webkit-inner-spin-button,
- input::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
- }
- select {
- background: #efefef;
- border: none;
- padding: 2px;
- }
-}
-.labelContainer {
- display: flex;
- align-items: center;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- margin-top: 24px;
- height: 30px;
- label {
- min-width: 64px;
- }
-}
-
-.selectContainer {
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- margin-top: 24px;
- label {
- min-width: 64px;
- }
-}
-
-.phoneContainer {
- display: flex;
- flex-direction: row;
- align-items: center;
- width: 100%;
- justify-content: space-between;
- margin-top: 24px;
- label {
- min-width: 64px;
- }
- //select {
- // background: #EFEFEF;
- // border: none;
- // padding: 2px;
- // margin-right: 3%;
- // height: 30px;
- //}
-}
-
-@media only screen and (max-width: 421px) {
- .formContainer {
- label {
- min-width: 88px;
- font-family: 'Avenir', sans-serif;
- font-weight: normal;
- }
- input {
- height: 30px;
- flex-grow: 1;
- }
- }
-}
-
-.greenTextButton {
- color: #00756a;
- width: 100%;
- font-size: 18px;
- text-align: left;
-}
-.requestContainer {
- width: 100%;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-}
diff --git a/packages/webapp/src/containers/Profile/People/People.jsx b/packages/webapp/src/containers/Profile/People/People.jsx
new file mode 100644
index 0000000000..dee71f5bdc
--- /dev/null
+++ b/packages/webapp/src/containers/Profile/People/People.jsx
@@ -0,0 +1,9 @@
+import PurePeople from '../../../components/Profile/People';
+import { useSelector } from 'react-redux';
+import { isAdminSelector, userFarmsByFarmSelector } from '../../userFarmSlice';
+
+export default function People({ history, match }) {
+ const userFarms = useSelector(userFarmsByFarmSelector);
+ const isAdmin = useSelector(isAdminSelector);
+ return ;
+}
diff --git a/packages/webapp/src/containers/Profile/People/index.js b/packages/webapp/src/containers/Profile/People/index.js
deleted file mode 100644
index 704d92fc40..0000000000
--- a/packages/webapp/src/containers/Profile/People/index.js
+++ /dev/null
@@ -1,548 +0,0 @@
-import React, { Component } from 'react';
-import { connect } from 'react-redux';
-import styles from './styles.module.scss';
-import defaultStyles from '../styles.module.scss';
-import { rolesSelector } from './slice';
-
-import {
- deactivateUser,
- getAllUserFarmsByFarmId,
- invitePseudoUser,
- reactivateUser,
- updateUserFarm,
-} from './saga';
-import Table from '../../../components/Table';
-import { actions, Control, Form } from 'react-redux-form';
-import { Alert, Button } from 'react-bootstrap';
-import closeButton from '../../../assets/images/grey_close_button.png';
-import Cleave from 'cleave.js/react.js';
-import { userFarmsByFarmSelector, userFarmSelector } from '../../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-import history from '../../../history';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-import MuiFullPagePopup from '../../../components/MuiFullPagePopup';
-import { enqueueSuccessSnackbar } from '../../Snackbar/snackbarSlice';
-
-const validEmailRegex = RegExp(/^$|^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
-const validWageRegex = RegExp(/^$|^[0-9]\d*(?:\.\d{1,2})?$/i);
-
-class People extends Component {
- constructor(props) {
- super(props);
- this.state = {
- showEdit: false,
- showAdd: false,
- editUser: null,
- editedUser: null,
- addUser: null,
- isAdmin: false,
- isPseudo: false,
- editTitle: '',
- currencySymbol: grabCurrencySymbol(this.props.farm),
- searchValue: '',
- edit_email_error: '',
- edit_wage_error: '',
- updated_edit: false,
- willConvertWorker: false,
- cleaveEmailState: null,
- summaryColumns: [
- {
- id: 'name',
- Header: this.props.t(`PROFILE.TABLE.HEADER_NAME`),
- accessor: (e) => e.first_name.concat(' ', e.last_name),
- minWidth: 70,
- },
- {
- id: 'email',
- Header: this.props.t(`PROFILE.TABLE.HEADER_EMAIL`),
- accessor: 'email',
- minWidth: 95,
- style: { whiteSpace: 'unset' },
- },
- {
- id: 'role',
- Header: this.props.t(`PROFILE.TABLE.HEADER_ROLE`),
- accessor: 'role',
- minWidth: 55,
- },
- {
- id: 'status',
- Header: this.props.t(`PROFILE.TABLE.HEADER_STATUS`),
- accessor: 'status',
- minWidth: 55,
- },
- ],
- };
- }
-
- openEditModal = (user) => {
- // let editTitle = user.is_admin ? 'Admin' : 'Worker'
- let editTitle = 'User';
- this.setState(
- {
- editUser: JSON.parse(JSON.stringify(user)),
- editTitle,
- editedUser: JSON.parse(JSON.stringify({ wage: user.wage })),
- },
- () => {
- this.setState({ showEdit: true });
- },
- );
- };
-
- closeEditModal = () => {
- this.setState({
- showEdit: false,
- updated_edit: false,
- edit_email_error: '',
- edit_wage_error: '',
- willConvertWorker: false,
- });
- };
-
- handleSubmit(editedUser, user) {
- if (this.state.edit_wage_error || this.state.edit_email_error) {
- return;
- }
-
- let hasChanged = false;
- let finalUser = {};
-
- if (editedUser.wage.type !== user.wage.type || editedUser.wage.amount !== user.wage.amount) {
- finalUser.wage = {
- type: editedUser.wage.type,
- amount: editedUser.wage.amount,
- };
- hasChanged = true;
- }
-
- // ADD ROLE CHANGE
- if (editedUser.role_id && editedUser.role_id !== user.role_id) {
- finalUser.role_id = editedUser.role_id;
- finalUser.has_consent = false;
- hasChanged = true;
- }
-
- // ADD EMAIL CHANGE
- const shouldConvertPseudoWorker =
- this.state.willConvertWorker &&
- editedUser.email &&
- editedUser.email.length &&
- user.role_id === 4;
-
- if (shouldConvertPseudoWorker) {
- finalUser.email = editedUser.email;
- if (!finalUser.role_id) {
- finalUser.role_id = 3;
- }
- finalUser.user_id = user.user_id;
- hasChanged = true;
- this.props.dispatch(invitePseudoUser(finalUser));
- return this.closeEditModal();
- } else if (hasChanged) {
- finalUser.user_id = user.user_id;
- this.props.dispatch(updateUserFarm(finalUser));
- this.closeEditModal();
- } else {
- this.props.dispatch(
- enqueueSuccessSnackbar(this.props.t('message:USER.ERROR.NOTHING_CHANGED')),
- );
- this.closeEditModal();
- }
- }
-
- componentDidMount() {
- const { dispatch, t } = this.props;
- dispatch(getAllUserFarmsByFarmId());
- dispatch(actions.reset('profileForms.addInfo'));
- }
-
- deactivate = (user_id) => {
- if (window.confirm(this.props.t('PROFILE.PEOPLE.DO_YOU_WANT_TO_REMOVE'))) {
- if (window.confirm(this.props.t('PROFILE.PEOPLE.THIS_WILL_REMOVE'))) {
- this.props.dispatch(deactivateUser(user_id));
- this.closeEditModal();
- }
- }
- };
-
- reactivate = (user_id) => {
- this.props.dispatch(reactivateUser(user_id));
- this.closeEditModal();
- };
-
- handleSearchValueChange = (event) => {
- this.setState({ searchValue: event.target.value });
- };
-
- formatData = () => {
- const { searchValue } = this.state;
- const { users, t } = this.props;
- const { farm_id, addedUser, roles, ...userGroups } = users;
- const ROLE_TRANSLATIONS = {
- Owner: t('role:OWNER'),
- 'Extension Officer': t('role:EXTENSION_OFFICER'),
- Manager: t('role:MANAGER'),
- Worker: t('role:WORKER'),
- 'Worker Without Account': t('role:WORKER_WITHOUT_ACCOUNT'),
- };
- const STATUS_TRANSLATIONS = {
- Active: t('STATUS.ACTIVE'),
- Inactive: t('STATUS.INACTIVE'),
- Invited: t('STATUS.INVITED'),
- };
- const combinedUserGroups = Object.keys(userGroups).reduce(
- (prev, curr) => prev.concat(userGroups[curr]),
- [],
- );
- const filteredUsers = combinedUserGroups.filter((user) => {
- const firstName = user.first_name.toLowerCase();
- const lastName = user.last_name.toLowerCase();
- const name = firstName.concat(' ', lastName);
- return name.includes(searchValue.trim().toLowerCase());
- });
- return filteredUsers.map((user) => ({
- ...user,
- role: ROLE_TRANSLATIONS[user.role],
- status: STATUS_TRANSLATIONS[user.status],
- originalStatus: user.status,
- }));
- };
-
- onRowEdit = (state, rowInfo, column, instance) => {
- const { isAdmin } = this.props;
- const isClickable = rowInfo && isAdmin && column.id === 'name';
- const clickableStyle = {
- whiteSpace: 'unset',
- cursor: 'pointer',
- textDecoration: 'underline',
- color: '#0645AD',
- };
- const normalTextStyle = { whiteSpace: 'unset' };
- return {
- onClick: (e) => {
- if (isClickable) {
- this.openEditModal(rowInfo.original);
- }
- },
- style: isClickable ? clickableStyle : normalTextStyle,
- };
- };
-
- validationCheck = (event) => {
- let to_check = event.target.value;
- let error_message;
- if (event.target.type === 'text') {
- error_message = validEmailRegex.test(to_check) ? '' : 'Email must be valid';
- this.setState({ edit_email_error: error_message });
- } else {
- error_message = validWageRegex.test(to_check)
- ? ''
- : 'Wage must be a valid, non-negative decimal';
- this.setState({ edit_wage_error: error_message });
- }
- };
-
- enableUpdate = () => {
- this.setState({ updated_edit: true });
- };
-
- updateEmail = (event) => {
- let email = event.target.value;
- let { editedUser } = this.state;
-
- editedUser.email = email;
- this.setState({
- editedUser: editedUser,
- });
-
- if (!this.state.edit_email_error) {
- this.enableUpdate();
- }
- };
-
- updateRoleSelection = (event) => {
- let role_id = Number(event.target.value);
- let { editedUser } = this.state;
-
- editedUser.role_id = role_id;
- this.setState({
- editedUser: editedUser,
- });
- this.enableUpdate();
- };
-
- updateWageAmount = (event) => {
- let amount = Number(event.target.value);
- let { editedUser } = this.state;
-
- editedUser.wage.amount = amount;
- this.setState({
- editedUser: editedUser,
- });
- this.enableUpdate();
- };
-
- updateWageType = (event) => {
- let type = event.target.value;
- let { editedUser } = this.state;
-
- editedUser.wage.type = type;
- this.setState({
- editedUser: editedUser,
- });
- this.enableUpdate();
- };
-
- toggleConvertWorker = (e) => {
- let { editedUser, edit_email_error, cleaveEmailState } = this.state;
- delete editedUser.email;
- if (!e.target.checked) {
- edit_email_error = '';
- cleaveEmailState.setRawValue('');
- }
-
- this.setState({
- willConvertWorker: e.target.checked,
- editedUser,
- edit_email_error,
- });
- };
-
- onEditEmailInit = (cleave) => {
- this.setState({ cleaveEmailState: cleave });
- };
-
- isDisabled = () => {
- const { profileForms } = this.props;
- const { forms } = profileForms;
- const { addInfo } = forms;
- return !addInfo.$form.valid;
- };
-
- isTextFieldErrorShown = (key) => {
- const { profileForms } = this.props;
- const { forms } = profileForms;
- const { addInfo } = forms;
- let field = addInfo[key];
-
- if (key === 'pay') {
- field = addInfo[key].amount;
- }
-
- // Show error only when it's invalid, touched, and not currently focused on
- // NOTE: Besides the first condition (field.valid), all the following
- // conditions should follow the show prop in the component to
- // ensure that the input field's styling is consistent with
- return !field.valid && field.touched && !field.focus;
- };
-
- getTextFieldStyle = (key) => {
- const hasErrors = this.isTextFieldErrorShown(key);
- if (hasErrors) {
- return styles.errorInputContainer;
- }
- return styles.inputContainer;
- };
-
- render() {
- const { isAdmin, profileForms } = this.props;
- const { editTitle, currencySymbol, searchValue } = this.state;
- const filteredData = this.formatData();
- const { addInfo } = profileForms;
-
- return (
-
-
-
- this.handleSearchValueChange(event)}
- className={styles.searchField}
- />
-
-
{`${
- filteredData.length
- } ${this.props.t('PROFILE.PEOPLE.USERS_FOUND')}`}
-
- {isAdmin ? (
-
history.push('/invite_user')}>
- {this.props.t('PROFILE.PEOPLE.INVITE_USER')}
-
- ) : null}
-
-
-
-
-
-
-
-
{this.props.t('PROFILE.ACCOUNT.EDIT_USER')}
-
- {this.state.editUser && (
-
-
- {this.state.editUser.originalStatus === 'Inactive' &&
- this.state.editUser.role_id !== 4 ? (
-
- {!this.state.editUser.is_admin && (
- this.reactivate(this.state.editUser.user_id)}
- >
- {this.props.t('PROFILE.PEOPLE.RESTORE_ACCESS')}
-
- )}
-
- ) : (
-
- {!this.state.editUser.is_admin && this.state.editUser.role_id !== 4 && (
- this.deactivate(this.state.editUser.user_id)}
- >
- {this.props.t('PROFILE.PEOPLE.REVOKE_ACCESS')}
-
- )}
-
- )}
-
- )}
-
-
-
- );
- }
-}
-
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-const mapStateToProps = (state) => {
- return {
- users: userFarmsByFarmSelector(state),
- farm: userFarmSelector(state),
- roles: rolesSelector(state),
- profileForms: state.profileForms,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(People));
diff --git a/packages/webapp/src/containers/Profile/People/saga.js b/packages/webapp/src/containers/Profile/People/saga.js
index 57962430da..eccc718456 100644
--- a/packages/webapp/src/containers/Profile/People/saga.js
+++ b/packages/webapp/src/containers/Profile/People/saga.js
@@ -13,8 +13,8 @@ import {
import { axios, getHeader } from '../../saga';
import { createAction } from '@reduxjs/toolkit';
import i18n from '../../../locales/i18n';
-import { roleIdRoleNameMapSelector } from './slice';
import { enqueueErrorSnackbar, enqueueSuccessSnackbar } from '../../Snackbar/snackbarSlice';
+import history from '../../../history';
const patchRoleUrl = (farm_id, user_id) => `${userFarmUrl}/role/farm/${farm_id}/user/${user_id}`;
const patchWageUrl = (farm_id, user_id) => `${userFarmUrl}/wage/farm/${farm_id}/user/${user_id}`;
@@ -55,6 +55,7 @@ export function* deactivateUserSaga({ payload: target_user_id }) {
);
yield put(patchUserStatusSuccess({ farm_id, user_id: target_user_id, ...body }));
yield put(enqueueSuccessSnackbar(i18n.t('message:USER.SUCCESS.REVOKE')));
+ history.back();
} catch (e) {
yield put(enqueueErrorSnackbar(i18n.t('message:USER.ERROR.REVOKE')));
}
@@ -81,6 +82,7 @@ export function* reactivateUserSaga({ payload: target_user_id }) {
);
yield put(patchUserStatusSuccess({ farm_id, user_id: target_user_id, ...body }));
yield put(enqueueSuccessSnackbar(i18n.t('message:USER.SUCCESS.RESTORE')));
+ history.back();
} catch (e) {
yield put(enqueueErrorSnackbar(i18n.t('message:USER.ERROR.RESTORE')));
}
@@ -98,14 +100,10 @@ export function* updateUserFarmSaga({ payload: user }) {
patchRequests.push(call(axios.patch, patchWageUrl(farm_id, target_user_id), user, header));
user.role_id &&
patchRequests.push(call(axios.patch, patchRoleUrl(farm_id, target_user_id), user, header));
- delete user.user_id;
const results = yield all(patchRequests);
- if (user.role_id) {
- const roleIdRoleNameMap = yield select(roleIdRoleNameMapSelector);
- user.role = roleIdRoleNameMap[user.role_id];
- }
- yield put(putUserSuccess({ ...user, farm_id, user_id: target_user_id }));
+ yield put(putUserSuccess({ ...user, farm_id }));
yield put(enqueueSuccessSnackbar(i18n.t('message:USER.SUCCESS.UPDATE')));
+ history.back();
} catch (e) {
yield put(enqueueErrorSnackbar(i18n.t('message:USER.ERROR.UPDATE')));
console.error(e);
@@ -119,6 +117,7 @@ export function* invitePseudoUserSaga({ payload: user }) {
const { user_id, farm_id } = yield select(loginSelector);
const header = getHeader(user_id, farm_id);
try {
+ history.back();
delete user.user_id;
const result = yield call(
axios.post,
@@ -134,6 +133,7 @@ export function* invitePseudoUserSaga({ payload: user }) {
);
yield put(enqueueSuccessSnackbar(i18n.t('message:USER.SUCCESS.UPDATE')));
} catch (e) {
+ history.push(`/user/${target_user_id}`);
yield put(enqueueErrorSnackbar(i18n.t('message:USER.ERROR.UPDATE')));
console.error(e);
}
diff --git a/packages/webapp/src/containers/Profile/People/styles.module.scss b/packages/webapp/src/containers/Profile/People/styles.module.scss
deleted file mode 100644
index d59298c3c7..0000000000
--- a/packages/webapp/src/containers/Profile/People/styles.module.scss
+++ /dev/null
@@ -1,339 +0,0 @@
-.userListContainer {
- display: flex;
- flex-direction: column;
- margin: 5% 0;
-}
-
-.searchFieldContainer {
- border: 1px solid #cecccc;
- border-radius: 8px;
- height: 40px;
- width: 50%;
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-bottom: 3%;
- padding: 1%;
-}
-
-.searchFieldContainer:focus-within {
- border: 2px solid #000000;
-}
-
-.searchField {
- border: 0;
- outline: none;
- padding: 0;
- margin-left: 0.5%;
- width: 95%;
-}
-
-.searchLabel {
- margin-bottom: 3%;
-}
-
-.addButton {
- max-width: 312px;
- margin: 16px auto 24px auto;
- background: #fce38d;
- box-shadow: 0px 2px 8px rgba(102, 115, 138, 0.3);
- border-radius: 4px;
- border: none;
- color: #282b36;
- padding: 12px 107px;
-}
-
-.close {
- img {
- width: 32px;
- }
- position: absolute;
- left: 0;
-}
-
-.modal,
-.addUserContainer {
- display: flex;
- flex-direction: column;
- width: 100%;
- max-width: 600px;
- margin: auto;
-}
-
-.addUserContainer {
-}
-
-.labelContainer {
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- margin-bottom: 3%;
- align-items: center;
- label {
- min-width: 92px;
- }
-
- input {
- flex-grow: 1;
- min-width: 0;
- padding: 0 3%;
- border: 1px solid #cecccc;
- border-radius: 8px;
- height: 40px;
- }
-}
-
-.selectContainer {
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: space-between;
- margin-bottom: 3%;
- align-items: center;
- label {
- min-width: 16%;
- }
- select {
- background: #efefef;
- border: none;
- padding: 2px;
- border-radius: 5px;
- height: 40px;
- }
- input {
- width: 30%;
- margin-right: 5%;
- padding: 0 3%;
- border: 1px solid #cecccc;
- border-radius: 8px;
- height: 40px;
- }
-}
-
-.emailInputReminder {
- margin: -0.5em 0 1em 0;
- color: #9faabe;
-}
-
-.formBodyContainer {
- width: 100%;
-}
-
-.inputContainer,
-.errorInputContainer {
- display: flex;
- flex-direction: column;
- margin: auto;
- input[type='text'],
- select {
- background: #ffffff;
- border: 1px solid #d4dae3;
- box-sizing: border-box;
- border-radius: 4px;
- margin: 0.25em 0 16px 0;
- padding: 0.75em 0.5em;
- height: 48px;
- font-size: 16px;
- color: #282b36;
- }
-
- input[type='text']:disabled,
- select:disabled {
- background: #f3f6fb;
- border: 1px solid #d4dae3;
- box-sizing: border-box;
- border-radius: 4px;
- color: #282b36;
- }
-
- input[type='text']:focus,
- select:focus {
- border: 1px solid #89d1c7;
- outline: none;
- }
-
- label {
- margin: 0;
- font-style: normal;
- font-weight: normal;
- font-size: 14px;
- line-height: 16px;
- color: #66738a;
- }
-
- input[type='radio'],
- label {
- margin: 0;
- }
-
- input[type='radio'] {
- width: 20px;
- margin-right: 2px;
- }
-}
-
-.errorInputContainer {
- input[type='text'] {
- border: 1px solid #f58282;
- }
-}
-
-.addUserTitleContainer {
- width: 100%;
- max-width: 312px;
-}
-
-.userTitle {
- margin-top: 16px;
- margin-bottom: 16px;
- font-size: 20px;
- line-height: 32px;
-}
-
-.wageContainer {
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: space-between;
- width: 50%;
-}
-
-.wageInputUnit {
- margin: 0.5em;
- color: #9faabe;
-}
-
-.payTypeContainer {
- display: flex;
- flex-direction: column;
-}
-
-.radioContainer {
- display: flex;
- flex-direction: row;
- align-items: center;
-}
-
-.popupTitle {
- position: relative;
- text-align: center;
- width: 100%;
- margin-bottom: 24px;
-}
-
-.formContainer {
- display: flex;
- flex-direction: column;
- width: 100%;
-}
-
-.removeButton {
- border: none;
- border-radius: 5px;
- background: #dc3545;
- color: white;
- width: 250px;
- margin: 15px auto 0 auto;
-}
-
-.error {
- color: red;
-}
-
-.errorContainer {
- color: #d02620;
- display: flex;
- align-items: center;
- margin: -0.75em auto 0.5em auto;
- max-width: 312px;
-}
-
-.errorText {
- margin-left: 2px;
-}
-
-.formActionsContainer {
- display: flex;
- justify-content: space-between;
- width: 100%;
- margin-bottom: 32px;
- margin-top: 45%;
-}
-
-.inviteButton,
-.cancelButton {
- padding: 12px 50px;
- border-radius: 4px;
- width: 48%;
- font-size: 18px;
- display: flex;
- justify-content: center;
- height: 48px;
-}
-
-.inviteButton {
- background: #fce38d;
- box-shadow: 0px 2px 8px rgba(102, 115, 138, 0.3);
- border: none;
- color: #282b36;
-}
-
-.inviteButton:disabled {
- background: #d4dae3;
- color: #f3f6fb;
- box-shadow: none;
-}
-
-.cancelButton {
- background: #ffffff;
- border: 1px solid #9faabe;
- color: #66738a;
-}
-
-@media (min-width: 768px) {
- .formActionsContainer {
- margin-top: 40px;
- position: unset;
- }
- .inviteButton {
- margin-right: 0;
- }
- .userTitle {
- margin-top: 24px;
- margin-bottom: 24px;
- }
- .labelContainer {
- margin-bottom: 24px;
- }
-}
-
-@media (min-width: 1024px) {
- .formActionsContainer {
- position: unset;
- margin-top: 0;
- }
- .inviteButton {
- margin-right: 0;
- }
- .userTitle {
- margin-top: 24px;
- margin-bottom: 24px;
- }
- .labelContainer {
- margin-bottom: 24px;
- }
-}
-
-@media only screen and (max-width: 421px) {
- .labelContainer {
- label {
- width: 64px;
- font-family: 'Avenir', sans-serif;
- font-weight: normal;
- }
- input {
- flex-grow: 1;
- }
- }
-}
diff --git a/packages/webapp/src/containers/Profile/index.js b/packages/webapp/src/containers/Profile/index.js
deleted file mode 100644
index beacd91898..0000000000
--- a/packages/webapp/src/containers/Profile/index.js
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React, { Component } from 'react';
-import Account from './Account/Account';
-import Farm from './Farm';
-import People from './People';
-import styles from './styles.module.scss';
-import { connect } from 'react-redux';
-import { TabContent, TabLink, Tabs } from 'react-tabs-redux';
-import { userFarmSelector } from '../userFarmSlice';
-import { withTranslation } from 'react-i18next';
-
-class Profile extends Component {
- constructor(props) {
- super(props);
- }
-
- render() {
- const tabs = [
- {
- key: 'account',
- path: 'account',
- label: this.props.t('PROFILE.ACCOUNT_TAB'),
- access: ['all'],
- },
- {
- key: 'people',
- path: 'people',
- label: this.props.t('PROFILE.PEOPLE_TAB'),
- access: ['all'],
- },
- {
- key: 'farm',
- path: 'farm',
- label: this.props.t('PROFILE.FARM_TAB'),
- access: ['all'],
- },
- ];
- const { farm = { role: '' } } = this.props; // Needed when redux does not contain farm yet
- const { role } = farm;
- const currentUserRole = (role || '').toLowerCase();
- const isAdmin =
- currentUserRole === 'owner' ||
- currentUserRole === 'manager' ||
- currentUserRole === 'extension officer';
-
- return (
-
-
-
- {tabs.map((tab) => {
- const { access, key, path, label } = tab;
- const isDisplayed = access.some(
- (roleKey) => roleKey === 'all' || roleKey === currentUserRole,
- );
- return isDisplayed ? (
-
- {label}
-
- ) : null;
- })}
-
-
-
-
- );
- }
-}
-
-const mapStateToProps = (state) => {
- return {
- farm: userFarmSelector(state),
- };
-};
-const mapDispatchToProps = (dispatch) => {
- return {
- dispatch,
- };
-};
-
-export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(Profile));
diff --git a/packages/webapp/src/containers/Profile/styles.module.scss b/packages/webapp/src/containers/Profile/styles.module.scss
deleted file mode 100644
index 0c8d2454d1..0000000000
--- a/packages/webapp/src/containers/Profile/styles.module.scss
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (styles.scss) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-.profileContainer {
- width: 100%;
- max-width: 1024px;
- margin: 0 auto;
- display: flex;
- flex-direction: column;
- padding: 24px 24px 0 24px;
-}
-
-.saveButton {
- margin-top: 30px;
- text-align: center;
-}
-
-.tabs {
- display: flex;
- flex-direction: column;
-}
-
-.tabLinks {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- width: 100%;
-
- background: #ffffff;
- border: 1px solid #cef1d8;
- border-right: none;
- box-sizing: border-box;
- border-radius: 4px;
-}
-
-.tabLink {
- width: 100%;
- outline: none;
- border: none;
- border-right: 1px solid #cef1d8;
- cursor: pointer;
- padding: 10px 0;
- background: transparent;
- text-align: center;
- color: #282b36;
-}
-
-.tabLink:focus {
- outline: none;
-}
-
-.selectedTabLink {
- background: #cef1d8;
-}
-
-.selectContainer {
- display: flex;
- flex-direction: row;
- width: 100%;
- justify-content: flex-start;
- margin-bottom: 3%;
- label {
- min-width: 64px;
- }
-}
-
-@media only screen and (min-width: 800px) {
- .profileContainer {
- width: 100%;
- max-width: 1024px;
- margin: 0 auto;
- padding-top: 70px;
- display: flex;
- flex-direction: column;
- }
-}
-
-.bottomContainer {
- width: 100%;
- max-width: 1024px;
- position: fixed;
- bottom: 0;
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- font-weight: 600;
- align-items: center;
- padding: 2% 5% 2% 5%;
- margin-left: -5%;
- background: white;
- box-shadow: 0 -5px 5px -5px #333;
- border-radius: 10px;
-}
-.buttonContainer {
- margin-left: auto;
- order: 2;
-}
-
-.cancelButton {
- width: 40%;
- font-size: 20px;
- color: #4d4d4d;
-}
-
-@media (min-width: 768px) {
- .tabs {
- width: 580px;
- height: 900px;
- left: 94px;
- top: 96px;
- margin-left: auto;
- margin-right: auto;
- background-color: #ffffff;
- padding-left: 100px;
- padding-right: 100px;
- padding-top: 16px;
- }
-
- .bottomContainer {
- margin-top: 100%;
- position: unset;
- width: auto;
- }
-}
-
-@media (min-width: 1024px) {
- .tabs {
- width: 580px;
- height: 648px;
- left: 222px;
- top: 96px;
- margin-left: auto;
- margin-right: auto;
- background-color: #ffffff;
- padding-left: 100px;
- padding-right: 100px;
- padding-top: 16px;
- }
- .bottomContainer {
- margin-top: 45%;
- position: unset;
- width: auto;
- }
-}
diff --git a/packages/webapp/src/containers/RenderSurvey/RenderSurvey.js b/packages/webapp/src/containers/RenderSurvey/RenderSurvey.jsx
similarity index 100%
rename from packages/webapp/src/containers/RenderSurvey/RenderSurvey.js
rename to packages/webapp/src/containers/RenderSurvey/RenderSurvey.jsx
diff --git a/packages/webapp/src/containers/ResetPassword/index.js b/packages/webapp/src/containers/ResetPassword/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/ResetPassword/index.js
rename to packages/webapp/src/containers/ResetPassword/index.jsx
diff --git a/packages/webapp/src/containers/RoleSelection/index.js b/packages/webapp/src/containers/RoleSelection/index.js
deleted file mode 100644
index 5740581e2f..0000000000
--- a/packages/webapp/src/containers/RoleSelection/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { useForm } from 'react-hook-form';
-import React, { useEffect } from 'react';
-import PureRoleSelection from '../../components/RoleSelection';
-import { useDispatch, useSelector } from 'react-redux';
-import { patchRole } from '../AddFarm/saga';
-import history from '../../history';
-import { roleToId } from './roleMap';
-import { useTranslation } from 'react-i18next';
-import { userFarmSelector } from '../userFarmSlice';
-
-function RoleSelection() {
- const { t } = useTranslation();
- const { role, owner_operated } = useSelector(userFarmSelector);
- const dispatch = useDispatch();
-
- const onSubmit = ({ role, owner_operated }) => {
- const callback = () => history.push('/consent');
- const boolOwnerOperated =
- owner_operated === 'true' ? true : owner_operated === 'false' ? false : null;
- dispatch(
- patchRole({ role, owner_operated: boolOwnerOperated, role_id: roleToId[role], callback }),
- );
- };
-
- const onGoBack = () => {
- history.push('/add_farm');
- };
- return (
-
- );
-}
-
-export default RoleSelection;
diff --git a/packages/webapp/src/containers/RoleSelection/index.jsx b/packages/webapp/src/containers/RoleSelection/index.jsx
new file mode 100644
index 0000000000..f9222ac08c
--- /dev/null
+++ b/packages/webapp/src/containers/RoleSelection/index.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import PureRoleSelection from '../../components/RoleSelection';
+import { useDispatch, useSelector } from 'react-redux';
+import { patchRole } from '../AddFarm/saga';
+import history from '../../history';
+import { roleToId } from './roleMap';
+import { useTranslation } from 'react-i18next';
+import { userFarmSelector } from '../userFarmSlice';
+
+function RoleSelection() {
+ const { t } = useTranslation();
+ const { role, owner_operated } = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+
+ const onSubmit = ({ role, owner_operated }) => {
+ const callback = () => history.push('/consent');
+
+ dispatch(patchRole({ role, owner_operated, role_id: roleToId[role], callback }));
+ };
+
+ const onGoBack = () => {
+ history.push('/add_farm');
+ };
+ return (
+
+ );
+}
+
+export default RoleSelection;
diff --git a/packages/webapp/src/containers/SSOUserCreateAccountInfo/index.js b/packages/webapp/src/containers/SSOUserCreateAccountInfo/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/SSOUserCreateAccountInfo/index.js
rename to packages/webapp/src/containers/SSOUserCreateAccountInfo/index.jsx
diff --git a/packages/webapp/src/containers/Snackbar/NotistackSnackbar.js b/packages/webapp/src/containers/Snackbar/NotistackSnackbar.jsx
similarity index 100%
rename from packages/webapp/src/containers/Snackbar/NotistackSnackbar.js
rename to packages/webapp/src/containers/Snackbar/NotistackSnackbar.jsx
diff --git a/packages/webapp/src/containers/Task/AddCustomTask/index.js b/packages/webapp/src/containers/Task/AddCustomTask/index.js
deleted file mode 100644
index a12e65f963..0000000000
--- a/packages/webapp/src/containers/Task/AddCustomTask/index.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import PureAddCustomTask from '../../../components/Task/PureAddCustomTask';
-import { addCustomTaskType } from '../saga';
-import { useDispatch } from 'react-redux';
-
-function AddCustomTask({ history, match }) {
-
-
- const dispatch = useDispatch();
-
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onSave = (payload) => {
- dispatch(addCustomTaskType(payload));
- history.goBack();
- };
-
- return (
-
-
-
- );
-}
-
-export default AddCustomTask;
diff --git a/packages/webapp/src/containers/Task/AddCustomTask/index.jsx b/packages/webapp/src/containers/Task/AddCustomTask/index.jsx
new file mode 100644
index 0000000000..d93296ea45
--- /dev/null
+++ b/packages/webapp/src/containers/Task/AddCustomTask/index.jsx
@@ -0,0 +1,30 @@
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import PureAddCustomTask from '../../../components/Task/PureAddCustomTask';
+import { addCustomTaskType } from '../saga';
+import { useDispatch } from 'react-redux';
+
+function AddCustomTask({ history, match }) {
+
+
+ const dispatch = useDispatch();
+
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onSave = (payload) => {
+ dispatch(addCustomTaskType(payload));
+ history.back();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default AddCustomTask;
diff --git a/packages/webapp/src/containers/Task/EditCustomTask/index.js b/packages/webapp/src/containers/Task/EditCustomTask/index.js
deleted file mode 100644
index 1190a3b2b9..0000000000
--- a/packages/webapp/src/containers/Task/EditCustomTask/index.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import PureEditCustomTask from '../../../components/Task/PureEditCustomTask';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useDispatch, useSelector } from 'react-redux';
-import { deleteTaskType } from '../saga';
-import useHookFormPersist from '../../hooks/useHookFormPersist';
-import { taskTypeSelector } from '../../taskTypeSlice';
-
-function EditCustomTask({ history, match }) {
- const dispatch = useDispatch();
- const onGoBackPath = '/add_task/manage_custom_tasks';
- const onEditPath = '/add_task/edit_custom_task_update';
- const persistedPaths = [onGoBackPath, onEditPath];
- const { persistedData } = useHookFormPersist();
- const selectedTaskType = useSelector(taskTypeSelector(persistedData.task_type_id));
- const handleGoBack = () => {
- history.goBack();
- };
-
- const handleEdit = () => {
- history.push(onEditPath);
- };
- const handleRetire = () => {
- dispatch(deleteTaskType(persistedData.task_type_id));
- };
-
- return (
-
-
-
- );
-}
-
-export default EditCustomTask;
diff --git a/packages/webapp/src/containers/Task/EditCustomTask/index.jsx b/packages/webapp/src/containers/Task/EditCustomTask/index.jsx
new file mode 100644
index 0000000000..898a038ecc
--- /dev/null
+++ b/packages/webapp/src/containers/Task/EditCustomTask/index.jsx
@@ -0,0 +1,39 @@
+import PureEditCustomTask from '../../../components/Task/PureEditCustomTask';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useDispatch, useSelector } from 'react-redux';
+import { deleteTaskType } from '../saga';
+import useHookFormPersist from '../../hooks/useHookFormPersist';
+import { taskTypeSelector } from '../../taskTypeSlice';
+
+function EditCustomTask({ history, match }) {
+ const dispatch = useDispatch();
+ const onGoBackPath = '/add_task/manage_custom_tasks';
+ const onEditPath = '/add_task/edit_custom_task_update';
+ const persistedPaths = [onGoBackPath, onEditPath];
+ const { persistedData } = useHookFormPersist();
+ const selectedTaskType = useSelector(taskTypeSelector(persistedData.task_type_id));
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const handleEdit = () => {
+ history.push(onEditPath);
+ };
+ const handleRetire = () => {
+ dispatch(deleteTaskType(persistedData.task_type_id));
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default EditCustomTask;
diff --git a/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.js b/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.js
deleted file mode 100644
index 7ae52faacc..0000000000
--- a/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import PureEditCustomTaskUpdate from '../../../components/Task/PureEditCustomTaskUpdate';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-
-function EditCustomTaskUpdate({ history, match }) {
- const onGoBackPath = '/add_task/edit_custom_task';
- const persistedPaths = [onGoBackPath];
- const handleGoBack = () => {
- history.goBack();
- };
-
- return (
-
-
-
- );
-}
-
-export default EditCustomTaskUpdate;
diff --git a/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.jsx b/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.jsx
new file mode 100644
index 0000000000..d19b42ccbf
--- /dev/null
+++ b/packages/webapp/src/containers/Task/EditCustomTaskUpdate/index.jsx
@@ -0,0 +1,22 @@
+import PureEditCustomTaskUpdate from '../../../components/Task/PureEditCustomTaskUpdate';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+
+function EditCustomTaskUpdate({ history, match }) {
+ const onGoBackPath = '/add_task/edit_custom_task';
+ const persistedPaths = [onGoBackPath];
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default EditCustomTaskUpdate;
diff --git a/packages/webapp/src/containers/Task/ManageCustomTasks/index.js b/packages/webapp/src/containers/Task/ManageCustomTasks/index.js
deleted file mode 100644
index 4c27ddfc61..0000000000
--- a/packages/webapp/src/containers/Task/ManageCustomTasks/index.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { PureManageCustomTasks } from '../../../components/Task/PureTaskTypeSelection/PureManageCustomTasks';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useSelector } from 'react-redux';
-import { userCreatedTaskTypesSelector } from '../../taskTypeSlice';
-
-function ManageCustomTasks({ history, match }) {
- const onAddCustomTaskPath = '/add_task/add_custom_task';
- const onEditCustomTaskPath = '/add_task/edit_custom_task';
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onEditCustomTask = () => {
- history.push(onEditCustomTaskPath);
- };
- const onAddCustomTask = () => {
- history.push(onAddCustomTaskPath);
- };
-
- const onError = () => {
- console.log('onError called');
- };
- const customTasks = useSelector(userCreatedTaskTypesSelector);
-
- return (
-
-
-
- );
-}
-
-export default ManageCustomTasks;
diff --git a/packages/webapp/src/containers/Task/ManageCustomTasks/index.jsx b/packages/webapp/src/containers/Task/ManageCustomTasks/index.jsx
new file mode 100644
index 0000000000..8ce0e66d59
--- /dev/null
+++ b/packages/webapp/src/containers/Task/ManageCustomTasks/index.jsx
@@ -0,0 +1,38 @@
+import { PureManageCustomTasks } from '../../../components/Task/PureTaskTypeSelection/PureManageCustomTasks';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useSelector } from 'react-redux';
+import { userCreatedTaskTypesSelector } from '../../taskTypeSlice';
+
+function ManageCustomTasks({ history, match }) {
+ const onAddCustomTaskPath = '/add_task/add_custom_task';
+ const onEditCustomTaskPath = '/add_task/edit_custom_task';
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onEditCustomTask = () => {
+ history.push(onEditCustomTaskPath);
+ };
+ const onAddCustomTask = () => {
+ history.push(onAddCustomTaskPath);
+ };
+
+ const onError = () => {
+ console.log('onError called');
+ };
+ const customTasks = useSelector(userCreatedTaskTypesSelector);
+
+ return (
+
+
+
+ );
+}
+
+export default ManageCustomTasks;
diff --git a/packages/webapp/src/containers/Task/TaskAbandon/index.js b/packages/webapp/src/containers/Task/TaskAbandon/index.js
deleted file mode 100644
index eb2074067b..0000000000
--- a/packages/webapp/src/containers/Task/TaskAbandon/index.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import PureAbandonTask from '../../../components/Task/AbandonTask';
-import { taskSelector } from '../../taskSlice';
-import { isAdminSelector, loginSelector } from '../../userFarmSlice';
-import { abandonTask } from '../saga';
-
-function TaskAbandon({ history, match }) {
- const { task_id } = match.params;
- const task = useSelector(taskSelector(task_id));
- const { user_id } = useSelector(loginSelector);
- const isAdmin = useSelector(isAdminSelector);
- const dispatch = useDispatch();
-
- const backPath = `/tasks/${task_id}/read_only`;
-
- useEffect(() => {
- // Redirect user to the task's read only view if task is abandoned
- // or if user is worker and not assigned to the task
- if (task.abandoned_time || (!isAdmin && task.assignee_user_id !== user_id && task.owner_user_id !== user_id)) {
- history.goBack();
- }
- }, []);
-
- const onSubmit = (data) => {
- const { no_work_completed, prefer_not_to_say } = data;
- let patchData = {
- abandonment_reason: data.reason_for_abandonment.value,
- abandonment_notes: data.abandonment_notes,
- duration: no_work_completed ? null : data.duration,
- happiness: prefer_not_to_say ? null : data.happiness,
- };
- if (patchData.abandonment_reason === 'OTHER') {
- patchData.other_abandonment_reason = data.other_abandonment_reason;
- }
- dispatch(abandonTask({ task_id, patchData }));
- };
-
- const onGoBack = () => {
- history.goBack();
- };
-
- return (
-
- );
-}
-
-export default TaskAbandon;
diff --git a/packages/webapp/src/containers/Task/TaskAbandon/index.jsx b/packages/webapp/src/containers/Task/TaskAbandon/index.jsx
new file mode 100644
index 0000000000..15557b2680
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskAbandon/index.jsx
@@ -0,0 +1,69 @@
+import React, { useEffect } from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import PureAbandonTask from '../../../components/Task/AbandonTask';
+import { taskSelector } from '../../taskSlice';
+import { isAdminSelector, loginSelector } from '../../userFarmSlice';
+import { abandonTask } from '../saga';
+
+function TaskAbandon({ history, match, location }) {
+ const { task_id } = match.params;
+ const task = useSelector(taskSelector(task_id));
+ const { user_id } = useSelector(loginSelector);
+ const isAdmin = useSelector(isAdminSelector);
+ const dispatch = useDispatch();
+
+ const backPath = `/tasks/${task_id}/read_only`;
+
+ useEffect(() => {
+ // Redirect user to the task's read only view if task is abandoned
+ // or if user is worker and not assigned to the task
+ if (
+ task.abandon_date ||
+ (!isAdmin && task.assignee_user_id !== user_id && task.owner_user_id !== user_id)
+ ) {
+ history.back();
+ }
+ }, []);
+
+ const onSubmit = (data) => {
+ const { no_work_completed, prefer_not_to_say, abandon_date } = data;
+ let patchData = {
+ abandonment_reason: data.reason_for_abandonment.value,
+ abandonment_notes: data.abandonment_notes,
+ duration: no_work_completed ? null : data.duration,
+ happiness: prefer_not_to_say ? null : data.happiness,
+ abandon_date,
+ };
+ if (patchData.abandonment_reason === 'OTHER') {
+ patchData.other_abandonment_reason = data.other_abandonment_reason;
+ }
+ dispatch(
+ abandonTask({
+ task_id,
+ patchData,
+ returnPath: location.state ? location.state.pathname : null,
+ }),
+ );
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ const checkIfAssigneeIsLoggedInUser = () =>
+ task?.assignee_user_id !== null &&
+ typeof task?.assignee_user_id === 'string' &&
+ typeof user_id === 'string' &&
+ task?.assignee_user_id === user_id;
+
+ return (
+
+ );
+}
+
+export default TaskAbandon;
diff --git a/packages/webapp/src/containers/Task/TaskAssignment/index.js b/packages/webapp/src/containers/Task/TaskAssignment/index.js
deleted file mode 100644
index 1e9ac417aa..0000000000
--- a/packages/webapp/src/containers/Task/TaskAssignment/index.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import PureTaskAssignment from '../../../components/Task/PureTaskAssignment';
-import { loginSelector, userFarmEntitiesSelector, userFarmSelector } from '../../userFarmSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
-import { getCurrencyFromStore } from '../../../util/getFromReduxStore';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { taskTypeSelector } from '../../taskTypeSlice';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { createTask } from '../saga';
-
-export default function TaskManagement({ history, match }) {
- const userFarms = useSelector(userFarmEntitiesSelector);
- const { farm_id } = useSelector(loginSelector);
- const userFarm = useSelector(userFarmSelector);
- const dispatch = useDispatch();
- const users = userFarms[farm_id];
- const userData = Object.values(users);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const selectedTaskType = useSelector(taskTypeSelector(persistedFormData.task_type_id));
- const isCustomType = !!selectedTaskType.farm_id;
- const [options, setOptions] = useState([{ label: 'Unassigned', value: null }]);
- const [wageData, setWageData] = useState([
- { 0: { currency: null, hourly_wage: null, currencySymbol: null } },
- ]);
- const [isFarmWorker] = useState(userFarm.role_id === 3);
- const currencySymbol = grabCurrencySymbol(getCurrencyFromStore());
- const worker = users[userFarm.user_id];
-
-
- useEffect(() => {
- let wage_data = [];
- let innerOptions = [];
- if (userFarm.role_id === 3) {
- let obj = { label: worker.first_name + ' ' + worker.last_name, value: worker.user_id };
- let wageObj = {
- [worker.user_id]: {
- currency: worker.units.currency,
- hourly_wage: worker.wage.amount,
- currencySymbol: currencySymbol,
- },
- };
- innerOptions.push(obj);
- wage_data.push(wageObj);
- } else {
- for (let i = 0; i < userData.length; i++) {
- let obj = {
- label: userData[i].first_name + ' ' + userData[i].last_name,
- value: userData[i].user_id,
- };
- innerOptions.push(obj);
- let wageObj = {
- [userData[i].user_id]: {
- currency: userData[i].units.currency,
- hourly_wage: userData[i].wage.amount,
- currencySymbol: currencySymbol,
- },
- };
- wage_data.push(wageObj);
- }
- }
- setOptions(options.concat(innerOptions));
- setWageData(wageData.concat(wage_data));
- }, []);
-
- const onSubmit = (data) => {
- const postData = { ...persistedFormData, ...data };
- dispatch(createTask(postData));
- };
-
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onError = () => {
- console.log('onError called');
- };
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskAssignment/index.jsx b/packages/webapp/src/containers/Task/TaskAssignment/index.jsx
new file mode 100644
index 0000000000..65a602e03b
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskAssignment/index.jsx
@@ -0,0 +1,97 @@
+import React, { useEffect, useState } from 'react';
+import PureTaskAssignment from '../../../components/Task/PureTaskAssignment';
+import { loginSelector, userFarmEntitiesSelector, userFarmSelector } from '../../userFarmSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import grabCurrencySymbol from '../../../util/grabCurrencySymbol';
+import { getCurrencyFromStore } from '../../../store/getFromReduxStore';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { taskTypeSelector } from '../../taskTypeSlice';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { createTask } from '../saga';
+import { useTranslation } from 'react-i18next';
+
+export default function TaskManagement({ history, match, location }) {
+ const userFarms = useSelector(userFarmEntitiesSelector);
+ const { farm_id } = useSelector(loginSelector);
+ const { t } = useTranslation();
+ const userFarm = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+ const users = userFarms[farm_id];
+ const userData = Object.values(users).filter((user) => user.status !== 'Inactive');
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const selectedTaskType = useSelector(taskTypeSelector(persistedFormData.task_type_id));
+ const isCustomType = !!selectedTaskType.farm_id;
+ const [options, setOptions] = useState([{ label: t('TASK.UNASSIGNED'), value: null }]);
+ const [wageData, setWageData] = useState([
+ { 0: { currency: null, hourly_wage: null, currencySymbol: null } },
+ ]);
+ const [isFarmWorker] = useState(userFarm.role_id === 3);
+ const currencySymbol = grabCurrencySymbol(getCurrencyFromStore());
+ const worker = users[userFarm.user_id];
+
+ useEffect(() => {
+ let wage_data = [];
+ let innerOptions = [];
+ if (userFarm.role_id === 3) {
+ let obj = { label: worker.first_name + ' ' + worker.last_name, value: worker.user_id };
+ let wageObj = {
+ [worker.user_id]: {
+ currency: worker.units.currency,
+ hourly_wage: worker.wage.amount,
+ currencySymbol: currencySymbol,
+ },
+ };
+ innerOptions.push(obj);
+ wage_data.push(wageObj);
+ } else {
+ for (let i = 0; i < userData.length; i++) {
+ let obj = {
+ label: userData[i].first_name + ' ' + userData[i].last_name,
+ value: userData[i].user_id,
+ };
+ innerOptions.push(obj);
+ let wageObj = {
+ [userData[i].user_id]: {
+ currency: userData[i].units.currency,
+ hourly_wage: userData[i].wage.amount,
+ currencySymbol: currencySymbol,
+ },
+ };
+ wage_data.push(wageObj);
+ }
+ }
+ setOptions(options.concat(innerOptions));
+ setWageData(wageData.concat(wage_data));
+ }, []);
+
+ const onSubmit = (data) => {
+ const postData = {
+ ...persistedFormData,
+ ...data,
+ returnPath: location.state ? location.state.pathname : null,
+ };
+ dispatch(createTask(postData));
+ };
+
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onError = () => {
+ console.log('onError called');
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskCard/index.js b/packages/webapp/src/containers/Task/TaskCard/index.js
deleted file mode 100644
index f924301981..0000000000
--- a/packages/webapp/src/containers/Task/TaskCard/index.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-
-import { useDispatch, useSelector } from 'react-redux';
-import { userFarmsByFarmSelector, userFarmSelector } from '../../userFarmSlice';
-import { PureTaskCard } from '../../../components/CardWithStatus/TaskCard/TaskCard';
-import TaskQuickAssignModal from '../../../components/Modals/QuickAssignModal';
-import { assignTask, assignTasksOnDate } from '../saga';
-
-const TaskCard = ({
- task_id,
- taskType,
- status,
- locationName,
- cropVarietyName,
- completeOrDueDate,
- assignee = null,
- style,
- onClick = null,
- selected,
- happiness,
- classes = { card: {} },
- ...props
-}) => {
- const [showTaskAssignModal, setShowTaskAssignModal] = useState();
- const dispatch = useDispatch();
- const onAssignTasksOnDate = (task) => dispatch(assignTasksOnDate(task));
- const onAssignTask = (task) => dispatch(assignTask(task));
- const users = useSelector(userFarmsByFarmSelector);
- const user = useSelector(userFarmSelector);
- const immutableStatus = ['completed', 'abandoned'];
-
- return (
- <>
- {
- if (!immutableStatus.includes(status)) {
- setShowTaskAssignModal(true);
- }
- }}
- selected={selected}
- happiness={happiness}
- classes={classes}
- />
- {showTaskAssignModal && (
- setShowTaskAssignModal(false)}
- />
- )}
- >
- );
-};
-
-TaskCard.propTypes = {
- style: PropTypes.object,
- status: PropTypes.oneOf(['late', 'planned', 'completed', 'abandoned', 'forReview']),
- classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
- onClick: PropTypes.func,
- happiness: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
- locationName: PropTypes.string,
- taskType: PropTypes.object,
- cropVarietyName: PropTypes.string,
- completeOrDueDate: PropTypes.string,
- assignee: PropTypes.object,
- onClickAssignee: PropTypes.func,
- selected: PropTypes.bool,
- task_id: PropTypes.number,
-};
-
-export default TaskCard;
diff --git a/packages/webapp/src/containers/Task/TaskCard/index.jsx b/packages/webapp/src/containers/Task/TaskCard/index.jsx
new file mode 100644
index 0000000000..ff9f04d2fc
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskCard/index.jsx
@@ -0,0 +1,118 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+
+import { useDispatch, useSelector } from 'react-redux';
+import { userFarmsByFarmSelector, userFarmSelector } from '../../userFarmSlice';
+import { PureTaskCard } from '../../../components/CardWithStatus/TaskCard/TaskCard';
+import TaskQuickAssignModal from '../../../components/Modals/QuickAssignModal';
+import UpdateTaskDateModal from '../../../components/Modals/UpdateTaskDateModal';
+import { assignTask, assignTasksOnDate, changeTaskDate } from '../saga';
+
+const TaskCard = ({
+ task_id,
+ taskType,
+ status,
+ locationName,
+ cropVarietyName,
+ completeOrDueDate,
+ assignee = null,
+ style,
+ onClick = null,
+ selected,
+ happiness,
+ classes = { card: {} },
+ ...props
+}) => {
+ const [showTaskAssignModal, setShowTaskAssignModal] = useState();
+ const [showDateAssignModal, setShowDateAssignModal] = useState();
+ const dispatch = useDispatch();
+ const onChangeTaskDate = (date) => {
+ dispatch(changeTaskDate({ task_id, due_date: date + 'T00:00:00.000' }));
+ };
+ const onAssignTasksOnDate = (task) => dispatch(assignTasksOnDate(task));
+ const onAssignTask = (task) => dispatch(assignTask(task));
+ const users = useSelector(userFarmsByFarmSelector).filter((user) => user.status !== 'Inactive');
+ const user = useSelector(userFarmSelector);
+ const immutableStatus = ['completed', 'abandoned'];
+ let isAssignee = false;
+ let isAdmin = false;
+ let taskUnassigned = false;
+
+ if (user) {
+ isAdmin = user.is_admin;
+ }
+ if (assignee) {
+ isAssignee = user.user_id === assignee.user_id;
+ } else {
+ taskUnassigned = true;
+ }
+
+ return (
+ <>
+ {
+ if ((!immutableStatus.includes(status) && isAssignee) || isAdmin || taskUnassigned) {
+ setShowTaskAssignModal(true);
+ }
+ }}
+ onClickCompleteOrDueDate={() => {
+ if (!immutableStatus.includes(status) && isAdmin) {
+ setShowDateAssignModal(true);
+ }
+ }}
+ selected={selected}
+ happiness={happiness}
+ classes={classes}
+ isAdmin={isAdmin}
+ isAssignee={isAssignee}
+ />
+ {showTaskAssignModal && (
+ setShowTaskAssignModal(false)}
+ />
+ )}
+ {showDateAssignModal && (
+ setShowDateAssignModal(false)}
+ />
+ )}
+ >
+ );
+};
+
+TaskCard.propTypes = {
+ style: PropTypes.object,
+ status: PropTypes.oneOf(['late', 'planned', 'completed', 'abandoned', 'forReview']),
+ classes: PropTypes.shape({ container: PropTypes.object, card: PropTypes.object }),
+ onClick: PropTypes.func,
+ happiness: PropTypes.oneOf([1, 2, 3, 4, 5, 0, null]),
+ locationName: PropTypes.string,
+ taskType: PropTypes.object,
+ cropVarietyName: PropTypes.string,
+ completeOrDueDate: PropTypes.string,
+ assignee: PropTypes.object,
+ onClickAssignee: PropTypes.func,
+ onClickCompleteOrDueDate: PropTypes.func,
+ selected: PropTypes.bool,
+ task_id: PropTypes.number,
+};
+
+export default TaskCard;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/AddHarvestUseType.js b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/AddHarvestUseType.jsx
similarity index 100%
rename from packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/AddHarvestUseType.js
rename to packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/AddHarvestUseType.jsx
diff --git a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.js b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.js
deleted file mode 100644
index ba65d9ada0..0000000000
--- a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../../userFarmSlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import PureHarvestUses from '../../../../components/Task/TaskComplete/HarvestComplete/HarvestUses';
-import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { harvestUseTypesSelector } from '../../../harvestUseTypeSlice';
-import { taskWithProductSelector } from '../../../taskSlice';
-import AddHarvestUseTypeModal from './AddHarvestUseType';
-
-function HarvestUses({ history, match }) {
- const system = useSelector(measurementSelector);
- const task_id = match.params.task_id;
- const persistedPaths = [
- `/tasks/${task_id}/complete_harvest_quantity`,
- `/tasks/${task_id}/complete`,
- ];
- const persistedFormData = useSelector(hookFormPersistSelector);
- const harvestUseTypes = useSelector(harvestUseTypesSelector);
- const task = useSelector(taskWithProductSelector(task_id));
- const [showAddHarvestTypeModal, setShowAddHarvestTypeModal] = useState(false);
-
- const onContinue = (data) => {
- history.push(`/tasks/${task_id}/complete`);
- };
-
- const onGoBack = () => {
- history.goBack();
- };
-
- return (
- <>
-
- setShowAddHarvestTypeModal(true)}
- task={task}
- />
-
- {showAddHarvestTypeModal && (
- harvestUseType.harvest_use_type_name,
- )}
- dismissModal={() => setShowAddHarvestTypeModal(false)}
- />
- )}
- >
- );
-}
-
-export default HarvestUses;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.jsx b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.jsx
new file mode 100644
index 0000000000..a57bc1f6f5
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/HarvestUses.jsx
@@ -0,0 +1,58 @@
+import React, { useState } from 'react';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../../userFarmSlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import PureHarvestUses from '../../../../components/Task/TaskComplete/HarvestComplete/HarvestUses';
+import { hookFormPersistSelector } from '../../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { harvestUseTypesSelector } from '../../../harvestUseTypeSlice';
+import { taskWithProductSelector } from '../../../taskSlice';
+import AddHarvestUseTypeModal from './AddHarvestUseType';
+
+function HarvestUses({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const task_id = match.params.task_id;
+ const persistedPaths = [
+ `/tasks/${task_id}/complete_harvest_quantity`,
+ `/tasks/${task_id}/complete`,
+ ];
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const harvestUseTypes = useSelector(harvestUseTypesSelector);
+ const task = useSelector(taskWithProductSelector(task_id));
+ const [showAddHarvestTypeModal, setShowAddHarvestTypeModal] = useState(false);
+
+ const onContinue = (data) => {
+ history.push(`/tasks/${task_id}/complete`, location?.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ return (
+ <>
+
+ setShowAddHarvestTypeModal(true)}
+ task={task}
+ />
+
+ {showAddHarvestTypeModal && (
+ harvestUseType.harvest_use_type_name,
+ )}
+ dismissModal={() => setShowAddHarvestTypeModal(false)}
+ />
+ )}
+ >
+ );
+}
+
+export default HarvestUses;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.js b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.js
deleted file mode 100644
index 2283b95196..0000000000
--- a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import { useSelector } from 'react-redux';
-import PureHarvestCompleteQuantity from '../../../../components/Task/TaskComplete/HarvestComplete/Quantity';
-import { measurementSelector } from '../../../userFarmSlice';
-import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { taskWithProductSelector } from '../../../taskSlice';
-
-function HarvestCompleteQuantity({ history, match }) {
- const system = useSelector(measurementSelector);
- const task_id = match.params.task_id;
- const persistedPaths = [`/tasks/${task_id}/harvest_uses`];
- const task = useSelector(taskWithProductSelector(task_id));
-
- const onContinue = (data) => {
- history.push(`/tasks/${task_id}/harvest_uses`);
- };
-
-
- const onGoBack = () => {
- history.goBack();
- };
-
- return (
-
-
-
- );
-}
-
-export default HarvestCompleteQuantity;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.jsx b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.jsx
new file mode 100644
index 0000000000..27bb361de9
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskComplete/HarvestComplete/Quantity.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import PureHarvestCompleteQuantity from '../../../../components/Task/TaskComplete/HarvestComplete/Quantity';
+import { measurementSelector } from '../../../userFarmSlice';
+import { HookFormPersistProvider } from '../../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { taskWithProductSelector } from '../../../taskSlice';
+
+function HarvestCompleteQuantity({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const task_id = match.params.task_id;
+ const persistedPaths = [`/tasks/${task_id}/harvest_uses`];
+ const task = useSelector(taskWithProductSelector(task_id));
+
+ const onContinue = (data) => {
+ history.push(`/tasks/${task_id}/harvest_uses`, location?.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default HarvestCompleteQuantity;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/StepOne.js b/packages/webapp/src/containers/Task/TaskComplete/StepOne.js
deleted file mode 100644
index 4f348aded2..0000000000
--- a/packages/webapp/src/containers/Task/TaskComplete/StepOne.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import PureCompleteStepOne from '../../../components/Task/TaskComplete/StepOne';
-import { useSelector } from 'react-redux';
-import { loginSelector, measurementSelector } from '../../userFarmSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { taskWithProductSelector } from '../../taskSlice';
-import { productsSelector } from '../../productSlice';
-
-function TaskCompleteStepOne({ history, match }) {
- const system = useSelector(measurementSelector);
- const { farm_id } = useSelector(loginSelector);
- const task_id = match.params.task_id;
- const task = useSelector(taskWithProductSelector(task_id));
- const selectedTaskType = task.taskType;
- const products = useSelector(productsSelector);
- const persistedPaths = [`/tasks/${task_id}/complete`];
-
- const onContinue = (data) => {
- history.push(persistedPaths[0]);
- };
-
- const onGoBack = () => {
- history.goBack();
- };
-
- return (
-
-
-
- );
-}
-
-export default TaskCompleteStepOne;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/StepOne.jsx b/packages/webapp/src/containers/Task/TaskComplete/StepOne.jsx
new file mode 100644
index 0000000000..a9b766380a
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskComplete/StepOne.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import PureCompleteStepOne from '../../../components/Task/TaskComplete/StepOne';
+import { useSelector } from 'react-redux';
+import { loginSelector, measurementSelector } from '../../userFarmSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { taskWithProductSelector } from '../../taskSlice';
+import { productsSelector } from '../../productSlice';
+
+function TaskCompleteStepOne({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const { farm_id } = useSelector(loginSelector);
+ const task_id = match.params.task_id;
+ const task = useSelector(taskWithProductSelector(task_id));
+ const selectedTaskType = task.taskType;
+ const products = useSelector(productsSelector);
+ const persistedPaths = [`/tasks/${task_id}/complete`];
+
+ const onContinue = (data) => {
+ history.push(persistedPaths[0], location?.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default TaskCompleteStepOne;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/index.js b/packages/webapp/src/containers/Task/TaskComplete/index.js
deleted file mode 100644
index d74373dde0..0000000000
--- a/packages/webapp/src/containers/Task/TaskComplete/index.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import PureTaskComplete from '../../../components/Task/TaskComplete';
-import { useDispatch } from 'react-redux';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { completeTask } from '../saga';
-
-function TaskComplete({ history, match }) {
- const dispatch = useDispatch();
- const task_id = match.params.task_id;
- const persistedPaths = [`/tasks/${task_id}/before_complete`, `/tasks/${task_id}/harvest_uses`];
-
- const onSave = (data) => {
- dispatch(completeTask({ task_id, data }));
- };
-
- const onGoBack = () => {
- history.goBack();
- };
-
- return (
-
-
-
- );
-}
-
-export default TaskComplete;
diff --git a/packages/webapp/src/containers/Task/TaskComplete/index.jsx b/packages/webapp/src/containers/Task/TaskComplete/index.jsx
new file mode 100644
index 0000000000..1b0d7be89a
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskComplete/index.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import PureTaskComplete from '../../../components/Task/TaskComplete';
+import { useDispatch } from 'react-redux';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { completeTask } from '../saga';
+
+function TaskComplete({ history, match, location }) {
+ const dispatch = useDispatch();
+ const task_id = match.params.task_id;
+ const persistedPaths = [`/tasks/${task_id}/before_complete`, `/tasks/${task_id}/harvest_uses`];
+
+ const returnPath = location?.state?.pathname ?? null;
+
+ const onSave = (data) => {
+ dispatch(completeTask({ task_id, data, returnPath }));
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default TaskComplete;
diff --git a/packages/webapp/src/containers/Task/TaskCrops/index.js b/packages/webapp/src/containers/Task/TaskCrops/index.js
deleted file mode 100644
index 6c4cd66032..0000000000
--- a/packages/webapp/src/containers/Task/TaskCrops/index.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import PureTaskCrops from '../../../components/Task/PureTaskCrops';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useSelector } from 'react-redux';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import {
- useActiveAndCurrentManagementPlanTilesByLocationIds,
- useCurrentWildManagementPlanTiles,
-} from './useManagementPlanTilesByLocationIds';
-import { cropLocationsSelector } from '../../locationSlice';
-import { useIsTaskType } from '../useIsTaskType';
-
-export default function ManagementPlanSelector({ history, match }) {
- const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
- return isTransplantTask ? (
-
- ) : (
-
- );
-}
-
-function TransplantManagementPlansSelector({ history, match }) {
- const locations = useSelector(cropLocationsSelector);
- const onContinuePath = '/add_task/task_locations';
- const goBackPath = '/add_task/task_date';
- return (
-
- );
-}
-
-function TaskCrops({
- history,
- match,
- goBackPath = '/add_task/task_locations',
- onContinuePath = '/add_task/task_details',
- locations,
-}) {
- const persistedPaths = [goBackPath, onContinuePath];
-
-
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onContinue = () => {
- history.push(onContinuePath);
- };
- const onError = () => {};
- const persistedFormData = useSelector(hookFormPersistSelector);
- const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
- const isHarvestTask = useIsTaskType('HARVEST_TASK');
- const showWildCrops = isTransplantTask || persistedFormData.show_wild_crop;
- const wildManagementPlanTiles = useCurrentWildManagementPlanTiles();
- const activeAndCurrentManagementPlansByLocationIds = useActiveAndCurrentManagementPlanTilesByLocationIds(
- locations || persistedFormData.locations,
- showWildCrops,
- );
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskCrops/index.jsx b/packages/webapp/src/containers/Task/TaskCrops/index.jsx
new file mode 100644
index 0000000000..52e7f8be87
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskCrops/index.jsx
@@ -0,0 +1,92 @@
+import PureTaskCrops from '../../../components/Task/PureTaskCrops';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useSelector } from 'react-redux';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import {
+ useActiveAndCurrentManagementPlanTilesByLocationIds,
+ useCurrentWildManagementPlanTiles,
+} from './useManagementPlanTilesByLocationIds';
+import { cropLocationsSelector } from '../../locationSlice';
+import { useIsTaskType } from '../useIsTaskType';
+
+export default function ManagementPlanSelector({ history, match, location }) {
+ const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
+ return isTransplantTask ? (
+
+ ) : (
+
+ );
+}
+
+function TransplantManagementPlansSelector({ history, match, location }) {
+ const locations = useSelector(cropLocationsSelector);
+ const onContinuePath = '/add_task/task_locations';
+ const goBackPath = '/add_task/task_date';
+ return (
+
+ );
+}
+
+function TaskCrops({
+ history,
+ match,
+ goBackPath = '/add_task/task_locations',
+ onContinuePath = '/add_task/task_details',
+ locations,
+ location,
+}) {
+ const persistedPaths = [goBackPath, onContinuePath];
+
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onContinue = () => {
+ history.push(onContinuePath, location?.state);
+ };
+ const onError = () => {};
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
+ const isHarvestTask = useIsTaskType('HARVEST_TASK');
+ const showWildCrops = isTransplantTask || persistedFormData.show_wild_crop;
+ const wildManagementPlanTiles = useCurrentWildManagementPlanTiles();
+ const activeAndCurrentManagementPlansByLocationIds =
+ useActiveAndCurrentManagementPlanTilesByLocationIds(
+ locations || persistedFormData.locations,
+ showWildCrops,
+ );
+
+ const bypass =
+ !Object.keys(activeAndCurrentManagementPlansByLocationIds).length &&
+ !persistedFormData.show_wild_crop;
+
+ const isRequired =
+ isHarvestTask || isTransplantTask || (showWildCrops && !persistedFormData.locations?.length);
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskCrops/managementPlansWithLocationSelector.js b/packages/webapp/src/containers/Task/TaskCrops/managementPlansWithLocationSelector.js
index 58fc687c66..6ea82874d3 100644
--- a/packages/webapp/src/containers/Task/TaskCrops/managementPlansWithLocationSelector.js
+++ b/packages/webapp/src/containers/Task/TaskCrops/managementPlansWithLocationSelector.js
@@ -37,8 +37,8 @@ export const managementPlansWithCurrentLocationSelector = createSelector(
const transplantTasks = transplantTasksByManagementPlanId[management_plan_id] || [];
let latestCompletedTime;
for (const transplantTask of transplantTasks) {
- const { completed_time } = taskEntities[transplantTask.task_id];
- const completedTimeInNumericalTime = completed_time && new Date(completed_time).getTime();
+ const { complete_date } = taskEntities[transplantTask.task_id];
+ const completedTimeInNumericalTime = complete_date && new Date(complete_date).getTime();
if (
completedTimeInNumericalTime &&
(!latestCompletedTime || completedTimeInNumericalTime > latestCompletedTime)
@@ -58,7 +58,7 @@ export const managementPlansWithCurrentLocationSelector = createSelector(
//In ground wild crop location and planting method
const planting_management_plan = plantingManagementPlanByManagementPlanEntities[
management_plan_id
- ]?.find(
+ ]?.find(
(planting_management_plan) =>
!transplantTasksByManagementPlanId[management_plan_id]?.find?.(
(transplantTask) =>
@@ -76,7 +76,6 @@ export const managementPlansWithCurrentLocationSelector = createSelector(
} catch (e) {
return [];
}
-
},
);
@@ -172,3 +171,8 @@ export const currentAndPlannedManagementPlansByLocationIdSelector = (location_id
...currentManagementPlans,
],
);
+
+export const managementPlansWithCurrentLocationByCropIdSelector = (cropId) =>
+ createSelector([managementPlansWithCurrentLocationSelector], (managementPlans) =>
+ managementPlans.filter((m) => m.crop_id === cropId),
+ );
diff --git a/packages/webapp/src/containers/Task/TaskDate/index.js b/packages/webapp/src/containers/Task/TaskDate/index.js
deleted file mode 100644
index 37332924cd..0000000000
--- a/packages/webapp/src/containers/Task/TaskDate/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import PureTaskDate from '../../../components/Task/TaskDate';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useIsTaskType } from '../useIsTaskType';
-
-function TaskDate({ history, match }) {
- const onGoBack = () => {
- history.goBack();
- };
- const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
- const onContinue = () => {
- history.push(isTransplantTask ? '/add_task/task_crops' : '/add_task/task_locations');
- };
-
-
- return (
-
-
-
- );
-}
-
-export default TaskDate;
diff --git a/packages/webapp/src/containers/Task/TaskDate/index.jsx b/packages/webapp/src/containers/Task/TaskDate/index.jsx
new file mode 100644
index 0000000000..f27b835963
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskDate/index.jsx
@@ -0,0 +1,85 @@
+import React, { useMemo } from 'react';
+import PureTaskDate from '../../../components/Task/TaskDate';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useIsTaskType } from '../useIsTaskType';
+import { useSelector } from 'react-redux';
+import { tasksByManagementPlanIdSelector } from '../../taskSlice';
+
+function TaskDate({ history, match, location }) {
+ const onGoBack = () => {
+ history.back();
+ };
+ const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
+
+ const tasks = location.state.management_plan_id
+ ? useSelector(tasksByManagementPlanIdSelector(location.state.management_plan_id))
+ : [];
+
+ const onContinue = (date) => () => {
+ if (tasks.length > 0) {
+ const { transplantTask, plantingTask, mostRecentlyCompleted, nextUpcoming } = tasks.reduce(
+ (previous, current) => {
+ if (
+ current.task_type_id === 19 &&
+ Date.parse(current.due_date) < Date.parse(date) &&
+ (previous.transplantTask === null ??
+ Date.parse(previous.transplantTask.due_date) < Date.parse(current.due_date))
+ ) {
+ previous.transplantTask = current;
+ } else if (current.task_type_id === 5 && current.complete_date !== null) {
+ previous.plantingTask = current;
+ } else if (
+ current.complete_date !== null &&
+ (previous.mostRecentlyCompleted === null ??
+ Date.parse(current.complete_date) >
+ Date.parse(previous.mostRecentlyCompleted.complete_date))
+ ) {
+ previous.mostRecentlyCompleted = current;
+ } else if (
+ previous.nextUpcoming === null ??
+ Date.parse(current.due_date) < Date.parse(previous.nextUpcoming.due_date)
+ ) {
+ previous.nextUpcoming = current;
+ }
+ return previous;
+ },
+ {
+ transplantTask: null,
+ plantingTask: null,
+ mostRecentlyCompleted: null,
+ nextUpcoming: null,
+ },
+ );
+ if (transplantTask) {
+ console.log('transplantTask');
+ location.state.location = transplantTask.locations[0];
+ console.log(location.state);
+ } else if (plantingTask) {
+ console.log('plantingTask');
+ location.state.location = plantingTask.locations[0];
+ console.log(location.state);
+ } else if (mostRecentlyCompleted) {
+ console.log('mostRecentlyCompleted');
+ location.state.location = mostRecentlyCompleted.locations[0];
+ console.log(location.state);
+ } else if (nextUpcoming) {
+ console.log('nextUpcoming');
+ location.state.location = nextUpcoming.locations[0];
+ console.log(location.state);
+ }
+ }
+
+ history.push(
+ isTransplantTask ? '/add_task/task_crops' : '/add_task/task_locations',
+ location?.state,
+ );
+ };
+
+ return (
+
+
+
+ );
+}
+
+export default TaskDate;
diff --git a/packages/webapp/src/containers/Task/TaskDetails/index.js b/packages/webapp/src/containers/Task/TaskDetails/index.js
deleted file mode 100644
index 426b616519..0000000000
--- a/packages/webapp/src/containers/Task/TaskDetails/index.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import PureTaskDetails from '../../../components/Task/PureTaskDetails';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useEffect } from 'react';
-import { shallowEqual, useDispatch, useSelector } from 'react-redux';
-import { getProducts } from '../saga';
-import { productsSelector } from '../../productSlice';
-import { taskTypeIdNoCropsSelector, taskTypeSelector } from '../../taskTypeSlice';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { userFarmSelector } from '../../userFarmSlice';
-import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
-import {
- useManagementPlanTilesByLocationIds,
- useWildManagementPlanTiles,
-} from '../TaskCrops/useManagementPlanTilesByLocationIds';
-import { useIsTaskType } from '../useIsTaskType';
-
-function TaskDetails({ history, match }) {
- const continuePath = '/add_task/task_assignment';
- const goBackPath = '/add_task/task_locations';
-
- const dispatch = useDispatch();
- const {
- country_id,
- units: { measurement: system },
- } = useSelector(userFarmSelector);
- const { interested, farm_id } = useSelector(certifierSurveySelector, shallowEqual);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const products = useSelector(productsSelector);
- const taskTypesBypassCrops = useSelector(taskTypeIdNoCropsSelector);
- const selectedTaskType = useSelector(taskTypeSelector(persistedFormData.task_type_id));
- const managementPlanIds = persistedFormData.managementPlans?.map(
- ({ management_plan_id }) => management_plan_id,
- );
- const managementPlanByLocations = useManagementPlanTilesByLocationIds(
- persistedFormData.locations,
- managementPlanIds,
- );
- const wildManagementPlanTiles = useWildManagementPlanTiles(persistedFormData.managementPlans);
- const showWildCrops = persistedFormData.show_wild_crop;
-
- const persistedPaths = [goBackPath, continuePath, '/add_task/task_crops'];
-
- const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onSubmit = () => {
- history.push('/add_task/task_assignment');
- };
-
- const onError = () => {};
-
- useEffect(() => {
- dispatch(getProducts());
- }, []);
-
- return (
-
-
-
- );
-}
-
-export default TaskDetails;
diff --git a/packages/webapp/src/containers/Task/TaskDetails/index.jsx b/packages/webapp/src/containers/Task/TaskDetails/index.jsx
new file mode 100644
index 0000000000..fe3e86a869
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskDetails/index.jsx
@@ -0,0 +1,76 @@
+import PureTaskDetails from '../../../components/Task/PureTaskDetails';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useEffect } from 'react';
+import { shallowEqual, useDispatch, useSelector } from 'react-redux';
+import { getProducts } from '../saga';
+import { productsSelector } from '../../productSlice';
+import { taskTypeIdNoCropsSelector, taskTypeSelector } from '../../taskTypeSlice';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { userFarmSelector } from '../../userFarmSlice';
+import { certifierSurveySelector } from '../../OrganicCertifierSurvey/slice';
+import {
+ useManagementPlanTilesByLocationIds,
+ useWildManagementPlanTiles,
+} from '../TaskCrops/useManagementPlanTilesByLocationIds';
+import { useIsTaskType } from '../useIsTaskType';
+
+function TaskDetails({ history, match, location }) {
+ const continuePath = '/add_task/task_assignment';
+ const goBackPath = '/add_task/task_locations';
+
+ const dispatch = useDispatch();
+ const {
+ country_id,
+ units: { measurement: system },
+ } = useSelector(userFarmSelector);
+ const { interested, farm_id } = useSelector(certifierSurveySelector, shallowEqual);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const products = useSelector(productsSelector);
+ const taskTypesBypassCrops = useSelector(taskTypeIdNoCropsSelector);
+ const selectedTaskType = useSelector(taskTypeSelector(persistedFormData.task_type_id));
+ const managementPlanIds = persistedFormData.managementPlans?.map(
+ ({ management_plan_id }) => management_plan_id,
+ );
+ const managementPlanByLocations = useManagementPlanTilesByLocationIds(
+ persistedFormData.locations,
+ managementPlanIds,
+ );
+ const wildManagementPlanTiles = useWildManagementPlanTiles(persistedFormData.managementPlans);
+ const showWildCrops = persistedFormData.show_wild_crop;
+
+ const persistedPaths = [goBackPath, continuePath, '/add_task/task_crops'];
+
+ const isTransplantTask = useIsTaskType('TRANSPLANT_TASK');
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onSubmit = () => {
+ history.push('/add_task/task_assignment', location?.state);
+ };
+
+ const onError = () => {};
+
+ useEffect(() => {
+ dispatch(getProducts());
+ }, []);
+
+ return (
+
+
+
+ );
+}
+
+export default TaskDetails;
diff --git a/packages/webapp/src/containers/Task/TaskLocations/index.js b/packages/webapp/src/containers/Task/TaskLocations/index.js
deleted file mode 100644
index ec338e676f..0000000000
--- a/packages/webapp/src/containers/Task/TaskLocations/index.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import React from 'react';
-import { hookFormPersistSelector, setManagementPlansData } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { useDispatch, useSelector } from 'react-redux';
-import PureTaskLocations from '../../../components/Task/TaskLocations';
-import { taskTypeIdNoCropsSelector } from '../../taskTypeSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { userFarmSelector } from '../../userFarmSlice';
-import { cropLocationEntitiesSelector, cropLocationsSelector, locationsSelector } from '../../locationSlice';
-import { useActiveAndCurrentManagementPlanTilesByLocationIds } from '../TaskCrops/useManagementPlanTilesByLocationIds';
-import { useIsTaskType } from '../useIsTaskType';
-import { useTranslation } from 'react-i18next';
-import { useReadOnlyPinCoordinates } from '../useReadOnlyPinCoordinates';
-import { useMaxZoom } from '../../Map/useMaxZoom';
-
-export default function TaskLocationsSwitch({ history, match }) {
- const isCropLocation = useIsTaskType('HARVEST_TASK');
- const isTransplantLocation = useIsTaskType('TRANSPLANT_TASK');
- if (isCropLocation) {
- return ;
- } else if (isTransplantLocation) {
- return ;
- } else {
- return ;
- }
-}
-
-function TaskActiveAndPlannedCropLocations({ history }) {
- const cropLocations = useSelector(cropLocationsSelector);
- const cropLocationEntities = useSelector(cropLocationEntitiesSelector);
- const cropLocationsIds = cropLocations.map(({ location_id }) => ({ location_id }));
- const activeAndPlannedLocationsIds = Object.keys(
- useActiveAndCurrentManagementPlanTilesByLocationIds(cropLocationsIds),
- );
- const activeAndPlannedLocations = activeAndPlannedLocationsIds.map(
- (location_id) => cropLocationEntities[location_id],
- );
- const readOnlyPinCoordinates = useReadOnlyPinCoordinates();
-
- const onContinue = () => {
- history.push('/add_task/task_crops');
- };
-
- const onGoBack = () => {
- history.goBack();
- };
- return (
-
- );
-}
-
-function TaskTransplantLocations({ history }) {
- const { t } = useTranslation();
- const cropLocations = useSelector(cropLocationsSelector);
- const onContinue = () => {
- history.push('/add_task/planting_method');
- };
-
- const onGoBack = () => {
- history.goBack();
- };
- return (
-
- );
-}
-
-function TaskAllLocations({ history }) {
- const dispatch = useDispatch();
- const locations = useSelector(locationsSelector);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const taskTypesBypassCrops = useSelector(taskTypeIdNoCropsSelector);
- const readOnlyPinCoordinates = useReadOnlyPinCoordinates();
-
- const onContinue = () => {
- if (taskTypesBypassCrops.includes(persistedFormData.task_type_id)) {
- dispatch(setManagementPlansData([]));
- return history.push('/add_task/task_details');
- }
- history.push('/add_task/task_crops');
- };
-
- const onGoBack = () => {
- history.goBack();
- };
- return (
-
- );
-}
-
-function TaskLocations({
- history,
- locations,
- isMulti,
- title,
- onContinue,
- onGoBack,
- readOnlyPinCoordinates,
-}) {
-
- const { grid_points } = useSelector(userFarmSelector);
- const { maxZoomRef, getMaxZoom } = useMaxZoom();
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskLocations/index.jsx b/packages/webapp/src/containers/Task/TaskLocations/index.jsx
new file mode 100644
index 0000000000..db7e2ae8a4
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskLocations/index.jsx
@@ -0,0 +1,154 @@
+import React from 'react';
+import {
+ hookFormPersistSelector,
+ setManagementPlansData,
+} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { useDispatch, useSelector } from 'react-redux';
+import PureTaskLocations from '../../../components/Task/TaskLocations';
+import { taskTypeIdNoCropsSelector } from '../../taskTypeSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { userFarmSelector } from '../../userFarmSlice';
+import {
+ cropLocationEntitiesSelector,
+ cropLocationsSelector,
+ locationsSelector,
+} from '../../locationSlice';
+import { useActiveAndCurrentManagementPlanTilesByLocationIds } from '../TaskCrops/useManagementPlanTilesByLocationIds';
+import { useIsTaskType } from '../useIsTaskType';
+import { useTranslation } from 'react-i18next';
+import { useReadOnlyPinCoordinates } from '../useReadOnlyPinCoordinates';
+import { useMaxZoom } from '../../Map/useMaxZoom';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskLocationsSwitch({ history, match, location }) {
+ const isCropLocation = useIsTaskType('HARVEST_TASK');
+ const isTransplantLocation = useIsTaskType('TRANSPLANT_TASK');
+ if (isCropLocation) {
+ return ;
+ } else if (isTransplantLocation) {
+ return ;
+ } else {
+ return ;
+ }
+}
+
+function TaskActiveAndPlannedCropLocations({ history, location }) {
+ const cropLocations = useSelector(cropLocationsSelector);
+ const cropLocationEntities = useSelector(cropLocationEntitiesSelector);
+ const cropLocationsIds = cropLocations.map(({ location_id }) => ({ location_id }));
+ const activeAndPlannedLocationsIds = Object.keys(
+ useActiveAndCurrentManagementPlanTilesByLocationIds(cropLocationsIds),
+ );
+ const activeAndPlannedLocations = activeAndPlannedLocationsIds.map(
+ (location_id) => cropLocationEntities[location_id],
+ );
+ const readOnlyPinCoordinates = useReadOnlyPinCoordinates();
+
+ const onContinue = () => {
+ history.push('/add_task/task_crops', location?.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+ return (
+
+ );
+}
+
+function TaskTransplantLocations({ history, location }) {
+ const { t } = useTranslation();
+ const cropLocations = useSelector(cropLocationsSelector);
+ const onContinue = () => {
+ history.push('/add_task/planting_method', location.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+ return (
+
+ );
+}
+
+function TaskAllLocations({ history, location }) {
+ const dispatch = useDispatch();
+ const locations = useSelector(locationsSelector);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const taskTypesBypassCrops = useSelector(taskTypeIdNoCropsSelector);
+ const readOnlyPinCoordinates = useReadOnlyPinCoordinates();
+
+ const onContinue = () => {
+ if (
+ taskTypesBypassCrops.includes(persistedFormData.task_type_id) &&
+ !readOnlyPinCoordinates?.length
+ ) {
+ dispatch(setManagementPlansData([]));
+ return history.push('/add_task/task_details', location?.state);
+ }
+ history.push('/add_task/task_crops', location?.state);
+ };
+
+ const onGoBack = () => {
+ history.back();
+ };
+ return (
+
+ );
+}
+
+function TaskLocations({
+ history,
+ locations,
+ isMulti,
+ title,
+ onContinue,
+ onGoBack,
+ readOnlyPinCoordinates,
+ location,
+}) {
+ const { grid_points } = useSelector(userFarmSelector);
+ const { maxZoomRef, getMaxZoom } = useMaxZoom();
+ const managementPlan = location?.state?.management_plan_id
+ ? useSelector(managementPlanSelector(location.state.management_plan_id))
+ : null;
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskReadOnly/index.js b/packages/webapp/src/containers/Task/TaskReadOnly/index.js
deleted file mode 100644
index 2be41e7c21..0000000000
--- a/packages/webapp/src/containers/Task/TaskReadOnly/index.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import React from 'react';
-import { useDispatch, useSelector } from 'react-redux';
-import PureTaskReadOnly from '../../../components/Task/TaskReadOnly';
-import {
- isAdminSelector,
- measurementSelector,
- userFarmsByFarmSelector,
- userFarmSelector,
-} from '../../userFarmSlice';
-import { productsSelector } from '../../productSlice';
-import {
- setFormData,
- setPersistedPaths,
-} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { harvestUseTypesSelector } from '../../harvestUseTypeSlice';
-import { useReadonlyTask } from './useReadonlyTask';
-import { isTaskType } from '../useIsTaskType';
-import { useMaxZoom } from '../../Map/useMaxZoom';
-
-function TaskReadOnly({ history, match }) {
- const task_id = match.params.task_id;
- const dispatch = useDispatch();
- const system = useSelector(measurementSelector);
- const task = useReadonlyTask(task_id);
- const products = useSelector(productsSelector);
- const users = useSelector(userFarmsByFarmSelector);
- const user = useSelector(userFarmSelector);
- const isAdmin = useSelector(isAdminSelector);
- const isTaskTypeCustom = !!task.taskType.farm_id;
-
- const selectedTaskType = task.taskType;
- const isHarvest = isTaskType(selectedTaskType, 'HARVEST_TASK');
- const harvestUseTypes = useSelector(harvestUseTypesSelector);
-
- const onGoBack = () => {
- history.goBack();
- };
-
- const onComplete = () => {
- dispatch(
- setPersistedPaths([
- `/tasks/${task_id}/complete_harvest_quantity`,
- `/tasks/${task_id}/complete`,
- `/tasks/${task_id}/before_complete`,
- `/tasks/${task_id}/harvest_uses`,
- ]),
- );
- if (isHarvest) {
- history.push(`/tasks/${task_id}/complete_harvest_quantity`);
- } else if (isTaskTypeCustom) {
- dispatch(setFormData({ task_id, taskType: task.taskType }));
- history.push(`/tasks/${task_id}/complete`);
- } else {
- history.push(`/tasks/${task_id}/before_complete`);
- }
- };
-
- const onEdit = () => {
- // TODO - LF-1720 Edit task page
- };
-
- const onAbandon = () => {
- history.push(`/tasks/${task_id}/abandon`);
- };
- const { maxZoomRef, getMaxZoom } = useMaxZoom();
- return (
-
- );
-}
-
-export default TaskReadOnly;
diff --git a/packages/webapp/src/containers/Task/TaskReadOnly/index.jsx b/packages/webapp/src/containers/Task/TaskReadOnly/index.jsx
new file mode 100644
index 0000000000..b3fa5f4d2d
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskReadOnly/index.jsx
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
+import React from 'react';
+import { useDispatch, useSelector } from 'react-redux';
+import PureTaskReadOnly from '../../../components/Task/TaskReadOnly';
+import {
+ isAdminSelector,
+ measurementSelector,
+ userFarmsByFarmSelector,
+ userFarmSelector,
+} from '../../userFarmSlice';
+import { productsSelector } from '../../productSlice';
+import {
+ setFormData,
+ setPersistedPaths,
+} from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { harvestUseTypesSelector } from '../../harvestUseTypeSlice';
+import { useReadonlyTask } from './useReadonlyTask';
+import { isTaskType } from '../useIsTaskType';
+import { useMaxZoom } from '../../Map/useMaxZoom';
+import { assignTask, assignTasksOnDate, changeTaskDate } from '../saga';
+
+function TaskReadOnly({ history, match, location }) {
+ const task_id = match.params.task_id;
+ const dispatch = useDispatch();
+ const system = useSelector(measurementSelector);
+ const task = useReadonlyTask(task_id);
+ const products = useSelector(productsSelector);
+ const users = useSelector(userFarmsByFarmSelector).filter((user) => user.status !== 'Inactive');
+ const user = useSelector(userFarmSelector);
+ const isAdmin = useSelector(isAdminSelector);
+ const isTaskTypeCustom = !!task.taskType.farm_id;
+
+ const selectedTaskType = task.taskType;
+ const isHarvest = isTaskType(selectedTaskType, 'HARVEST_TASK');
+ const harvestUseTypes = useSelector(harvestUseTypesSelector);
+
+ const onGoBack = () => {
+ history.back();
+ };
+
+ const onComplete = () => {
+ dispatch(
+ setPersistedPaths([
+ `/tasks/${task_id}/complete_harvest_quantity`,
+ `/tasks/${task_id}/complete`,
+ `/tasks/${task_id}/before_complete`,
+ `/tasks/${task_id}/harvest_uses`,
+ ]),
+ );
+ if (isHarvest) {
+ history.push(`/tasks/${task_id}/complete_harvest_quantity`, location?.state);
+ } else if (isTaskTypeCustom) {
+ dispatch(setFormData({ task_id, taskType: task.taskType }));
+ history.push(`/tasks/${task_id}/complete`, location?.state);
+ } else {
+ history.push(`/tasks/${task_id}/before_complete`, location?.state);
+ }
+ };
+
+ const onEdit = () => {
+ // TODO - LF-1720 Edit task page
+ };
+
+ const onAbandon = () => {
+ history.push(`/tasks/${task_id}/abandon`, location?.state);
+ };
+ const { maxZoomRef, getMaxZoom } = useMaxZoom();
+
+ const onChangeTaskDate = (date) =>
+ dispatch(changeTaskDate({ task_id, due_date: date + 'T00:00:00.000' }));
+ const onAssignTasksOnDate = (task) => dispatch(assignTasksOnDate(task));
+ const onAssignTask = (task) => dispatch(assignTask(task));
+ return (
+ <>
+
+ >
+ );
+}
+
+export default TaskReadOnly;
diff --git a/packages/webapp/src/containers/Task/TaskReadOnly/useReadonlyTask.js b/packages/webapp/src/containers/Task/TaskReadOnly/useReadonlyTask.js
index e4e9c6adaf..97df3e70d0 100644
--- a/packages/webapp/src/containers/Task/TaskReadOnly/useReadonlyTask.js
+++ b/packages/webapp/src/containers/Task/TaskReadOnly/useReadonlyTask.js
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see < .>
+ */
+
import { useSelector } from 'react-redux';
import { taskEntitiesByManagementPlanIdSelector, taskWithProductSelector } from '../../taskSlice';
import { useMemo } from 'react';
@@ -18,16 +33,17 @@ export const useReadonlyTask = (task_id) => {
const getTransplantTask = (task) => {
const managementPlan = task.managementPlans[0];
- const { prev_planting_management_plan, planting_management_plan } = managementPlan;
+ // prev_planting_management_plan will default to planting_management_plan if undefined
+ const { planting_management_plan, prev_planting_management_plan = planting_management_plan } =
+ managementPlan;
task.pinCoordinates = [];
task.managementPlansByPinCoordinate = {};
task.managementPlansByLocation = {};
const pin_coordinate = prev_planting_management_plan.pin_coordinate;
if (pin_coordinate) {
task.pinCoordinates.push(pin_coordinate);
- task.managementPlansByPinCoordinate[
- getLocationName({ pin_coordinate }, 6)
- ] = getManagementPlanTile(managementPlan, tasksByManagementPlanId);
+ task.managementPlansByPinCoordinate[getLocationName({ pin_coordinate }, 6)] =
+ getManagementPlanTile(managementPlan, tasksByManagementPlanId);
} else {
task.managementPlansByLocation[prev_planting_management_plan.location_id] = [
getManagementPlanTile(managementPlan, tasksByManagementPlanId),
@@ -69,7 +85,7 @@ export const useReadonlyTask = (task_id) => {
return useMemo(() => {
return produce(task, task.transplant_task ? getTransplantTask : getTask);
- }, []);
+ }, [task]);
};
const getLocationsById = (task) => {
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.js
deleted file mode 100644
index 6736c60fcb..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../userFarmSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function TaskBedGuidance({ history, match }) {
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { crop_variety_id } = useSelector(
- managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
- );
- const system = useSelector(measurementSelector);
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.jsx
new file mode 100644
index 0000000000..c5c717cc29
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedGuidance.jsx
@@ -0,0 +1,29 @@
+import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../userFarmSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskBedGuidance({ history, match, location }) {
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { crop_variety_id } = useSelector(
+ managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
+ );
+ const system = useSelector(measurementSelector);
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.js
deleted file mode 100644
index 0ec0551e81..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import PureBedPlan from '../../../components/Crop/BedPlan/PureBedPlan';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../userFarmSlice';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function TaskBedPlan({ history, match }) {
- const system = useSelector(measurementSelector);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { crop_variety_id } = useSelector(
- managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
- );
- const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.jsx
new file mode 100644
index 0000000000..bdf10edb41
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskBedMethod.jsx
@@ -0,0 +1,31 @@
+import PureBedPlan from '../../../components/Crop/BedPlan/PureBedPlan';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../userFarmSlice';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskBedPlan({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { crop_variety_id } = useSelector(
+ managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
+ );
+ const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.js
deleted file mode 100644
index 51a3ffe735..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import PurePlantInContainer from '../../../components/Crop/PlantInContainer';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../userFarmSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function TaskPlantInContainer({ history, match }) {
- const system = useSelector(measurementSelector);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { crop_variety_id } = useSelector(
- managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
- );
- const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.jsx
new file mode 100644
index 0000000000..e714f59fc8
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskContainerMethod.jsx
@@ -0,0 +1,31 @@
+import PurePlantInContainer from '../../../components/Crop/PlantInContainer';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../userFarmSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskPlantInContainer({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { crop_variety_id } = useSelector(
+ managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
+ );
+ const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.js
deleted file mode 100644
index 7dfdddc6c1..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../userFarmSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function TaskRowGuidance({ history, match }) {
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { crop_variety_id } = useSelector(
- managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
- );
- const system = useSelector(measurementSelector);
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.jsx
new file mode 100644
index 0000000000..186c915756
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowGuidance.jsx
@@ -0,0 +1,28 @@
+import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../userFarmSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskRowGuidance({ history, match, location }) {
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { crop_variety_id } = useSelector(
+ managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
+ );
+ const system = useSelector(measurementSelector);
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.js
deleted file mode 100644
index 240ebe7db8..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import PureRowMethod from '../../../components/Crop/RowMethod';
-import { useSelector } from 'react-redux';
-import { measurementSelector } from '../../userFarmSlice';
-import { cropVarietySelector } from '../../cropVarietySlice';
-import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
-import { managementPlanSelector } from '../../managementPlanSlice';
-
-export default function TaskRowMethod({ history, match }) {
- const system = useSelector(measurementSelector);
- const persistedFormData = useSelector(hookFormPersistSelector);
- const { crop_variety_id } = useSelector(
- managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
- );
- const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.jsx
new file mode 100644
index 0000000000..06bed986d5
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskRowMethod.jsx
@@ -0,0 +1,30 @@
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import PureRowMethod from '../../../components/Crop/RowMethod';
+import { useSelector } from 'react-redux';
+import { measurementSelector } from '../../userFarmSlice';
+import { cropVarietySelector } from '../../cropVarietySlice';
+import { hookFormPersistSelector } from '../../hooks/useHookFormPersist/hookFormPersistSlice';
+import { managementPlanSelector } from '../../managementPlanSlice';
+
+export default function TaskRowMethod({ history, match, location }) {
+ const system = useSelector(measurementSelector);
+ const persistedFormData = useSelector(hookFormPersistSelector);
+ const { crop_variety_id } = useSelector(
+ managementPlanSelector(persistedFormData.managementPlans[0].management_plan_id),
+ );
+ const crop_variety = useSelector(cropVarietySelector(crop_variety_id));
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.js b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.js
deleted file mode 100644
index 781315fb68..0000000000
--- a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import {
- PureTaskPlantingMethod,
-} from '../../../components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod';
-
-export default function PlantingMethod({ history, match }) {
-
-
- return (
-
-
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.jsx b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.jsx
new file mode 100644
index 0000000000..20541918d2
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTransplantMethod/TaskTransplantMethod.jsx
@@ -0,0 +1,10 @@
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { PureTaskPlantingMethod } from '../../../components/Task/PureTaskPlantingMethod/PureManagementPlanPlantingMethod';
+
+export default function PlantingMethod({ history, match, location }) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/TaskTypeSelection/index.js b/packages/webapp/src/containers/Task/TaskTypeSelection/index.js
deleted file mode 100644
index fc5d7cb60a..0000000000
--- a/packages/webapp/src/containers/Task/TaskTypeSelection/index.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { PureTaskTypeSelection } from '../../../components/Task/PureTaskTypeSelection/PureTaskTypeSelection';
-import { useDispatch, useSelector } from 'react-redux';
-import { isAdminSelector, userFarmSelector } from '../../userFarmSlice';
-import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
-import { useEffect } from 'react';
-import { getTaskTypes } from '../saga';
-import { defaultTaskTypesSelector, userCreatedTaskTypesSelector } from '../../taskTypeSlice';
-import { showedSpotlightSelector } from '../../showedSpotlightSlice';
-import { setSpotlightToShown } from '../../Map/saga';
-import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
-
-function TaskTypeSelection({ history, match }) {
- const userFarm = useSelector(userFarmSelector);
- const dispatch = useDispatch();
- const taskTypes = useSelector(defaultTaskTypesSelector);
- const customTasks = useSelector(userCreatedTaskTypesSelector);
- const continuePath = '/add_task/task_date';
- const customTaskPath = '/add_task/manage_custom_tasks';
- const persistedPaths = [continuePath, customTaskPath];
- const { planting_task } = useSelector(showedSpotlightSelector);
- const isAdmin = useSelector(isAdminSelector);
-
-
- useEffect(() => {
- dispatch(getTaskTypes());
- }, []);
-
- const onCustomTask = () => {
- history.push(customTaskPath);
- };
-
- const onContinue = () => history.push(continuePath);
-
- const handleGoBack = () => {
- history.goBack();
- };
-
- const onError = () => {
- };
-
- const updatePlantTaskSpotlight = () => dispatch(setSpotlightToShown('planting_task'));
-
- const hasCurrentManagementPlans = useSelector(currentAndPlannedManagementPlansSelector)?.length > 0;
-
- return (
- <>
-
-
-
- >
- );
-}
-
-export default TaskTypeSelection;
diff --git a/packages/webapp/src/containers/Task/TaskTypeSelection/index.jsx b/packages/webapp/src/containers/Task/TaskTypeSelection/index.jsx
new file mode 100644
index 0000000000..5d2a81c85d
--- /dev/null
+++ b/packages/webapp/src/containers/Task/TaskTypeSelection/index.jsx
@@ -0,0 +1,66 @@
+import { PureTaskTypeSelection } from '../../../components/Task/PureTaskTypeSelection/PureTaskTypeSelection';
+import { useDispatch, useSelector } from 'react-redux';
+import { isAdminSelector, userFarmSelector } from '../../userFarmSlice';
+import { HookFormPersistProvider } from '../../hooks/useHookFormPersist/HookFormPersistProvider';
+import { useEffect } from 'react';
+import { getTaskTypes } from '../saga';
+import { defaultTaskTypesSelector, userCreatedTaskTypesSelector } from '../../taskTypeSlice';
+import { showedSpotlightSelector } from '../../showedSpotlightSlice';
+import { setSpotlightToShown } from '../../Map/saga';
+import { currentAndPlannedManagementPlansSelector } from '../../managementPlanSlice';
+
+function TaskTypeSelection({ history, match, location }) {
+ const userFarm = useSelector(userFarmSelector);
+ const dispatch = useDispatch();
+ const taskTypes = useSelector(defaultTaskTypesSelector);
+ const customTasks = useSelector(userCreatedTaskTypesSelector);
+ const continuePath = '/add_task/task_date';
+ const customTaskPath = '/add_task/manage_custom_tasks';
+ const persistedPaths = [continuePath, customTaskPath];
+ const { planting_task } = useSelector(showedSpotlightSelector);
+ const isAdmin = useSelector(isAdminSelector);
+
+ useEffect(() => {
+ dispatch(getTaskTypes());
+ }, []);
+
+ const onCustomTask = () => {
+ history.push(customTaskPath, location?.state);
+ };
+
+ const onContinue = () => history.push(continuePath, location?.state);
+
+ const handleGoBack = () => {
+ history.back();
+ };
+
+ const onError = () => {};
+
+ const updatePlantTaskSpotlight = () => dispatch(setSpotlightToShown('planting_task'));
+
+ const hasCurrentManagementPlans =
+ useSelector(currentAndPlannedManagementPlansSelector)?.length > 0;
+
+ return (
+ <>
+
+
+
+ >
+ );
+}
+
+export default TaskTypeSelection;
diff --git a/packages/webapp/src/containers/Task/getTasksMinMaxDate.js b/packages/webapp/src/containers/Task/getTasksMinMaxDate.js
index c27a3aeef7..2390fe0b77 100644
--- a/packages/webapp/src/containers/Task/getTasksMinMaxDate.js
+++ b/packages/webapp/src/containers/Task/getTasksMinMaxDate.js
@@ -1,17 +1,16 @@
export const getTasksMinMaxDate = (tasks = []) => {
let startDate;
let endDate;
- for (const { planned_time } of tasks) {
- const date = new Date(planned_time).getTime();
+ for (const { due_date } of tasks) {
if (!startDate) {
- startDate = date;
- } else if (date < startDate) {
+ startDate = due_date;
+ } else if (due_date < startDate) {
!endDate && (endDate = startDate);
- startDate = date;
+ startDate = due_date;
} else if (!endDate) {
- endDate = date;
- } else if (date > endDate) {
- endDate = date;
+ endDate = due_date;
+ } else if (due_date > endDate) {
+ endDate = due_date;
}
}
return { startDate, endDate };
diff --git a/packages/webapp/src/containers/Task/index.js b/packages/webapp/src/containers/Task/index.js
deleted file mode 100644
index 0b1aff778f..0000000000
--- a/packages/webapp/src/containers/Task/index.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import Layout from '../../components/Layout';
-import { useTranslation } from 'react-i18next';
-import PageTitle from '../../components/PageTitle/v2';
-import { AddLink, Semibold } from '../../components/Typography';
-import { useDispatch, useSelector } from 'react-redux';
-import React, { useEffect, useMemo, useState } from 'react';
-import styles from './styles.module.scss';
-
-import { isAdminSelector, loginSelector } from '../userFarmSlice';
-import { resetAndUnLockFormData } from '../hooks/useHookFormPersist/hookFormPersistSlice';
-import StateTab from '../../components/RouterTab/StateTab';
-import { ALL, TODO, UNASSIGNED } from './constants';
-import { getManagementPlansAndTasks } from '../saga';
-import { taskCardContentSelector } from './taskCardContentSelector';
-import TaskCard from './TaskCard';
-import { onAddTask } from './onAddTask';
-
-export default function TaskPage({ history }) {
- const { t } = useTranslation();
- const isAdmin = useSelector(isAdminSelector);
- const { user_id, farm_id } = useSelector(loginSelector);
- const tasks = useSelector(taskCardContentSelector);
- const dispatch = useDispatch();
-
- const defaultTab = TODO;
- const [activeTab, setTab] = useState(defaultTab);
-
- useEffect(() => {
- dispatch(getManagementPlansAndTasks());
- }, []);
-
- useEffect(() => {
- dispatch(resetAndUnLockFormData());
- }, []);
-
- const taskCardContents = useMemo(() => {
- switch (activeTab) {
- case ALL:
- return tasks;
- case TODO:
- return tasks.filter(
- (task) => task.assignee?.user_id === user_id && ['planned', 'late'].includes(task.status),
- );
- case UNASSIGNED:
- return tasks.filter((task) => !task.assignee);
- default:
- return [];
- }
- }, [tasks, activeTab]);
-
- return (
-
-
-
-
-
- {t('TASK.TASKS_COUNT', { count: taskCardContents.length })}
-
-
{t('TASK.ADD_TASK')}
-
- {taskCardContents.length > 0 ? (
- taskCardContents.map((task) => (
- history.push(`/tasks/${task.task_id}/read_only`)}
- style={{ marginBottom: '14px' }}
- {...task}
- />
- ))
- ) : (
- {t('TASK.NO_TASKS_TO_DISPLAY')}
- )}
-
- );
-}
diff --git a/packages/webapp/src/containers/Task/index.jsx b/packages/webapp/src/containers/Task/index.jsx
new file mode 100644
index 0000000000..7e1737fbd2
--- /dev/null
+++ b/packages/webapp/src/containers/Task/index.jsx
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import Layout from '../../components/Layout';
+import { useTranslation } from 'react-i18next';
+import PageTitle from '../../components/PageTitle/v2';
+import { AddLink, Semibold } from '../../components/Typography';
+import { useDispatch, useSelector } from 'react-redux';
+import React, { useEffect, useMemo, useState } from 'react';
+
+import { isAdminSelector, userFarmSelector } from '../userFarmSlice';
+import { resetAndUnLockFormData } from '../hooks/useHookFormPersist/hookFormPersistSlice';
+import { getManagementPlansAndTasks } from '../saga';
+import TaskCard from './TaskCard';
+import { onAddTask } from './onAddTask';
+import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
+import TasksFilterPage from '../Filter/Tasks';
+import {
+ isFilterCurrentlyActiveSelector,
+ setTasksFilter,
+ tasksFilterSelector,
+ setTasksFilterUnassignedDueThisWeek,
+ setTasksFilterDueToday,
+} from '../filterSlice';
+import ActiveFilterBox from '../../components/ActiveFilterBox';
+import PureTaskDropdownFilter from '../../components/PopupFilter/PureTaskDropdownFilter';
+import produce from 'immer';
+import { IS_ASCENDING } from '../Filter/constants';
+import { WEEKLY_UNASSIGNED_TASKS, DAILY_TASKS_DUE_TODAY } from '../Notification/constants';
+import { filteredTaskCardContentSelector } from './taskCardContentSelector';
+import TaskCount from '../../components/Task/TaskCount';
+
+export default function TaskPage({ history }) {
+ const { t } = useTranslation();
+ const isAdmin = useSelector(isAdminSelector);
+ const { user_id, farm_id, first_name, last_name } = useSelector(userFarmSelector);
+ const taskCardContents = useSelector(filteredTaskCardContentSelector);
+ const dispatch = useDispatch();
+
+ const tasksFilter = useSelector(tasksFilterSelector);
+ const isFilterCurrentlyActive = useSelector(isFilterCurrentlyActiveSelector('tasks'));
+
+ const [isFilterOpen, setIsFilterOpen] = useState(false);
+ const onFilterClose = () => {
+ setIsFilterOpen(false);
+ };
+ const onFilterOpen = () => {
+ setIsFilterOpen(true);
+ };
+
+ useEffect(() => {
+ dispatch(getManagementPlansAndTasks());
+ dispatch(resetAndUnLockFormData());
+
+ const context = history.location?.state;
+
+ let notificationDate;
+ if (context?.notification_date) {
+ const tempDate = new Date(context?.notification_date);
+ notificationDate = new Date(
+ tempDate.getUTCFullYear(),
+ tempDate.getUTCMonth(),
+ tempDate.getUTCDate(),
+ );
+ } else {
+ notificationDate = new Date();
+ }
+
+ switch (context?.notification_type) {
+ case WEEKLY_UNASSIGNED_TASKS:
+ dispatch(setTasksFilterUnassignedDueThisWeek({ date: notificationDate }));
+ break;
+ case DAILY_TASKS_DUE_TODAY:
+ dispatch(
+ setTasksFilterDueToday({ user_id, first_name, last_name, date: notificationDate }),
+ );
+ break;
+ default:
+ break;
+ }
+ }, []);
+
+ const assigneeValue = useMemo(() => {
+ let unassigned;
+ let myTask;
+ for (const [assignee, { active }] of Object.entries(tasksFilter.ASSIGNEE)) {
+ if (assignee === 'unassigned' && active) {
+ unassigned = true;
+ } else if (assignee === user_id && active) {
+ myTask = true;
+ } else if (active) {
+ return undefined;
+ }
+ }
+ if (unassigned && !myTask) return 'unassigned';
+ if (myTask) return 'myTask';
+ return 'all';
+ }, [tasksFilter.ASSIGNEE]);
+ const onAssigneeChange = (e) => {
+ const assigneeValue = e.target.value;
+ dispatch(
+ setTasksFilter(
+ produce(tasksFilter, (tasksFilter) => {
+ for (const assignee in tasksFilter.ASSIGNEE) {
+ tasksFilter.ASSIGNEE[assignee].active = false;
+ }
+ if (assigneeValue === 'myTask') {
+ tasksFilter.ASSIGNEE[user_id] = { active: true, label: `${first_name} ${last_name}` };
+ } else if (assigneeValue === 'unassigned') {
+ tasksFilter.ASSIGNEE.unassigned = { active: true, label: t('TASK.UNASSIGNED') };
+ }
+ }),
+ ),
+ );
+ };
+ const onDateOrderChange = (e) => {
+ const dateOrderValue = e.target.value;
+ dispatch(
+ setTasksFilter(
+ produce(tasksFilter, (tasksFilter) => {
+ tasksFilter[IS_ASCENDING] = dateOrderValue === 'ascending';
+ }),
+ ),
+ );
+ };
+ return (
+
+
+
+
+
+
+
+
+
+ {isFilterCurrentlyActive && (
+
+ )}
+
+ {taskCardContents.length > 0 ? (
+ taskCardContents.map((task) => (
+ history.push(`/tasks/${task.task_id}/read_only`)}
+ style={{ marginBottom: '14px' }}
+ {...task}
+ />
+ ))
+ ) : (
+ {t('TASK.NO_TASKS_TO_DISPLAY')}
+ )}
+
+ );
+}
diff --git a/packages/webapp/src/containers/Task/onAddTask.js b/packages/webapp/src/containers/Task/onAddTask.js
index 3cbe4fc66f..322b7a5595 100644
--- a/packages/webapp/src/containers/Task/onAddTask.js
+++ b/packages/webapp/src/containers/Task/onAddTask.js
@@ -4,9 +4,10 @@ import { setPersistedPaths } from '../hooks/useHookFormPersist/hookFormPersistSl
*
* @param dispatch
* @param history
+ * @param state
* @return {(function(): void)|*}
*/
-export const onAddTask = (dispatch, history) => () => {
+export const onAddTask = (dispatch, history, state) => () => {
//TODO: remove all persistedPath in add task flow
dispatch(
setPersistedPaths([
@@ -28,5 +29,5 @@ export const onAddTask = (dispatch, history) => () => {
'/add_task/row_guidance',
]),
);
- history.push('/add_task/task_type_selection');
+ history.push('/add_task/task_type_selection', state);
};
diff --git a/packages/webapp/src/containers/Task/saga.js b/packages/webapp/src/containers/Task/saga.js
index 2547a2096f..d25b95ecc5 100644
--- a/packages/webapp/src/containers/Task/saga.js
+++ b/packages/webapp/src/containers/Task/saga.js
@@ -99,7 +99,7 @@ export function* assignTaskSaga({ payload: { task_id, assignee_user_id } }) {
{ assignee_user_id: assignee_user_id },
header,
);
- yield put(putTaskSuccess({ id: task_id, changes: { assignee_user_id } }));
+ yield put(putTaskSuccess({ assignee_user_id, task_id }));
yield put(enqueueSuccessSnackbar(i18n.t('message:ASSIGN_TASK.SUCCESS')));
} catch (e) {
console.log(e);
@@ -123,7 +123,7 @@ export function* assignTaskOnDateSaga({ payload: { task_id, date, assignee_user_
let modified_tasks = [];
for (let i = 0; i < result.data.length; i++) {
modified_tasks.push({
- id: result.data[i],
+ id: result.data[i].task_id,
changes: { assignee_user_id },
});
}
@@ -135,6 +135,28 @@ export function* assignTaskOnDateSaga({ payload: { task_id, date, assignee_user_
}
}
+export const changeTaskDate = createAction('changeTaskDateSaga');
+
+export function* changeTaskDateSaga({ payload: { task_id, due_date } }) {
+ const { taskUrl } = apiConfig;
+ let { user_id, farm_id } = yield select(loginSelector);
+ const header = getHeader(user_id, farm_id);
+ try {
+ const result = yield call(
+ axios.patch,
+ `${taskUrl}/patch_due_date/${task_id}`,
+ { due_date },
+ header,
+ );
+
+ yield put(putTaskSuccess({ due_date, task_id }));
+ yield put(enqueueSuccessSnackbar(i18n.t('message:ASSIGN_TASK.SUCCESS')));
+ } catch (e) {
+ console.log(e);
+ yield put(enqueueErrorSnackbar(i18n.t('message:ASSIGN_TASK.ERROR')));
+ }
+}
+
export const getPlantingTasksAndPlantingManagementPlansSuccess = createAction(
'getPlantingTasksAndPlantingManagementPlansSuccessSaga',
);
@@ -279,7 +301,7 @@ const getPostTaskBody = (data, endpoint, managementPlanWithCurrentLocationEntiti
delete data[key];
}
data.wage_at_moment = data.override_hourly_wage ? data.wage_at_moment : null;
- data.managementPlans = data.managementPlans.map(({ management_plan_id }) => ({
+ data.managementPlans = data.managementPlans?.map(({ management_plan_id }) => ({
planting_management_plan_id:
managementPlanWithCurrentLocationEntities[management_plan_id].planting_management_plan
.planting_management_plan_id,
@@ -291,9 +313,15 @@ const getPostTaskBody = (data, endpoint, managementPlanWithCurrentLocationEntiti
const getPostHarvestTaskBody = (data, endpoint, managementPlanWithCurrentLocationEntities) => {
return data.harvest_tasks.map((harvest_task) => {
- const [location_id, management_plan_id] = harvest_task.id.split('.');
+ const { location_id, management_plan_id } = harvest_task;
return getObjectInnerValues({
- harvest_task: { ...harvest_task, id: undefined, notes: undefined },
+ harvest_task: {
+ ...harvest_task,
+ location_id: undefined,
+ management_plan_id: undefined,
+ id: undefined,
+ notes: undefined,
+ },
...pick(
data,
Object.keys(data).filter(
@@ -363,7 +391,9 @@ const getPostTaskReqBody = (
export const createTask = createAction('createTaskSaga');
-export function* createTaskSaga({ payload: data }) {
+export function* createTaskSaga({ payload }) {
+ const { returnPath, ...data } = payload;
+
const { taskUrl } = apiConfig;
let { user_id, farm_id } = yield select(loginSelector);
const { task_translation_key, farm_id: task_farm_id } = yield select(
@@ -398,7 +428,7 @@ export function* createTaskSaga({ payload: data }) {
yield call(getTasksSuccessSaga, { payload: isHarvest ? result.data : [result.data] });
yield call(onReqSuccessSaga, {
message: i18n.t('message:TASK.CREATE.SUCCESS'),
- pathname: '/tasks',
+ pathname: returnPath ?? '/tasks',
});
}
} catch (e) {
@@ -426,9 +456,8 @@ const getCompletePlantingTaskBody = (task_translation_key) => (data) => {
const taskType = task_translation_key.toLowerCase();
const planting_management_plan = data?.taskData?.[taskType]?.planting_management_plan;
if (planting_management_plan) {
- data.taskData[taskType].planting_management_plan = getPlantingMethodReqBody(
- planting_management_plan,
- );
+ data.taskData[taskType].planting_management_plan =
+ getPlantingMethodReqBody(planting_management_plan);
data.taskData[taskType].planting_management_plan.planting_management_plan_id =
data.taskData[taskType].planting_management_plan_id;
delete data.taskData[taskType].planting_management_plan_id;
@@ -445,7 +474,7 @@ const taskTypeGetCompleteTaskBodyFunctionMap = {
export const completeTask = createAction('completeTaskSaga');
-export function* completeTaskSaga({ payload: { task_id, data } }) {
+export function* completeTaskSaga({ payload: { task_id, data, returnPath } }) {
const { taskUrl } = apiConfig;
let { user_id, farm_id } = yield select(loginSelector);
const { task_translation_key, isCustomTaskType } = data;
@@ -462,10 +491,10 @@ export function* completeTaskSaga({ payload: { task_id, data } }) {
header,
);
if (result) {
- yield put(putTaskSuccess({ id: task_id, changes: result.data }));
+ yield put(putTaskSuccess(result.data));
yield call(onReqSuccessSaga, {
message: i18n.t('message:TASK.COMPLETE.SUCCESS'),
- pathname: '/tasks',
+ pathname: returnPath ?? '/tasks',
});
}
} catch (e) {
@@ -477,16 +506,17 @@ export function* completeTaskSaga({ payload: { task_id, data } }) {
export const abandonTask = createAction('abandonTaskSaga');
export function* abandonTaskSaga({ payload: data }) {
+ console.log(data);
const { taskUrl } = apiConfig;
let { user_id, farm_id } = yield select(loginSelector);
- const { task_id, patchData } = data;
+ const { task_id, patchData, returnPath } = data;
const header = getHeader(user_id, farm_id);
try {
const result = yield call(axios.patch, `${taskUrl}/abandon/${task_id}`, patchData, header);
if (result) {
- yield put(putTaskSuccess({ id: task_id, changes: result.data }));
+ yield put(putTaskSuccess(result.data));
yield put(enqueueSuccessSnackbar(i18n.t('message:TASK.ABANDON.SUCCESS')));
- history.push('/tasks');
+ history.push(returnPath ?? '/tasks');
}
} catch (e) {
console.log(e);
@@ -546,7 +576,7 @@ export function* deleteTaskTypeSaga({ payload: id }) {
if (result) {
yield put(deleteTaskTypeSuccess(id));
yield put(enqueueSuccessSnackbar(i18n.t('message:TASK_TYPE.DELETE.SUCCESS')));
- history.goBack();
+ history.back();
}
} catch (e) {
yield put(enqueueErrorSnackbar(i18n.t('message:TASK_TYPE.DELETE.FAILED')));
@@ -601,6 +631,7 @@ export function* addCustomHarvestUseSaga({ payload: data }) {
export default function* taskSaga() {
yield takeLeading(addCustomTaskType.type, addTaskTypeSaga);
yield takeLeading(assignTask.type, assignTaskSaga);
+ yield takeLeading(changeTaskDate.type, changeTaskDateSaga);
yield takeLeading(createTask.type, createTaskSaga);
yield takeLatest(getTaskTypes.type, getTaskTypesSaga);
yield takeLeading(assignTasksOnDate.type, assignTaskOnDateSaga);
diff --git a/packages/webapp/src/containers/Task/styles.module.scss b/packages/webapp/src/containers/Task/styles.module.scss
index 07428280b5..e69de29bb2 100644
--- a/packages/webapp/src/containers/Task/styles.module.scss
+++ b/packages/webapp/src/containers/Task/styles.module.scss
@@ -1,17 +0,0 @@
-.taskCountContainer {
- display: flex;
- flex-direction: row;
- align-items: center;
- gap: 18px;
- margin-bottom: 16px;
-}
-
-.taskCount {
- background: var(--teal700);
- color: #ffffff;
- border-radius: 4px;
- font-weight: bold;
- font-size: 14px;
- line-height: 20px;
- padding: 2px 8px;
-}
diff --git a/packages/webapp/src/containers/Task/taskCardContentSelector.js b/packages/webapp/src/containers/Task/taskCardContentSelector.js
index 40990a31c5..dde664178c 100644
--- a/packages/webapp/src/containers/Task/taskCardContentSelector.js
+++ b/packages/webapp/src/containers/Task/taskCardContentSelector.js
@@ -5,72 +5,89 @@ import { isTaskType } from './useIsTaskType';
import { getTaskCardDate } from '../../util/moment';
import { loginSelector, userFarmEntitiesSelector } from '../userFarmSlice';
import { getLocationName } from '../Crop/CropManagement/useManagementPlanCardContents';
+import { tasksFilterSelector } from '../filterSlice';
+import { filterTasks } from './tasksFilter';
+import { IS_ASCENDING } from '../Filter/constants';
const getTaskContents = (tasks, userFarmEntities, { farm_id }) => {
- return tasks
- .sort((taskA, taskB) => {
- if (
- !taskA.completed_time &&
- !taskA.abandoned_time &&
- (taskB.completed_time || taskB.abandoned_time)
- ) {
- return -1;
- }
- if (
- taskA.completed_time &&
- !taskA.abandoned_time &&
- !taskB.completed_time &&
- taskB.abandoned_time
- ) {
- return -1;
- }
- if (
- !taskA.completed_time &&
- !taskA.abandoned_time &&
- !taskB.completed_time &&
- !taskB.abandoned_time
- ) {
- return new Date(taskA.due_date).getTime() - new Date(taskB.due_date).getTime();
- }
- if (taskA.completed_time && taskB.completed_time) {
- return new Date(taskA.completed_time).getTime() - new Date(taskB.completed_time).getTime();
- }
- if (taskA.abandoned_time && taskB.abandoned_time) {
- return new Date(taskA.abandoned_time).getTime() - new Date(taskB.abandoned_time).getTime();
- }
- return 1;
- })
- .map((task) => {
- const managementPlans = task.managementPlans;
- return {
- task_id: task.task_id,
- taskType: task.taskType,
- status: getTaskStatus(task),
- cropVarietyName: getCropVarietyName(managementPlans),
- locationName: getLocationNameOfTask(managementPlans, task.locations, task.taskType),
- completeOrDueDate: getTaskCardDate(task.completed_time || task.due_date),
- assignee: userFarmEntities[farm_id][task.assignee_user_id],
- happiness: task.happiness,
- abandoned_time: task.abandoned_time,
- };
- });
+ return tasks.map((task) => {
+ const managementPlans = task.managementPlans;
+ return {
+ task_id: task.task_id,
+ taskType: task.taskType,
+ status: getTaskStatus(task),
+ cropVarietyName: getCropVarietyName(managementPlans),
+ locationName: getLocationNameOfTask(managementPlans, task.locations, task.taskType),
+ completeOrDueDate: getTaskCardDate(task.complete_date || task.due_date),
+ assignee: task.assignee,
+ happiness: task.happiness,
+ abandon_date: task.abandon_date,
+ date: task.abandon_date || task.complete_date || task.due_date,
+ };
+ });
};
+export const sortTaskCardContent = (taskCardContents, isAscending = true) =>
+ taskCardContents.sort((taskA, taskB) => {
+ const order = isAscending ? 1 : -1;
+ const bottomTwoStatus = ['completed', 'abandoned'];
+ if (!bottomTwoStatus.includes(taskA.status) && bottomTwoStatus.includes(taskB.status)) {
+ return -1;
+ }
+ if (
+ taskA.status === 'completed' &&
+ taskB.status === 'abandoned' &&
+ taskA.status !== 'abandoned' &&
+ taskB.status !== 'completed'
+ ) {
+ return -1;
+ }
+ if (!bottomTwoStatus.includes(taskA.status) && !bottomTwoStatus.includes(taskB.status)) {
+ return (new Date(taskA.date).getTime() - new Date(taskB.date).getTime()) * order;
+ }
+ if (taskA.status === 'completed' && taskB.status === 'completed') {
+ return (new Date(taskA.date).getTime() - new Date(taskB.date).getTime()) * order;
+ }
+ if (taskA.status === 'abandoned' && taskB.status === 'abandoned') {
+ return (
+ (new Date(taskA.abandon_date).getTime() - new Date(taskB.abandon_date).getTime()) * order
+ );
+ }
+ return 1;
+ });
+
export const taskCardContentSelector = createSelector(
[tasksSelector, userFarmEntitiesSelector, loginSelector],
getTaskContents,
);
+export const manualFilteredTaskCardContentSelector = (filter) =>
+ createSelector(
+ [tasksSelector, userFarmEntitiesSelector, loginSelector],
+ (tasks, userFarmEntities, userFarm) =>
+ getTaskContents(filter(tasks), userFarmEntities, userFarm),
+ );
+
+export const filteredTaskCardContentSelector = createSelector(
+ [tasksSelector, tasksFilterSelector, userFarmEntitiesSelector, loginSelector],
+ (tasks, filters, userFarmEntities, userFarm) =>
+ sortTaskCardContent(
+ getTaskContents(filterTasks(tasks, filters), userFarmEntities, userFarm),
+ filters[IS_ASCENDING],
+ ),
+);
+
export const taskCardContentByManagementPlanSelector = (management_plan_id) =>
createSelector(
[tasksByManagementPlanIdSelector(management_plan_id), userFarmEntitiesSelector, loginSelector],
- getTaskContents,
+ (tasks, userFarmEntities, { farm_id }) =>
+ sortTaskCardContent(getTaskContents(tasks, userFarmEntities, { farm_id })),
);
export const getTaskStatus = (task) => {
- if (task.completed_time) return 'completed';
- if (task.abandoned_time) return 'abandoned';
- if (new Date(task.due_date) > Date.now()) return 'planned';
+ if (task.complete_date) return 'completed';
+ if (task.abandon_date) return 'abandoned';
+ if (new Date(task.due_date) >= new Date().setHours(0, 0, 0, 0)) return 'planned';
return 'late';
};
diff --git a/packages/webapp/src/containers/Task/tasksFilter.js b/packages/webapp/src/containers/Task/tasksFilter.js
new file mode 100644
index 0000000000..3478679c5f
--- /dev/null
+++ b/packages/webapp/src/containers/Task/tasksFilter.js
@@ -0,0 +1,64 @@
+import moment from 'moment';
+
+import { getTaskStatus } from './taskCardContentSelector';
+import { ASSIGNEE, CROP, FROM_DATE, LOCATION, STATUS, TO_DATE, TYPE } from '../Filter/constants';
+
+const getActiveCriteria = (filter) => {
+ const filterKeys = Object.keys(filter);
+ const countActive = filterKeys.filter((k) => filter[k].active).length;
+ let selected = [];
+
+ if (countActive > 0) selected = filterKeys.filter((key) => filter[key].active);
+ else selected = filterKeys;
+
+ return new Set(selected);
+};
+
+const filterByAssignee = (task, activeAssignees) => {
+ let user_id = 'unassigned';
+ if (task.assignee !== undefined) {
+ user_id = task.assignee.user_id;
+ }
+ return activeAssignees.has(user_id);
+};
+
+const filterByFromDate = (task, fromDate) => {
+ if (fromDate === undefined) {
+ return true;
+ }
+
+ return moment(task.complete_date || task.due_date).isSameOrAfter(fromDate, 'day');
+};
+
+const filterByToDate = (task, toDate) => {
+ if (toDate === undefined) {
+ return true;
+ }
+
+ return moment(task.complete_date || task.due_date).isSameOrBefore(toDate, 'day');
+};
+
+export function filterTasks(tasks, filters) {
+ const activeStatus = getActiveCriteria(filters[STATUS]);
+ const activeTypes = getActiveCriteria(filters[TYPE]);
+ const activeLocations = getActiveCriteria(filters[LOCATION]);
+ const activeAssignees = getActiveCriteria(filters[ASSIGNEE]);
+ const activeVarieties = getActiveCriteria(filters[CROP]);
+ return tasks
+ .filter((t) => !activeStatus.size || activeStatus.has(getTaskStatus(t)))
+ .filter((t) => !activeTypes.size || activeTypes.has(t.taskType.task_type_id.toString()))
+ .filter(
+ (t) =>
+ !activeLocations.size ||
+ t.locations.find(({ location_id }) => activeLocations.has(location_id)) ||
+ !t.locations.length
+ )
+ .filter(
+ (t) =>
+ !Object.values(filters[CROP]).find(({ active }) => active) ||
+ t.managementPlans.find(({ crop_variety_id }) => activeVarieties.has(crop_variety_id)),
+ )
+ .filter((t) => !activeAssignees.size || filterByAssignee(t, activeAssignees))
+ .filter((t) => filterByFromDate(t, filters[FROM_DATE]))
+ .filter((t) => filterByToDate(t, filters[TO_DATE]));
+}
diff --git a/packages/webapp/src/containers/WeatherBoard/index.js b/packages/webapp/src/containers/WeatherBoard/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/WeatherBoard/index.js
rename to packages/webapp/src/containers/WeatherBoard/index.jsx
diff --git a/packages/webapp/src/containers/WeatherBoard/saga.js b/packages/webapp/src/containers/WeatherBoard/saga.js
index ba73c83788..665129b5d2 100644
--- a/packages/webapp/src/containers/WeatherBoard/saga.js
+++ b/packages/webapp/src/containers/WeatherBoard/saga.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (saga.js) is part of LiteFarm.
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,8 +44,7 @@ export function* getWeatherSaga({ payload: args }) {
measurement !== weather?.measurement
) {
yield put(onLoadingWeatherStart(farm_id));
- const apikey = process.env.REACT_APP_WEATHER_API_KEY;
- const baseUri = 'https://cors-anywhere.litefarm.workers.dev/';
+ const apikey = import.meta.env.VITE_WEATHER_API_KEY;
const params = {
...args,
appid: apikey,
@@ -60,14 +59,7 @@ export function* getWeatherSaga({ payload: args }) {
for (const key in params) {
openWeatherUrl.searchParams.append(key, params[key]);
}
- const endPointToday = `${baseUri}?${openWeatherUrl.toString()}`;
- const config = {
- headers: {
- Authorization: 'Bearer ' + localStorage.getItem('farm_token'),
- },
- method: 'GET',
- };
- const weatherRes = yield call(axios.get, endPointToday, config);
+ const weatherRes = yield call(axios.get, openWeatherUrl.toString());
const weatherResData = weatherRes.data;
const weatherPayload = {
humidity: `${weatherResData.main?.humidity}%`,
diff --git a/packages/webapp/src/containers/WeatherBoard/utils/icons.js b/packages/webapp/src/containers/WeatherBoard/utils/icons.js
index 24bac3bc9f..407f347c5c 100644
--- a/packages/webapp/src/containers/WeatherBoard/utils/icons.js
+++ b/packages/webapp/src/containers/WeatherBoard/utils/icons.js
@@ -1,22 +1,20 @@
-module.exports = {
- icons: {
- '01d': 'wi-day-sunny',
- '02d': 'wi-day-cloudy',
- '03d': 'wi-cloudy',
- '04d': 'wi-cloudy',
- '09d': 'wi-showers',
- '10d': 'wi-day-rain',
- '11d': 'wi-day-thunderstorm',
- '13d': 'wi-day-snow-thunderstorm',
- '50d': 'wi-fog',
- '01n': 'wi-day-sunny',
- '02n': 'wi-day-cloudy',
- '03n': 'wi-cloudy',
- '04n': 'wi-cloudy',
- '09n': 'wi-showers',
- '10n': 'wi-day-rain',
- '11n': 'wi-day-thunderstorm',
- '13n': 'wi-day-snow-thunderstorm',
- '50n': 'wi-fog',
- },
+export const icons = {
+ '01d': 'wi-day-sunny',
+ '02d': 'wi-day-cloudy',
+ '03d': 'wi-cloudy',
+ '04d': 'wi-cloudy',
+ '09d': 'wi-showers',
+ '10d': 'wi-day-rain',
+ '11d': 'wi-day-thunderstorm',
+ '13d': 'wi-day-snow-thunderstorm',
+ '50d': 'wi-fog',
+ '01n': 'wi-day-sunny',
+ '02n': 'wi-day-cloudy',
+ '03n': 'wi-cloudy',
+ '04n': 'wi-cloudy',
+ '09n': 'wi-showers',
+ '10n': 'wi-day-rain',
+ '11n': 'wi-day-thunderstorm',
+ '13n': 'wi-day-snow-thunderstorm',
+ '50n': 'wi-fog',
};
diff --git a/packages/webapp/src/containers/WeatherBoard/utils/index.js b/packages/webapp/src/containers/WeatherBoard/utils/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/WeatherBoard/utils/index.js
rename to packages/webapp/src/containers/WeatherBoard/utils/index.jsx
diff --git a/packages/webapp/src/containers/WelcomeScreen/index.js b/packages/webapp/src/containers/WelcomeScreen/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/WelcomeScreen/index.js
rename to packages/webapp/src/containers/WelcomeScreen/index.jsx
diff --git a/packages/webapp/src/containers/cropSlice.js b/packages/webapp/src/containers/cropSlice.js
index 434ca937af..26b7a35b93 100644
--- a/packages/webapp/src/containers/cropSlice.js
+++ b/packages/webapp/src/containers/cropSlice.js
@@ -189,7 +189,7 @@ export const cropGroupAverages = createSelector([cropReducerSelector], ({ entiti
.map((k) => entities[k])
.reduce((averagesObject, crop) => {
const { crop_group } = crop;
- if (!!averagesObject[crop_group]) {
+ if (averagesObject[crop_group]) {
return { ...averagesObject, [crop_group]: cropsAverage(crop, averagesObject[crop_group]) };
} else {
return {
diff --git a/packages/webapp/src/containers/cropVarietySlice.js b/packages/webapp/src/containers/cropVarietySlice.js
index 800773962b..f9ae9b4d0d 100644
--- a/packages/webapp/src/containers/cropVarietySlice.js
+++ b/packages/webapp/src/containers/cropVarietySlice.js
@@ -173,3 +173,24 @@ export const suppliersSelector = createSelector([cropVarietiesSelector], (cropVa
suppliers.delete(null);
return Array.from(suppliers);
});
+
+export const suppliersByCropIdSelector = (cropId) => {
+ return createSelector([cropVarietiesSelector], (cropVarieties) => {
+ const suppliers = new Set(
+ cropVarieties.reduce((acc, { crop_id, supplier }) => {
+ if (crop_id === cropId) {
+ acc.push(supplier);
+ }
+ return acc;
+ }, []),
+ );
+ suppliers.delete(null);
+ return Array.from(suppliers);
+ });
+};
+
+export const cropVarietiesByCropIdSelector = (cropId) => {
+ return createSelector([cropVarietiesSelector], (cropVarieties) =>
+ cropVarieties.filter((c) => c.crop_id === cropId),
+ );
+};
diff --git a/packages/webapp/src/containers/documentSlice.js b/packages/webapp/src/containers/documentSlice.js
index e93e0aef45..dd2e401dbc 100644
--- a/packages/webapp/src/containers/documentSlice.js
+++ b/packages/webapp/src/containers/documentSlice.js
@@ -17,6 +17,7 @@ const getDocument = (obj) => {
'updated_at',
'files',
'no_expiration',
+ 'archived',
]);
};
@@ -67,8 +68,10 @@ const documentSlice = createSlice({
},
archiveDocumentSuccess(state, { payload: document_id }) {
return updateOneDocument(state, {
- document_id,
- valid_until: new Date('2000/1/1').toISOString(),
+ payload: {
+ document_id,
+ archived: true,
+ },
});
},
},
@@ -112,7 +115,11 @@ export const documentStatusSelector = createSelector(
);
const isValidDocument = (document, lastActiveDatetime) => {
- return lastActiveDatetime <= new Date(document.valid_until).getTime() || document.no_expiration;
+ return (
+ !document.archived &&
+ (lastActiveDatetime <= new Date(document.valid_until).getTime() ||
+ (!document.valid_until && document.no_expiration))
+ );
};
export const validDocumentSelector = createSelector(
[documentsSelector, lastActiveDatetimeSelector],
diff --git a/packages/webapp/src/containers/filterSlice.js b/packages/webapp/src/containers/filterSlice.js
index d66123dcea..bbff06ed00 100644
--- a/packages/webapp/src/containers/filterSlice.js
+++ b/packages/webapp/src/containers/filterSlice.js
@@ -1,7 +1,22 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
import { createSlice } from '@reduxjs/toolkit';
import { createSelector } from 'reselect';
-import { VALID_ON } from './Filter/constants';
import { getDateInputFormat } from '../util/moment';
+import i18n from '../locales/i18n';
const initialCropCatalogueFilter = {
STATUS: {},
@@ -13,10 +28,21 @@ const initialDocumentsFilter = {
TYPE: {},
VALID_ON: undefined,
};
+const intialTasksFilter = {
+ STATUS: {},
+ TYPE: {},
+ LOCATION: {},
+ CROP: {},
+ ASSIGNEE: {},
+ FROM_DATE: undefined,
+ TO_DATE: undefined,
+ IS_ASCENDING: false,
+};
export const initialState = {
cropCatalogue: initialCropCatalogueFilter,
documents: initialDocumentsFilter,
+ tasks: intialTasksFilter,
};
const filterSliceReducer = createSlice({
@@ -51,6 +77,68 @@ const filterSliceReducer = createSlice({
setDocumentsFilter: (state, { payload: documentsFilter }) => {
Object.assign(state.documents, documentsFilter);
},
+ resetTasksFilter: (state, { payload: { user_id, userFarms } }) => {
+ state.tasks = {
+ ...intialTasksFilter,
+ ASSIGNEE: userFarms.reduce((assignees, userFarm) => {
+ assignees[userFarm.user_id] = {
+ active: false,
+ label: `${userFarm.first_name} ${userFarm.last_name}`,
+ };
+ return assignees;
+ }, {}),
+ };
+ state.tasks.ASSIGNEE[user_id].active = true;
+ state.tasks.ASSIGNEE['unassigned'] = {
+ active: false,
+ label: i18n.t('TASK.UNASSIGNED'),
+ };
+ },
+ setTasksFilter: (state, { payload: tasksFilter }) => {
+ Object.assign(state.tasks, tasksFilter);
+ },
+ setTasksFilterUnassignedDueThisWeek: (state, { payload: { date = new Date() } }) => {
+ const oneWeekFromDate = new Date(date.valueOf());
+ oneWeekFromDate.setDate(date.getDate() + 6);
+ state.tasks = {
+ ...intialTasksFilter,
+ ASSIGNEE: Object.keys(state.tasks.ASSIGNEE).reduce((assignees, assigneeUserId) => {
+ assignees[assigneeUserId] = {
+ active: false,
+ label: state.tasks.ASSIGNEE[assigneeUserId].label,
+ };
+ return assignees;
+ }, {}),
+ FROM_DATE: getDateInputFormat(date),
+ TO_DATE: getDateInputFormat(oneWeekFromDate),
+ };
+ state.tasks.ASSIGNEE['unassigned'] = {
+ active: true,
+ label: i18n.t('TASK.UNASSIGNED'),
+ };
+ },
+ setTasksFilterDueToday: (
+ state,
+ { payload: { user_id, first_name, last_name, date = new Date() } },
+ ) => {
+ const dayBefore = new Date(date.valueOf());
+ dayBefore.setDate(date.getDate() - 1);
+ state.tasks = {
+ ...intialTasksFilter,
+ ASSIGNEE: Object.keys(state.tasks.ASSIGNEE).reduce((assignees, assigneeUserId) => {
+ assignees[assigneeUserId] = {
+ active: false,
+ };
+ return assignees;
+ }, {}),
+ FROM_DATE: getDateInputFormat(dayBefore),
+ TO_DATE: getDateInputFormat(date),
+ };
+ state.tasks.ASSIGNEE[user_id] = {
+ active: true,
+ label: `${first_name} ${last_name}`,
+ };
+ },
},
});
@@ -65,6 +153,10 @@ export const {
removeNonFilterValue,
resetDocumentsFilter,
setDocumentsFilter,
+ resetTasksFilter,
+ setTasksFilter,
+ setTasksFilterUnassignedDueThisWeek,
+ setTasksFilterDueToday,
} = filterSliceReducer.actions;
export default filterSliceReducer.reducer;
@@ -83,6 +175,10 @@ export const documentsFilterSelector = createSelector(
[filterReducerSelector],
(filterReducer) => filterReducer.documents,
);
+export const tasksFilterSelector = createSelector(
+ [filterReducerSelector],
+ (filterReducer) => filterReducer.tasks,
+);
export const cropCatalogueFilterDateSelector = createSelector(
[cropCatalogueFilterSelector],
(cropCatalogueFilter) => cropCatalogueFilter.date || getDateInputFormat(new Date()),
@@ -92,17 +188,20 @@ export const isFilterCurrentlyActiveSelector = (pageFilterKey) => {
return createSelector([filterReducerSelector], (filterReducer) => {
const targetPageFilter = filterReducer[pageFilterKey];
let isActive = false;
+
for (const filterKey in targetPageFilter) {
const filter = targetPageFilter[filterKey];
- if (filterKey === 'date') continue; // TODO: this is hacky, need to figure out if date can be stored differently, or if we can just remove it from initial state
- if (filterKey === VALID_ON) {
- isActive = isActive || !!filter;
- continue;
+ const filterType = typeof filter;
+
+ if (filterType === 'object') {
+ isActive = Object.values(filter).reduce((acc, curr) => {
+ return acc || curr.active;
+ }, isActive);
+ } else {
+ isActive = isActive || filterType === 'string';
}
- isActive = Object.values(filter).reduce((acc, curr) => {
- return acc || curr.active;
- }, isActive);
}
+
return isActive;
});
};
diff --git a/packages/webapp/src/containers/hooks/useDebounce.js b/packages/webapp/src/containers/hooks/useDebounce.js
new file mode 100644
index 0000000000..edab47ea7a
--- /dev/null
+++ b/packages/webapp/src/containers/hooks/useDebounce.js
@@ -0,0 +1,16 @@
+import { useRef } from 'react';
+
+export function useDebounce() {
+ const timeoutRef = useRef();
+ const blockRef = useRef(false);
+ return (callback, ms) => {
+ if (!blockRef.current) {
+ callback();
+ blockRef.current = true;
+ setTimeout(() => {
+ blockRef.current = false;
+ }, ms);
+ }
+ return () => timeoutRef.current && clearTimeout(timeoutRef.current);
+ };
+}
diff --git a/packages/webapp/src/containers/hooks/useHookFormPersist/HookFormPersistProvider.js b/packages/webapp/src/containers/hooks/useHookFormPersist/HookFormPersistProvider.jsx
similarity index 100%
rename from packages/webapp/src/containers/hooks/useHookFormPersist/HookFormPersistProvider.js
rename to packages/webapp/src/containers/hooks/useHookFormPersist/HookFormPersistProvider.jsx
diff --git a/packages/webapp/src/containers/hooks/useHookFormPersist/index.js b/packages/webapp/src/containers/hooks/useHookFormPersist/index.jsx
similarity index 100%
rename from packages/webapp/src/containers/hooks/useHookFormPersist/index.js
rename to packages/webapp/src/containers/hooks/useHookFormPersist/index.jsx
diff --git a/packages/webapp/src/containers/locationSlice.js b/packages/webapp/src/containers/locationSlice.js
index f074ee813f..bcadec8756 100644
--- a/packages/webapp/src/containers/locationSlice.js
+++ b/packages/webapp/src/containers/locationSlice.js
@@ -283,6 +283,11 @@ export const locationsSelector = createSelector(
},
);
+export const locationByIdSelector = (location_id) =>
+ createSelector(locationsSelector, (entities) =>
+ entities.find((entity) => entity.location_id === location_id),
+ );
+
export const locationEntitiesSelector = createSelector(
[
barnEntitiesSelector,
diff --git a/packages/webapp/src/containers/mapSlice.js b/packages/webapp/src/containers/mapSlice.js
index d3b89907f0..8910b0d36a 100644
--- a/packages/webapp/src/containers/mapSlice.js
+++ b/packages/webapp/src/containers/mapSlice.js
@@ -14,7 +14,7 @@ const mapLocationReducer = createSlice({
initialState,
reducers: {
setSuccessMessage: (state, { payload: [locationType, action] }) => {
- state.successMessage = `${locationType}${action}`;
+ state.successMessage = `${locationType} ${action?.toString()?.toLowerCase()}`;
},
canShowSuccessHeader: (state, { payload: showHeader }) => {
state.canShowSuccessHeader = showHeader;
diff --git a/packages/webapp/src/containers/notificationSlice.js b/packages/webapp/src/containers/notificationSlice.js
new file mode 100644
index 0000000000..a2e515fa63
--- /dev/null
+++ b/packages/webapp/src/containers/notificationSlice.js
@@ -0,0 +1,77 @@
+import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
+import { createSelector } from 'reselect';
+import { getNotificationCardDate } from '../util/moment';
+
+/**
+ * Generate action creators and action types that correspond to a specified initial state and a specified set of reducers.
+ * @see {@link https://redux-toolkit.js.org/api/createslice/}
+ */
+const addManyNotifications = (state, { payload: notifications }) => {
+ notificationAdapter.upsertMany(state, notifications);
+};
+
+const notificationAdapter = createEntityAdapter({
+ selectId: (notification) => notification.notification_id,
+});
+
+const notificationSlice = createSlice({
+ name: 'notificationReducer',
+ initialState: notificationAdapter.getInitialState({
+ loading: false,
+ loaded: false,
+ error: undefined,
+ }),
+ reducers: {
+ onLoadingNotificationStart: (state) => {
+ state.loading = true;
+ },
+ onLoadingNotificationFail: (state, { payload: error }) => {
+ state.loading = false;
+ state.error = error;
+ state.loaded = true;
+ },
+ getNotificationSuccess: (state, { payload: notifications }) => {
+ addManyNotifications(state, { payload: notifications });
+ state.loading = false;
+ state.loaded = true;
+ state.error = null;
+ },
+ },
+});
+
+export const { onLoadingNotificationStart, onLoadingNotificationFail, getNotificationSuccess } =
+ notificationSlice.actions;
+export default notificationSlice.reducer;
+
+export const notificationReducerSelector = (state) =>
+ state.farmStateReducer[notificationSlice.name];
+
+const notificationSelectors = notificationAdapter.getSelectors(
+ (state) => state.farmStateReducer[notificationSlice.name],
+);
+
+export const notificationEntitiesSelector = notificationSelectors.selectEntities;
+
+/**
+ * Generate a memoized selector function.
+ * @see {@link https://github.com/reduxjs/reselect#createselectorinputselectors--inputselectors-resultfunc-selectoroptions}
+ */
+export const notificationsSelector = createSelector(
+ // Call these selectors ...
+ notificationSelectors.selectAll,
+ // ... and pass the results to this ...
+ (notificationEntities) => {
+ // ... so that we re-render when there are changes to the notification entities.
+ return notificationEntities.map((notification) => {
+ return {
+ ...notification,
+ ...notification.variables,
+ created_at: getNotificationCardDate(notification.created_at),
+ };
+ });
+ },
+);
+
+export const notificationSelector = (notification_id) => (state) => {
+ return notificationSelectors.selectById(state, notification_id);
+};
diff --git a/packages/webapp/src/containers/saga.js b/packages/webapp/src/containers/saga.js
index 2729409588..4289ccf979 100644
--- a/packages/webapp/src/containers/saga.js
+++ b/packages/webapp/src/containers/saga.js
@@ -13,17 +13,7 @@
* GNU General Public License for more details, see .
*/
-import {
- all,
- call,
- delay,
- put,
- race,
- select,
- take,
- takeLatest,
- takeLeading,
-} from 'redux-saga/effects';
+import { all, call, delay, put, select, takeLatest, takeLeading } from 'redux-saga/effects';
import apiConfig, { url } from '../apiConfig';
import history from '../history';
import {
@@ -32,6 +22,7 @@ import {
patchFarmSuccess,
putUserSuccess,
selectFarmSuccess,
+ userFarmsByFarmSelector,
userFarmSelector,
} from './userFarmSlice';
import { createAction } from '@reduxjs/toolkit';
@@ -96,7 +87,7 @@ import { getExpense, getSales } from './Finances/actions';
import { logout } from '../util/jwt';
import { getGardensSuccess, onLoadingGardenFail, onLoadingGardenStart } from './gardenSlice';
import { getRoles } from './InviteUser/saga';
-import { getAllUserFarmsByFarmId } from './Profile/People/saga';
+import { getAllUserFarmsByFarmIDSaga } from './Profile/People/saga';
import {
getAllSupportedCertifications,
getAllSupportedCertifiers,
@@ -149,20 +140,19 @@ import {
getTasksSaga,
getTaskTypesSaga,
} from './Task/saga';
-import {
- getCertificationSurveysSuccess,
- onLoadingCertifierSurveyFail,
-} from './OrganicCertifierSurvey/slice';
+import notificationSaga, { getNotification } from './Notification/saga';
import { appVersionSelector, setAppVersion } from './appSettingSlice';
import { APP_VERSION } from '../util/constants';
import { hookFormPersistHistoryStackSelector } from './hooks/useHookFormPersist/hookFormPersistSlice';
+import axiosWithoutInterceptors from 'axios';
+import produce from 'immer';
+import { resetTasksFilter } from './filterSlice';
const logUserInfoUrl = () => `${url}/userLog`;
const getCropsByFarmIdUrl = (farm_id) => `${url}/crop/farm/${farm_id}`;
const getLocationsUrl = (farm_id) => `${url}/location/farm/${farm_id}`;
-export const axios = require('axios');
-axios.interceptors.response.use(
+axiosWithoutInterceptors.interceptors.response.use(
function (response) {
return response;
},
@@ -177,6 +167,7 @@ axios.interceptors.response.use(
return Promise.reject(error);
},
);
+export const axios = axiosWithoutInterceptors;
export function getHeader(user_id, farm_id, { headers, ...props } = {}) {
return {
@@ -197,20 +188,23 @@ export function* updateUserSaga({ payload: user }) {
let { user_id, farm_id } = yield select(loginSelector);
const header = getHeader(user_id, farm_id);
const { userUrl } = apiConfig;
- let data = user;
- if (data.wage === null) {
- delete data.wage;
- }
- if (data.phone_number === null) {
- delete data.phone_number;
- }
+ const data = produce(user, (user) => {
+ if (user.wage === null) {
+ delete user.wage;
+ }
+ if (user.phone_number === null) {
+ delete user.phone_number;
+ }
+ });
+
try {
const result = yield call(axios.put, userUrl + '/' + user_id, data, header);
- yield put(putUserSuccess({ ...user, farm_id }));
- i18n.changeLanguage(user.language_preference);
+ yield put(putUserSuccess({ ...user, farm_id, user_id }));
+ const t = yield call(i18n.changeLanguage, user.language_preference);
localStorage.setItem('litefarm_lang', user.language_preference);
- yield put(enqueueSuccessSnackbar(i18n.t('message:USER.SUCCESS.UPDATE')));
+ yield put(enqueueSuccessSnackbar(t('message:USER.SUCCESS.UPDATE')));
} catch (e) {
+ console.log(e);
yield put(enqueueErrorSnackbar(i18n.t('message:USER.ERROR.UPDATE')));
}
}
@@ -290,7 +284,7 @@ export const putFarm = createAction(`putFarmSaga`);
export function* putFarmSaga({ payload: farm }) {
const { farmUrl } = apiConfig;
- let { user_id, farm_id } = yield select(loginSelector);
+ let { user_id, farm_id, units } = yield select(userFarmSelector);
const header = getHeader(user_id, farm_id);
// OC: We should never update address information of a farm.
@@ -298,11 +292,13 @@ export function* putFarmSaga({ payload: farm }) {
if (data.farm_phone_number === null) {
delete data.farm_phone_number;
}
+ data.units = { measurement: data.units.measurement, currency: units.currency };
try {
const result = yield call(axios.put, farmUrl + '/' + farm_id, data, header);
- yield put(patchFarmSuccess(data));
+ yield put(patchFarmSuccess({ ...data, farm_id, user_id }));
yield put(enqueueSuccessSnackbar(i18n.t('message:FARM.SUCCESS.UPDATE')));
} catch (e) {
+ console.log(e);
yield put(enqueueErrorSnackbar(i18n.t('message:FARM.ERROR.UPDATE')));
}
}
@@ -564,8 +560,8 @@ export function* fetchAllSaga() {
];
const tasks = [
put(getRoles()),
- put(getAllUserFarmsByFarmId()),
put(getManagementPlansAndTasks()),
+ call(getAllUserFarmsByFarmIDSaga),
];
yield all(isAdmin ? [...tasks, ...adminTasks] : tasks);
@@ -578,40 +574,24 @@ export function* fetchAllSaga() {
if (appVersion !== APP_VERSION) {
yield put(setAppVersion());
}
+ const userFarms = yield select(userFarmsByFarmSelector);
+ yield put(resetTasksFilter({ user_id, userFarms }));
}
export const selectFarmAndFetchAll = createAction('selectFarmAndFetchAllSaga');
-export function* selectFarmAndFetchAllSaga({ payload: userFarm }) {
+export function* selectFarmAndFetchAllSaga({ payload: farm }) {
try {
- yield put(selectFarmSuccess(userFarm));
- const { has_consent, user_id, farm_id } = yield select(userFarmSelector);
- if (!has_consent) return history.push('/consent');
+ yield put(selectFarmSuccess(farm));
+ const userFarm = yield select(userFarmSelector);
+ if (!userFarm.has_consent) return history.push('/consent');
+ history.push({ pathname: '/' });
yield call(fetchAllSaga);
- const isAdmin = yield select(isAdminSelector);
- /**
- * wait for getManagementPlansAndTasks to finish
- */
- if (isAdmin) {
- yield put(waitForCertificationSurveyResultAndPushToHome());
- } else {
- history.push({ pathname: '/' });
- }
} catch (e) {
console.error('failed to fetch farm info', e);
}
}
-//TODO: remove after removing certification spotlight
-export const waitForCertificationSurveyResultAndPushToHome = createAction(
- 'waitForCertificationSurveyResultAndPushToHomeSaga',
-);
-
-export function* waitForCertificationSurveyResultAndPushToHomeSaga() {
- yield race([take(getCertificationSurveysSuccess.type), take(onLoadingCertifierSurveyFail.type)]);
- history.push({ pathname: '/' });
-}
-
export function* onReqSuccessSaga({ pathname, state, message }) {
const historyStack = yield select(hookFormPersistHistoryStackSelector);
const unlisten = history.listen(() => {
@@ -656,10 +636,7 @@ export default function* getFarmIdSaga() {
getManagementPlanAndPlantingMethodSuccess.type,
getManagementPlanAndPlantingMethodSuccessSaga,
);
- yield takeLatest(
- waitForCertificationSurveyResultAndPushToHome.type,
- waitForCertificationSurveyResultAndPushToHomeSaga,
- );
- yield takeLatest(getManagementPlansAndTasks.type, getManagementPlansAndTasksSaga);
+ yield takeLeading(getManagementPlansAndTasks.type, getManagementPlansAndTasksSaga);
yield takeLatest(getCropsAndManagementPlans.type, getCropsAndManagementPlansSaga);
+ yield takeLatest(getNotification.type, notificationSaga);
}
diff --git a/packages/webapp/src/containers/showedSpotlightSlice.js b/packages/webapp/src/containers/showedSpotlightSlice.js
index ef22040ffd..d176ef5536 100644
--- a/packages/webapp/src/containers/showedSpotlightSlice.js
+++ b/packages/webapp/src/containers/showedSpotlightSlice.js
@@ -10,6 +10,7 @@ const initialState = {
adjust_area: false,
adjust_line: false,
navigation: false,
+ notification: false,
introduce_map: false,
crop_catalog: false,
documents: false,
diff --git a/packages/webapp/src/containers/taskSlice.js b/packages/webapp/src/containers/taskSlice.js
index 13e09d6ad7..e7432fc0e0 100644
--- a/packages/webapp/src/containers/taskSlice.js
+++ b/packages/webapp/src/containers/taskSlice.js
@@ -1,5 +1,10 @@
import { createEntityAdapter, createSlice } from '@reduxjs/toolkit';
-import { loginSelector, onLoadingFail, onLoadingStart } from './userFarmSlice';
+import {
+ loginSelector,
+ onLoadingFail,
+ onLoadingStart,
+ userFarmEntitiesSelector,
+} from './userFarmSlice';
import { createSelector } from 'reselect';
import { pick } from '../util/pick';
import { managementPlanEntitiesSelector } from './managementPlanSlice';
@@ -30,11 +35,10 @@ export const getTask = (obj) => {
'duration',
'wage_at_moment',
'happiness',
- 'planned_time',
- 'completed_time',
+ 'complete_date',
'late_time',
'for_review_time',
- 'abandoned_time',
+ 'abandon_date',
'locations',
'managementPlans',
'abandonment_reason',
@@ -56,11 +60,11 @@ const upsertManyTasks = (state, { payload: tasks }) => {
);
};
-const updateOneTask = (state, { payload: task }) => {
+const upsertOneTask = (state, { payload: task }) => {
state.loading = false;
state.error = null;
state.loaded = true;
- taskAdapter.updateOne(state, task);
+ taskAdapter.upsertOne(state, task);
};
const updateManyTasks = (state, { payload: tasks }) => {
@@ -96,7 +100,7 @@ const taskSlice = createSlice({
})) || [],
})),
}),
- putTaskSuccess: updateOneTask,
+ putTaskSuccess: upsertOneTask,
putTasksSuccess: updateManyTasks,
createTaskSuccess: taskAdapter.addOne,
deleteTaskSuccess: taskAdapter.removeOne,
@@ -121,6 +125,8 @@ export const taskSelectors = taskAdapter.getSelectors(
//TODO: refactor
export const taskEntitiesSelector = createSelector(
[
+ userFarmEntitiesSelector,
+ loginSelector,
taskSelectors.selectEntities,
taskTypeEntitiesSelector,
managementPlanEntitiesSelector,
@@ -135,6 +141,8 @@ export const taskEntitiesSelector = createSelector(
plantingManagementPlanEntitiesSelector,
],
(
+ userFarmEntities,
+ userFarm,
taskEntities,
taskTypeEntities,
managementPlanEntities,
@@ -194,6 +202,8 @@ export const taskEntitiesSelector = createSelector(
getManagementPlanByPlantingManagementPlan(subtask),
];
}
+ taskEntities[task_id].assignee =
+ userFarmEntities[userFarm.farm_id][taskEntities[task_id].assignee_user_id];
}
});
},
@@ -250,7 +260,7 @@ export const tasksByManagementPlanIdSelector = (management_plan_id) =>
export const taskSelector = (task_id) => (state) => taskEntitiesSelector(state)[task_id];
export const getPendingTasks = (tasks) =>
- tasks.filter((task) => !task.abandoned_time && !task.completed_time);
+ tasks.filter((task) => !task.abandon_date && !task.complete_date);
export const pendingTasksSelector = createSelector([tasksSelector], getPendingTasks);
@@ -266,11 +276,11 @@ export const pendingTasksByManagementPlanIdSelector = (management_plan_id) =>
);
export const getCompletedTasks = (tasks) =>
- tasks.filter((task) => !task.abandoned_time && task.completed_time);
+ tasks.filter((task) => !task.abandon_date && task.complete_date);
export const completedTasksSelector = createSelector([tasksSelector], getCompletedTasks);
-export const getAbandonedTasks = (tasks) => tasks.filter((task) => task.abandoned_time);
+export const getAbandonedTasks = (tasks) => tasks.filter((task) => task.abandon_date);
export const abandonedTasksSelector = createSelector([tasksSelector], getAbandonedTasks);
diff --git a/packages/webapp/src/containers/userFarmSlice.js b/packages/webapp/src/containers/userFarmSlice.js
index f1a90a9505..518261f872 100644
--- a/packages/webapp/src/containers/userFarmSlice.js
+++ b/packages/webapp/src/containers/userFarmSlice.js
@@ -49,6 +49,7 @@ const addUserFarm = (state, { payload: userFarm }) => {
}
state.byFarmIdUserId[farm_id] = state.byFarmIdUserId[farm_id] || {};
state.byFarmIdUserId[farm_id][user_id] = userFarm;
+ delete state.byFarmIdUserId[farm_id][user_id].role;
};
const removeUserFarm = (state, { payload: userFarm }) => {
@@ -92,6 +93,7 @@ const userFarmSlice = createSlice({
state.byFarmIdUserId[farm_id] = prevUserFarms;
state.byFarmIdUserId[farm_id][user_id] = prevUserFarms[user_id] || {};
Object.assign(state.byFarmIdUserId[farm_id][user_id], userFarm);
+ delete state.byFarmIdUserId[farm_id][user_id].role;
});
},
postFarmSuccess: addUserFarm,
@@ -106,14 +108,8 @@ const userFarmSlice = createSlice({
});
},
patchConsentStepThreeSuccess: (state, { payload }) => {
- const {
- step_three,
- step_three_end,
- has_consent,
- consent_version,
- farm_id,
- user_id,
- } = payload;
+ const { step_three, step_three_end, has_consent, consent_version, farm_id, user_id } =
+ payload;
Object.assign(state.byFarmIdUserId[farm_id][user_id], {
step_three,
step_three_end,
@@ -163,10 +159,10 @@ const userFarmSlice = createSlice({
removeUserFarm(state, { payload: pseudoUserFarm });
addUserFarm(state, { payload: newUserFarm });
},
- setLoadingStart: (state, {}) => {
+ setLoadingStart: (state) => {
state.loading = true;
},
- setLoadingEnd: (state, {}) => {
+ setLoadingEnd: (state) => {
state.loading = false;
},
},
diff --git a/packages/webapp/src/history.js b/packages/webapp/src/history.js
index cc26d8a8db..8662d3bbfe 100644
--- a/packages/webapp/src/history.js
+++ b/packages/webapp/src/history.js
@@ -13,6 +13,7 @@
* GNU General Public License for more details, see .
*/
-const createHistory = require('history').createBrowserHistory;
+import { createBrowserHistory } from 'history';
-export default createHistory();
+const history = createBrowserHistory();
+export default history;
diff --git a/packages/webapp/src/index.js b/packages/webapp/src/index.js
deleted file mode 100644
index f2609ecbe1..0000000000
--- a/packages/webapp/src/index.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React from 'react';
-import ReactDOM from 'react-dom';
-import * as Sentry from '@sentry/react';
-import { Integrations } from '@sentry/tracing';
-import { Router } from 'react-router-dom';
-import history from './history';
-import { configureStore } from '@reduxjs/toolkit';
-import createSagaMiddleware from 'redux-saga';
-import homeSaga from './containers/saga';
-import addFarmSaga from './containers/AddFarm/saga';
-import peopleSaga from './containers/Profile/People/saga';
-import signUpSaga from './containers/CustomSignUp/saga';
-import resetUserPasswordSaga from './containers/PasswordResetAccount/saga';
-import outroSaga from './containers/Outro/saga';
-import locationSaga from './containers/LocationDetails/saga';
-import fieldLocationSaga from './containers/LocationDetails/AreaDetails/FieldDetailForm/saga';
-import documentSaga from './containers/Documents/saga';
-import managementPlanSaga from './containers/Crop/saga';
-import gardenSaga from './containers/LocationDetails/AreaDetails/GardenDetailForm/saga';
-import gateSaga from './containers/LocationDetails/PointDetails/GateDetailForm/saga';
-import waterValveSaga from './containers/LocationDetails/PointDetails/WaterValveDetailForm/saga';
-import naturalAreaSaga from './containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga';
-import barnSaga from './containers/LocationDetails/AreaDetails/BarnDetailForm/saga';
-import surfaceWaterSaga from './containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga';
-import greenhouseSaga from './containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga';
-import ceremonialSaga from './containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga';
-import residenceSaga from './containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga';
-import farmSiteBoundarySaga from './containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga';
-import fenceSaga from './containers/LocationDetails/LineDetails/FenceDetailForm/saga';
-import bufferZoneSaga from './containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga';
-import watercourseSaga from './containers/LocationDetails/LineDetails/WatercourseDetailForm/saga';
-import financeSaga from './containers/Finances/saga';
-import varietalSaga from './containers/AddCropVariety/saga';
-import insightSaga from './containers/Insights/saga';
-import farmDataSaga from './containers/Profile/Farm/saga';
-import chooseFarmSaga from './containers/ChooseFarm/saga';
-import supportSaga from './containers/Help/saga';
-import certifierSurveySaga from './containers/OrganicCertifierSurvey/saga';
-import consentSaga from './containers/Consent/saga';
-import callbackSaga from './containers/Callback/saga';
-import inviteUserSaga from './containers/InviteUser/saga';
-import exportSaga from './containers/ExportDownload/saga';
-import { Provider } from 'react-redux';
-import { persistReducer, persistStore } from 'redux-persist';
-import { PersistGate } from 'redux-persist/lib/integration/react';
-import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
-import storage from 'redux-persist/lib/storage';
-import rootReducer from './reducer';
-import { unregister } from './registerServiceWorker';
-import loginSaga from './containers/GoogleLoginButton/saga';
-import inviteSaga from './containers/InvitedUserCreateAccount/saga';
-import SSOInfoSaga from './containers/SSOUserCreateAccountInfo/saga';
-import weatherSaga from './containers/WeatherBoard/saga';
-import mapSaga from './containers/Map/saga';
-import uploadDocumentSaga from './containers/Documents/DocumentUploader/saga';
-import { CssBaseline, ThemeProvider } from '@material-ui/core';
-import theme from './assets/theme';
-import cropVarietyImageUploaderSaga from './containers/ImagePickerWrapper/saga';
-import certificationsSaga from './containers/Certifications/saga';
-import taskSaga from './containers/Task/saga';
-import abandonAndCompleteManagementPlanSaga from './containers/Crop/CompleteManagementPlan/saga';
-import errorHandlerSaga from './containers/ErrorHandler/saga';
-
-if (process.env.REACT_APP_SENTRY_DSN) {
- Sentry.init({
- dsn: process.env.REACT_APP_SENTRY_DSN,
- integrations: [new Integrations.BrowserTracing()],
-
- // Set tracesSampleRate to 1.0 to capture 100%
- // of transactions for performance monitoring.
- // We recommend adjusting this value in production
- tracesSampleRate: 0.7,
- });
-}
-// config for redux-persist
-const persistConfig = {
- key: 'root',
- storage,
- stateReconciler: autoMergeLevel2,
-};
-const languages = ['en', 'es', 'pt'];
-
-const persistedReducer = persistReducer(persistConfig, rootReducer);
-
-const sagaMiddleware = createSagaMiddleware();
-const middlewares = [sagaMiddleware];
-export const store = configureStore({
- reducer: persistedReducer,
- middleware: (getDefaultMiddleware) => [
- ...getDefaultMiddleware({
- thunk: true,
- immutableCheck: false,
- serializableCheck: false,
- }),
- ...middlewares,
- ],
- devTools: process.env.REACT_APP_ENV !== 'production',
-});
-
-// https://redux-toolkit.js.org/tutorials/advanced-tutorial#store-setup-and-hmr
-if (process.env.NODE_ENV === 'development' && module.hot) {
- module.hot.accept('./reducer', () => {
- const newRootReducer = require('./reducer').default;
- store.replaceReducer(newRootReducer);
- });
-}
-
-
-sagaMiddleware.run(homeSaga);
-// sagaMiddleware.run(createAccount);
-sagaMiddleware.run(addFarmSaga);
-sagaMiddleware.run(peopleSaga);
-sagaMiddleware.run(signUpSaga);
-sagaMiddleware.run(resetUserPasswordSaga);
-
-sagaMiddleware.run(outroSaga);
-
-sagaMiddleware.run(locationSaga);
-sagaMiddleware.run(fieldLocationSaga);
-sagaMiddleware.run(managementPlanSaga);
-sagaMiddleware.run(gardenSaga);
-sagaMiddleware.run(gateSaga);
-sagaMiddleware.run(barnSaga);
-sagaMiddleware.run(surfaceWaterSaga);
-sagaMiddleware.run(bufferZoneSaga);
-sagaMiddleware.run(naturalAreaSaga);
-sagaMiddleware.run(greenhouseSaga);
-sagaMiddleware.run(residenceSaga);
-sagaMiddleware.run(ceremonialSaga);
-sagaMiddleware.run(waterValveSaga);
-sagaMiddleware.run(farmSiteBoundarySaga);
-sagaMiddleware.run(fenceSaga);
-sagaMiddleware.run(watercourseSaga);
-sagaMiddleware.run(financeSaga);
-sagaMiddleware.run(varietalSaga);
-sagaMiddleware.run(insightSaga);
-sagaMiddleware.run(farmDataSaga);
-sagaMiddleware.run(chooseFarmSaga);
-sagaMiddleware.run(certifierSurveySaga);
-sagaMiddleware.run(consentSaga);
-sagaMiddleware.run(loginSaga);
-sagaMiddleware.run(supportSaga);
-sagaMiddleware.run(callbackSaga);
-sagaMiddleware.run(inviteSaga);
-sagaMiddleware.run(SSOInfoSaga);
-sagaMiddleware.run(weatherSaga);
-sagaMiddleware.run(inviteUserSaga);
-sagaMiddleware.run(mapSaga);
-sagaMiddleware.run(uploadDocumentSaga);
-sagaMiddleware.run(documentSaga);
-sagaMiddleware.run(cropVarietyImageUploaderSaga);
-sagaMiddleware.run(certificationsSaga);
-sagaMiddleware.run(taskSaga);
-sagaMiddleware.run(abandonAndCompleteManagementPlanSaga);
-sagaMiddleware.run(exportSaga);
-sagaMiddleware.run(errorHandlerSaga);
-
-
-const persistor = persistStore(store);
-
-export const purgeState = () => {
- persistor.purge();
-};
-
-export default () => {
- return { store, persistor };
-};
-
-const render = () => {
- const App = require('./App').default;
- ReactDOM.render(
-
-
-
- <>
-
-
- <>
-
- >
-
- >
-
-
- ,
- document.getElementById('root'),
- );
-};
-
-render();
-
-if (process.env.NODE_ENV === 'development' && module.hot) {
- module.hot.accept('./App', render);
-}
-
-//FIXME: service worker disabled for now. Causing problems when deploying: shows blank page until N+1th visit
-// https://twitter.com/dan_abramov/status/954146978564395008
-unregister();
diff --git a/packages/webapp/src/locales/i18n.js b/packages/webapp/src/locales/i18n.js
index 9c7e25d875..4d1b443a98 100644
--- a/packages/webapp/src/locales/i18n.js
+++ b/packages/webapp/src/locales/i18n.js
@@ -10,10 +10,12 @@ i18n
.use(I18nextBrowserLanguageDetector)
.init({
defaultNS: 'translation',
+ nsSeparator: ':',
fallbackLng: 'en',
- locales: ['en', 'pt', 'es'],
+ locales: ['en', 'pt', 'es', 'fr'],
debug: false,
detection: {
+ order: ['localStorage', 'navigator', 'querystring'],
lookupLocalStorage: 'litefarm_lang',
},
diff --git a/packages/webapp/src/main.jsx b/packages/webapp/src/main.jsx
new file mode 100644
index 0000000000..0bee9cf385
--- /dev/null
+++ b/packages/webapp/src/main.jsx
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (index.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import * as Sentry from '@sentry/react';
+import { Integrations } from '@sentry/tracing';
+import { Router } from 'react-router-dom';
+import history from './history';
+import homeSaga from './containers/saga';
+import addFarmSaga from './containers/AddFarm/saga';
+import peopleSaga from './containers/Profile/People/saga';
+import signUpSaga from './containers/CustomSignUp/saga';
+import resetUserPasswordSaga from './containers/PasswordResetAccount/saga';
+import outroSaga from './containers/Outro/saga';
+import locationSaga from './containers/LocationDetails/saga';
+import fieldLocationSaga from './containers/LocationDetails/AreaDetails/FieldDetailForm/saga';
+import documentSaga from './containers/Documents/saga';
+import managementPlanSaga from './containers/Crop/saga';
+import gardenSaga from './containers/LocationDetails/AreaDetails/GardenDetailForm/saga';
+import gateSaga from './containers/LocationDetails/PointDetails/GateDetailForm/saga';
+import waterValveSaga from './containers/LocationDetails/PointDetails/WaterValveDetailForm/saga';
+import naturalAreaSaga from './containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/saga';
+import barnSaga from './containers/LocationDetails/AreaDetails/BarnDetailForm/saga';
+import surfaceWaterSaga from './containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/saga';
+import greenhouseSaga from './containers/LocationDetails/AreaDetails/GreenhouseDetailForm/saga';
+import ceremonialSaga from './containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/saga';
+import residenceSaga from './containers/LocationDetails/AreaDetails/ResidenceDetailForm/saga';
+import farmSiteBoundarySaga from './containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/saga';
+import fenceSaga from './containers/LocationDetails/LineDetails/FenceDetailForm/saga';
+import bufferZoneSaga from './containers/LocationDetails/LineDetails/BufferZoneDetailForm/saga';
+import watercourseSaga from './containers/LocationDetails/LineDetails/WatercourseDetailForm/saga';
+import financeSaga from './containers/Finances/saga';
+import varietalSaga from './containers/AddCropVariety/saga';
+import insightSaga from './containers/Insights/saga';
+import chooseFarmSaga from './containers/ChooseFarm/saga';
+import supportSaga from './containers/Help/saga';
+import certifierSurveySaga from './containers/OrganicCertifierSurvey/saga';
+import consentSaga from './containers/Consent/saga';
+import callbackSaga from './containers/Callback/saga';
+import inviteUserSaga from './containers/InviteUser/saga';
+import exportSaga from './containers/ExportDownload/saga';
+import { Provider } from 'react-redux';
+import { PersistGate } from 'redux-persist/lib/integration/react';
+import loginSaga from './containers/GoogleLoginButton/saga';
+import inviteSaga from './containers/InvitedUserCreateAccount/saga';
+import SSOInfoSaga from './containers/SSOUserCreateAccountInfo/saga';
+import weatherSaga from './containers/WeatherBoard/saga';
+import alertSaga from './containers/Navigation/Alert/saga';
+import mapSaga from './containers/Map/saga';
+import uploadDocumentSaga from './containers/Documents/DocumentUploader/saga';
+import { CssBaseline, ThemeProvider } from '@material-ui/core';
+import theme from './assets/theme';
+import cropVarietyImageUploaderSaga from './containers/ImagePickerWrapper/saga';
+import certificationsSaga from './containers/Certifications/saga';
+import taskSaga from './containers/Task/saga';
+import abandonAndCompleteManagementPlanSaga from './containers/Crop/CompleteManagementPlan/saga';
+import notificationSaga from './containers/Notification/saga';
+import errorHandlerSaga from './containers/ErrorHandler/saga';
+import App from './App';
+import { sagaMiddleware } from './store/sagaMiddleware';
+import { persistor, store } from './store/store';
+import { GlobalScss } from './components/GlobalScss';
+
+if (import.meta.env.VITE_SENTRY_DSN) {
+ Sentry.init({
+ dsn: import.meta.env.VITE_SENTRY_DSN,
+ integrations: [new Integrations.BrowserTracing()],
+
+ // Set tracesSampleRate to 1.0 to capture 100%
+ // of transactions for performance monitoring.
+ // We recommend adjusting this value in production
+ tracesSampleRate: 0.7,
+ });
+}
+
+sagaMiddleware.run(homeSaga);
+sagaMiddleware.run(addFarmSaga);
+sagaMiddleware.run(peopleSaga);
+sagaMiddleware.run(signUpSaga);
+sagaMiddleware.run(resetUserPasswordSaga);
+sagaMiddleware.run(outroSaga);
+sagaMiddleware.run(locationSaga);
+sagaMiddleware.run(fieldLocationSaga);
+sagaMiddleware.run(managementPlanSaga);
+sagaMiddleware.run(gardenSaga);
+sagaMiddleware.run(gateSaga);
+sagaMiddleware.run(barnSaga);
+sagaMiddleware.run(surfaceWaterSaga);
+sagaMiddleware.run(bufferZoneSaga);
+sagaMiddleware.run(naturalAreaSaga);
+sagaMiddleware.run(greenhouseSaga);
+sagaMiddleware.run(residenceSaga);
+sagaMiddleware.run(ceremonialSaga);
+sagaMiddleware.run(waterValveSaga);
+sagaMiddleware.run(farmSiteBoundarySaga);
+sagaMiddleware.run(fenceSaga);
+sagaMiddleware.run(watercourseSaga);
+sagaMiddleware.run(financeSaga);
+sagaMiddleware.run(varietalSaga);
+sagaMiddleware.run(insightSaga);
+sagaMiddleware.run(chooseFarmSaga);
+sagaMiddleware.run(certifierSurveySaga);
+sagaMiddleware.run(consentSaga);
+sagaMiddleware.run(loginSaga);
+sagaMiddleware.run(supportSaga);
+sagaMiddleware.run(callbackSaga);
+sagaMiddleware.run(inviteSaga);
+sagaMiddleware.run(SSOInfoSaga);
+sagaMiddleware.run(weatherSaga);
+sagaMiddleware.run(alertSaga);
+sagaMiddleware.run(notificationSaga);
+sagaMiddleware.run(inviteUserSaga);
+sagaMiddleware.run(mapSaga);
+sagaMiddleware.run(uploadDocumentSaga);
+sagaMiddleware.run(documentSaga);
+sagaMiddleware.run(cropVarietyImageUploaderSaga);
+sagaMiddleware.run(certificationsSaga);
+sagaMiddleware.run(taskSaga);
+sagaMiddleware.run(abandonAndCompleteManagementPlanSaga);
+sagaMiddleware.run(exportSaga);
+sagaMiddleware.run(errorHandlerSaga);
+
+ReactDOM.render(
+
+
+
+ <>
+
+
+
+ <>
+
+ >
+
+ >
+
+
+ ,
+ document.getElementById('root'),
+);
+
+if (window.Cypress) {
+ window.store = store;
+}
diff --git a/packages/webapp/src/reducer/index.js b/packages/webapp/src/reducer/index.js
deleted file mode 100644
index c590bd2684..0000000000
--- a/packages/webapp/src/reducer/index.js
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import { combineReducers } from 'redux';
-import baseReducer from '../containers/reducer';
-import { combineForms } from 'react-redux-form';
-import { PURGE } from 'redux-persist';
-import insightReducer from '../containers/Insights/reducer';
-import financeReducer from '../containers/Finances/reducer';
-import farmReducer from '../containers/Profile/Farm/reducer';
-import certifierSurveyReducer from '../containers/OrganicCertifierSurvey/slice';
-import userFarmReducer from '../containers/userFarmSlice';
-import rolesReducer from '../containers/Profile/People/slice';
-import userLogReducer from '../containers/userLogSlice';
-import weatherReducer from '../containers/WeatherBoard/weatherSlice';
-import chooseFarmFlowReducer from '../containers/ChooseFarm/chooseFarmFlowSlice';
-
-import barnReducer from '../containers/barnSlice';
-import ceremonialReducer from '../containers/ceremonialSlice';
-import farmSiteBoundaryReducer from '../containers/farmSiteBoundarySlice';
-import fieldReducer from '../containers/fieldSlice';
-import gardenReducer from '../containers/gardenSlice';
-import greenhouseReducer from '../containers/greenhouseSlice';
-import surfaceWaterReducer from '../containers/surfaceWaterSlice';
-import naturalAreaReducer from '../containers/naturalAreaSlice';
-import residenceReducer from '../containers/residenceSlice';
-import bufferZoneReducer from '../containers/bufferZoneSlice';
-import watercourseReducer from '../containers/watercourseSlice';
-import fenceReducer from '../containers/fenceSlice';
-import gateReducer from '../containers/gateSlice';
-import waterValveReducer from '../containers/waterValveSlice';
-
-import cropReducer from '../containers/cropSlice';
-import cropVarietyReducer from '../containers/cropVarietySlice';
-import taskReducer from '../containers/taskSlice';
-import cleaningTaskReducer from '../containers/slice/taskSlice/cleaningTaskSlice';
-import fieldWorkTaskReducer from '../containers/slice/taskSlice/fieldWorkTaskSlice';
-import harvestTaskReducer from '../containers/slice/taskSlice/harvestTaskSlice';
-import pestControlTaskReducer from '../containers/slice/taskSlice/pestControlTaskSlice';
-import soilAmendmentTaskReducer from '../containers/slice/taskSlice/soilAmendmentTaskSlice';
-import plantTaskReducer from '../containers/slice/taskSlice/plantTaskSlice';
-import transplantTaskReducer from '../containers/slice/taskSlice/transplantTaskSlice';
-import harvestUseTypeReducer from '../containers/harvestUseTypeSlice';
-import taskTypeReducer from '../containers/taskTypeSlice';
-import productReducer from '../containers/productSlice';
-import homeReducer from '../containers/Home/homeSlice';
-import mapLocationReducer from '../containers/mapSlice';
-import mapFilterSettingReducer from '../containers/Map/mapFilterSettingSlice';
-import mapCacheReducer from '../containers/Map/mapCacheSlice';
-import showedSpotlightReducer from '../containers/showedSpotlightSlice';
-import hookFormPersistReducer from '../containers/hooks/useHookFormPersist/hookFormPersistSlice';
-import filterReducer from '../containers/filterSlice';
-import managementPlanReducer from '../containers/managementPlanSlice';
-import cropManagementPlanReducer from '../containers/cropManagementPlanSlice';
-import plantingManagementPlanReducer from '../containers/plantingManagementPlanSlice';
-import containerMethodReducer from '../containers/containerMethodSlice';
-import bedMethodReducer from '../containers/bedMethodSlice';
-import rowMethodReducer from '../containers/rowMethodSlice';
-import broadcastMethodReducer from '../containers/broadcastMethodSlice';
-import documentReducer from '../containers/documentSlice';
-import certificationReducer from '../containers/OrganicCertifierSurvey/certificationSlice';
-import certifierReducer from '../containers/OrganicCertifierSurvey/certifierSlice';
-import snackbarReducer from '../containers/Snackbar/snackbarSlice';
-import navbarReducer from '../containers/Navigation/navbarSlice';
-import appSettingReducer from '../containers/appSettingSlice';
-// all the initial state for the forms
-const initialFarmState = {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
-};
-
-const initialNotification = {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
-};
-
-const initialUserInfo = {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
-};
-
-const initialFarmInfo = {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
-};
-
-const editUserInfo = {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
-};
-
-const addUserInfo = {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
-};
-
-const signUpUserInfo = {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
-};
-
-const entitiesReducer = combineReducers({
- userFarmReducer,
- // userReducer,
- certifierSurveyReducer,
- rolesReducer,
- cropReducer,
- cropVarietyReducer,
- weatherReducer,
- barnReducer,
- ceremonialReducer,
- farmSiteBoundaryReducer,
- fieldReducer,
- gardenReducer,
- greenhouseReducer,
- surfaceWaterReducer,
- naturalAreaReducer,
- residenceReducer,
- bufferZoneReducer,
- watercourseReducer,
- fenceReducer,
- gateReducer,
- waterValveReducer,
- showedSpotlightReducer,
- managementPlanReducer,
- cropManagementPlanReducer,
- plantingManagementPlanReducer,
- containerMethodReducer,
- bedMethodReducer,
- rowMethodReducer,
- broadcastMethodReducer,
- documentReducer,
- certifierReducer,
- certificationReducer,
- taskReducer,
- cleaningTaskReducer,
- fieldWorkTaskReducer,
- harvestTaskReducer,
- pestControlTaskReducer,
- soilAmendmentTaskReducer,
- plantTaskReducer,
- transplantTaskReducer,
- taskTypeReducer,
- harvestUseTypeReducer,
- productReducer,
-});
-
-const persistedStateReducer = combineReducers({
- userLogReducer,
- chooseFarmFlowReducer,
- mapFilterSettingReducer,
- mapCacheReducer,
- appSettingReducer,
-});
-
-const tempStateReducer = combineReducers({
- homeReducer,
- mapLocationReducer,
- hookFormPersistReducer,
- filterReducer,
- snackbarReducer,
- navbarReducer,
-});
-
-// combine all reducers here and pass it to application
-const appReducer = combineReducers({
- profileForms: combineForms(
- {
- addInfo: addUserInfo,
- farm: initialFarmState,
- notification: initialNotification,
- userInfo: initialUserInfo,
- farmInfo: initialFarmInfo,
- editInfo: editUserInfo,
- signUpInfo: signUpUserInfo,
- },
- 'profileForms',
- ),
- entitiesReducer,
- persistedStateReducer,
- tempStateReducer,
- baseReducer,
- insightReducer,
- financeReducer,
- farmReducer,
-});
-
-const rootReducer = (state, action) => {
- if (action.type === PURGE) {
- // clear redux state
- state = undefined;
- }
-
- return appReducer(state, action);
-};
-
-export default rootReducer;
diff --git a/packages/webapp/src/registerServiceWorker.js b/packages/webapp/src/registerServiceWorker.js
index a32858da47..6acfec87dc 100644
--- a/packages/webapp/src/registerServiceWorker.js
+++ b/packages/webapp/src/registerServiceWorker.js
@@ -32,9 +32,9 @@ const isLocalhost = Boolean(
);
export default function register() {
- if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+ if (import.meta.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
- const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
+ const publicUrl = new URL(import.meta.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
@@ -43,7 +43,7 @@ export default function register() {
}
window.addEventListener('load', () => {
- const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
+ const swUrl = `${import.meta.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
diff --git a/packages/webapp/src/routes/BarnDetailsRoutes.js b/packages/webapp/src/routes/BarnDetailsRoutes.js
deleted file mode 100644
index 35ba7c67d8..0000000000
--- a/packages/webapp/src/routes/BarnDetailsRoutes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditBarnDetailForm from '../containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function BarnDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && }
- >
- );
-}
diff --git a/packages/webapp/src/routes/BarnDetailsRoutes.jsx b/packages/webapp/src/routes/BarnDetailsRoutes.jsx
new file mode 100644
index 0000000000..5918ad599a
--- /dev/null
+++ b/packages/webapp/src/routes/BarnDetailsRoutes.jsx
@@ -0,0 +1,17 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditBarnDetailForm from '../containers/LocationDetails/AreaDetails/BarnDetailForm/EditBarn';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function BarnDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && }
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/BufferZoneDetailsRoutes.js b/packages/webapp/src/routes/BufferZoneDetailsRoutes.js
deleted file mode 100644
index fe77aae20d..0000000000
--- a/packages/webapp/src/routes/BufferZoneDetailsRoutes.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditBufferZoneDetailForm from '../containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone';
-import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function BufferZoneDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
-
- >
- );
-}
diff --git a/packages/webapp/src/routes/BufferZoneDetailsRoutes.jsx b/packages/webapp/src/routes/BufferZoneDetailsRoutes.jsx
new file mode 100644
index 0000000000..da096402fa
--- /dev/null
+++ b/packages/webapp/src/routes/BufferZoneDetailsRoutes.jsx
@@ -0,0 +1,21 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditBufferZoneDetailForm from '../containers/LocationDetails/LineDetails/BufferZoneDetailForm/EditBufferZone';
+import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function BufferZoneDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.js b/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.js
deleted file mode 100644
index c1d264ce7c..0000000000
--- a/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditCeremonialAreaForm from '../containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function CeremonialAreaDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.jsx b/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.jsx
new file mode 100644
index 0000000000..e314a1e697
--- /dev/null
+++ b/packages/webapp/src/routes/CeremonialAreaDetailsRoutes.jsx
@@ -0,0 +1,23 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditCeremonialAreaForm from '../containers/LocationDetails/AreaDetails/CeremonialAreaDetailForm/EditCeremonialArea';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function CeremonialAreaDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.js b/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.js
deleted file mode 100644
index 6945a2665a..0000000000
--- a/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditFarmSiteBoundaryDetailForm from '../containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function FarmSiteBoundaryDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.jsx b/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.jsx
new file mode 100644
index 0000000000..b3522d78cb
--- /dev/null
+++ b/packages/webapp/src/routes/FarmSiteBoundaryDetailsRoutes.jsx
@@ -0,0 +1,27 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditFarmSiteBoundaryDetailForm from '../containers/LocationDetails/AreaDetails/FarmSiteBoundaryDetailForm/EditFarmSiteBoundary';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function FarmSiteBoundaryDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/FenceDetailsRoutes.js b/packages/webapp/src/routes/FenceDetailsRoutes.js
deleted file mode 100644
index 49e0c48bf7..0000000000
--- a/packages/webapp/src/routes/FenceDetailsRoutes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditFenceDetailForm from '../containers/LocationDetails/LineDetails/FenceDetailForm/EditFence';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function FenceDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && }
- >
- );
-}
diff --git a/packages/webapp/src/routes/FenceDetailsRoutes.jsx b/packages/webapp/src/routes/FenceDetailsRoutes.jsx
new file mode 100644
index 0000000000..e121194c09
--- /dev/null
+++ b/packages/webapp/src/routes/FenceDetailsRoutes.jsx
@@ -0,0 +1,17 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditFenceDetailForm from '../containers/LocationDetails/LineDetails/FenceDetailForm/EditFence';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function FenceDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && }
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/FieldDetailsRoutes.js b/packages/webapp/src/routes/FieldDetailsRoutes.js
deleted file mode 100644
index 338f866174..0000000000
--- a/packages/webapp/src/routes/FieldDetailsRoutes.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditFieldDetailForm from '../containers/LocationDetails/AreaDetails/FieldDetailForm/EditField';
-import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function FieldDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && }
-
- >
- );
-}
diff --git a/packages/webapp/src/routes/FieldDetailsRoutes.jsx b/packages/webapp/src/routes/FieldDetailsRoutes.jsx
new file mode 100644
index 0000000000..9af8a873c4
--- /dev/null
+++ b/packages/webapp/src/routes/FieldDetailsRoutes.jsx
@@ -0,0 +1,19 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditFieldDetailForm from '../containers/LocationDetails/AreaDetails/FieldDetailForm/EditField';
+import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+
+export default function FieldDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && }
+
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/GardenDetailsRoutes.js b/packages/webapp/src/routes/GardenDetailsRoutes.js
deleted file mode 100644
index 95d8d8b704..0000000000
--- a/packages/webapp/src/routes/GardenDetailsRoutes.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditGardenDetailForm from '../containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden';
-import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function GardenDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && }
-
- >
- );
-}
diff --git a/packages/webapp/src/routes/GardenDetailsRoutes.jsx b/packages/webapp/src/routes/GardenDetailsRoutes.jsx
new file mode 100644
index 0000000000..4fbec9a499
--- /dev/null
+++ b/packages/webapp/src/routes/GardenDetailsRoutes.jsx
@@ -0,0 +1,19 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditGardenDetailForm from '../containers/LocationDetails/AreaDetails/GardenDetailForm/EditGarden';
+import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function GardenDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && }
+
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/GateDetailsRoutes.js b/packages/webapp/src/routes/GateDetailsRoutes.js
deleted file mode 100644
index 7f92ecc57a..0000000000
--- a/packages/webapp/src/routes/GateDetailsRoutes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditGateDetailForm from '../containers/LocationDetails/PointDetails/GateDetailForm/EditGate';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function GateDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && }
- >
- );
-}
diff --git a/packages/webapp/src/routes/GateDetailsRoutes.jsx b/packages/webapp/src/routes/GateDetailsRoutes.jsx
new file mode 100644
index 0000000000..652fc3f5e2
--- /dev/null
+++ b/packages/webapp/src/routes/GateDetailsRoutes.jsx
@@ -0,0 +1,17 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditGateDetailForm from '../containers/LocationDetails/PointDetails/GateDetailForm/EditGate';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function GateDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && }
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/GreenhouseDetailsRoutes.js b/packages/webapp/src/routes/GreenhouseDetailsRoutes.js
deleted file mode 100644
index efe8cfc05a..0000000000
--- a/packages/webapp/src/routes/GreenhouseDetailsRoutes.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditGreenhouseDetailForm from '../containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse';
-import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function GreenhouseDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
-
- >
- );
-}
diff --git a/packages/webapp/src/routes/GreenhouseDetailsRoutes.jsx b/packages/webapp/src/routes/GreenhouseDetailsRoutes.jsx
new file mode 100644
index 0000000000..40aa237204
--- /dev/null
+++ b/packages/webapp/src/routes/GreenhouseDetailsRoutes.jsx
@@ -0,0 +1,21 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditGreenhouseDetailForm from '../containers/LocationDetails/AreaDetails/GreenhouseDetailForm/EditGreenhouse';
+import LocationManagementPlan from '../containers/LocationDetails/LocationManagementPlan';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function GreenhouseDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/NaturalAreaDetailsRoutes.js b/packages/webapp/src/routes/NaturalAreaDetailsRoutes.js
deleted file mode 100644
index a70f0cc44d..0000000000
--- a/packages/webapp/src/routes/NaturalAreaDetailsRoutes.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditNaturalAreaDetailForm from '../containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function NaturalAreaDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/NaturalAreaDetailsRoutes.jsx b/packages/webapp/src/routes/NaturalAreaDetailsRoutes.jsx
new file mode 100644
index 0000000000..d41e7d882e
--- /dev/null
+++ b/packages/webapp/src/routes/NaturalAreaDetailsRoutes.jsx
@@ -0,0 +1,23 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditNaturalAreaDetailForm from '../containers/LocationDetails/AreaDetails/NaturalAreaDetailForm/EditNaturalArea';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function NaturalAreaDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/Onboarding.js b/packages/webapp/src/routes/Onboarding.jsx
similarity index 100%
rename from packages/webapp/src/routes/Onboarding.js
rename to packages/webapp/src/routes/Onboarding.jsx
diff --git a/packages/webapp/src/routes/ResidenceDetailsRoutes.js b/packages/webapp/src/routes/ResidenceDetailsRoutes.js
deleted file mode 100644
index 7330331c6b..0000000000
--- a/packages/webapp/src/routes/ResidenceDetailsRoutes.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditResidenceDetailForm from '../containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function ResidenceDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/ResidenceDetailsRoutes.jsx b/packages/webapp/src/routes/ResidenceDetailsRoutes.jsx
new file mode 100644
index 0000000000..4878f397ca
--- /dev/null
+++ b/packages/webapp/src/routes/ResidenceDetailsRoutes.jsx
@@ -0,0 +1,19 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditResidenceDetailForm from '../containers/LocationDetails/AreaDetails/ResidenceDetailForm/EditResidence';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function ResidenceDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.js b/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.js
deleted file mode 100644
index d4b723f1c7..0000000000
--- a/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditSurfaceWaterDetailForm from '../containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function SurfaceWaterDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.jsx b/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.jsx
new file mode 100644
index 0000000000..f882cb075e
--- /dev/null
+++ b/packages/webapp/src/routes/SurfaceWaterDetailsRoutes.jsx
@@ -0,0 +1,27 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditSurfaceWaterDetailForm from '../containers/LocationDetails/AreaDetails/SurfaceWaterDetailForm/EditSurfaceWater';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function SurfaceWaterDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/WaterValveDetailsRoutes.js b/packages/webapp/src/routes/WaterValveDetailsRoutes.js
deleted file mode 100644
index fb60e4bc2c..0000000000
--- a/packages/webapp/src/routes/WaterValveDetailsRoutes.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditWaterValveDetailForm from '../containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function WaterValveDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/WaterValveDetailsRoutes.jsx b/packages/webapp/src/routes/WaterValveDetailsRoutes.jsx
new file mode 100644
index 0000000000..a3285c51ba
--- /dev/null
+++ b/packages/webapp/src/routes/WaterValveDetailsRoutes.jsx
@@ -0,0 +1,19 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditWaterValveDetailForm from '../containers/LocationDetails/PointDetails/WaterValveDetailForm/EditWaterValve';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function WaterValveDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/routes/WatercourseDetailsRoutes.js b/packages/webapp/src/routes/WatercourseDetailsRoutes.js
deleted file mode 100644
index 3b1c4ade7f..0000000000
--- a/packages/webapp/src/routes/WatercourseDetailsRoutes.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { Route } from 'react-router-dom';
-import React from 'react';
-import EditWatercourseDetailForm from '../containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse';
-import { useSelector } from 'react-redux';
-import { isAdminSelector } from '../containers/userFarmSlice';
-
-export default function WatercourseDetailsRoutes() {
- const isAdmin = useSelector(isAdminSelector);
- return (
- <>
-
- {isAdmin && (
-
- )}
- >
- );
-}
diff --git a/packages/webapp/src/routes/WatercourseDetailsRoutes.jsx b/packages/webapp/src/routes/WatercourseDetailsRoutes.jsx
new file mode 100644
index 0000000000..8be357f5cb
--- /dev/null
+++ b/packages/webapp/src/routes/WatercourseDetailsRoutes.jsx
@@ -0,0 +1,19 @@
+import { Route } from 'react-router-dom';
+import React from 'react';
+import EditWatercourseDetailForm from '../containers/LocationDetails/LineDetails/WatercourseDetailForm/EditWatercourse';
+import { useSelector } from 'react-redux';
+import { isAdminSelector } from '../containers/userFarmSlice';
+import LocationTasks from '../containers/LocationDetails/LocationTasks';
+
+export default function WatercourseDetailsRoutes() {
+ const isAdmin = useSelector(isAdminSelector);
+ return (
+ <>
+
+ {isAdmin && (
+
+ )}
+
+ >
+ );
+}
diff --git a/packages/webapp/src/store/actionTypes.js b/packages/webapp/src/store/actionTypes.js
new file mode 100644
index 0000000000..85d64b64f8
--- /dev/null
+++ b/packages/webapp/src/store/actionTypes.js
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2019, 2020, 2021, 2022 LiteFarm.org
+ * This file is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+export const ActionTypes = {
+ SWITCH_FARMS: 'chooseFarmFlowReducer/startSwitchFarmModal',
+};
diff --git a/packages/webapp/src/util/getFromReduxStore.js b/packages/webapp/src/store/getFromReduxStore.js
similarity index 95%
rename from packages/webapp/src/util/getFromReduxStore.js
rename to packages/webapp/src/store/getFromReduxStore.js
index e4ff3cbdcd..bb25bec5fe 100644
--- a/packages/webapp/src/util/getFromReduxStore.js
+++ b/packages/webapp/src/store/getFromReduxStore.js
@@ -1,4 +1,4 @@
-import { store } from '../index';
+import { store } from './store';
const getStore = () => {
return store;
diff --git a/packages/webapp/src/store/reducer.js b/packages/webapp/src/store/reducer.js
new file mode 100644
index 0000000000..1fe0635e0f
--- /dev/null
+++ b/packages/webapp/src/store/reducer.js
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ * This file (index.js) is part of LiteFarm.
+ *
+ * LiteFarm is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * LiteFarm is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details, see .
+ */
+
+import { combineReducers } from 'redux';
+import baseReducer from '../containers/reducer';
+import { combineForms } from 'react-redux-form';
+import { PURGE } from 'redux-persist';
+import insightReducer from '../containers/Insights/reducer';
+import financeReducer from '../containers/Finances/reducer';
+import certifierSurveyReducer from '../containers/OrganicCertifierSurvey/slice';
+import userFarmReducer from '../containers/userFarmSlice';
+import rolesReducer from '../containers/Profile/People/slice';
+import userLogReducer from '../containers/userLogSlice';
+import weatherReducer from '../containers/WeatherBoard/weatherSlice';
+import alertReducer from '../containers/Navigation/Alert/alertSlice';
+import notificationReducer from '../containers/notificationSlice';
+import chooseFarmFlowReducer from '../containers/ChooseFarm/chooseFarmFlowSlice';
+
+import barnReducer from '../containers/barnSlice';
+import ceremonialReducer from '../containers/ceremonialSlice';
+import farmSiteBoundaryReducer from '../containers/farmSiteBoundarySlice';
+import fieldReducer from '../containers/fieldSlice';
+import gardenReducer from '../containers/gardenSlice';
+import greenhouseReducer from '../containers/greenhouseSlice';
+import surfaceWaterReducer from '../containers/surfaceWaterSlice';
+import naturalAreaReducer from '../containers/naturalAreaSlice';
+import residenceReducer from '../containers/residenceSlice';
+import bufferZoneReducer from '../containers/bufferZoneSlice';
+import watercourseReducer from '../containers/watercourseSlice';
+import fenceReducer from '../containers/fenceSlice';
+import gateReducer from '../containers/gateSlice';
+import waterValveReducer from '../containers/waterValveSlice';
+
+import cropReducer from '../containers/cropSlice';
+import cropVarietyReducer from '../containers/cropVarietySlice';
+import taskReducer from '../containers/taskSlice';
+import cleaningTaskReducer from '../containers/slice/taskSlice/cleaningTaskSlice';
+import fieldWorkTaskReducer from '../containers/slice/taskSlice/fieldWorkTaskSlice';
+import harvestTaskReducer from '../containers/slice/taskSlice/harvestTaskSlice';
+import pestControlTaskReducer from '../containers/slice/taskSlice/pestControlTaskSlice';
+import soilAmendmentTaskReducer from '../containers/slice/taskSlice/soilAmendmentTaskSlice';
+import plantTaskReducer from '../containers/slice/taskSlice/plantTaskSlice';
+import transplantTaskReducer from '../containers/slice/taskSlice/transplantTaskSlice';
+import harvestUseTypeReducer from '../containers/harvestUseTypeSlice';
+import taskTypeReducer from '../containers/taskTypeSlice';
+import productReducer from '../containers/productSlice';
+import homeReducer from '../containers/Home/homeSlice';
+import mapLocationReducer from '../containers/mapSlice';
+import mapFilterSettingReducer from '../containers/Map/mapFilterSettingSlice';
+import mapCacheReducer from '../containers/Map/mapCacheSlice';
+import showedSpotlightReducer from '../containers/showedSpotlightSlice';
+import hookFormPersistReducer from '../containers/hooks/useHookFormPersist/hookFormPersistSlice';
+import filterReducer from '../containers/filterSlice';
+import managementPlanReducer from '../containers/managementPlanSlice';
+import cropManagementPlanReducer from '../containers/cropManagementPlanSlice';
+import plantingManagementPlanReducer from '../containers/plantingManagementPlanSlice';
+import containerMethodReducer from '../containers/containerMethodSlice';
+import bedMethodReducer from '../containers/bedMethodSlice';
+import rowMethodReducer from '../containers/rowMethodSlice';
+import broadcastMethodReducer from '../containers/broadcastMethodSlice';
+import documentReducer from '../containers/documentSlice';
+import certificationReducer from '../containers/OrganicCertifierSurvey/certificationSlice';
+import certifierReducer from '../containers/OrganicCertifierSurvey/certifierSlice';
+import snackbarReducer from '../containers/Snackbar/snackbarSlice';
+import appSettingReducer from '../containers/appSettingSlice';
+import { ActionTypes } from './actionTypes';
+// all the initial state for the forms
+const initialFarmState = {
+ farm_name: '',
+ address: '',
+ gridPoints: {},
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ sandbox: false,
+};
+
+const initialNotification = {
+ alert_pest: true,
+ alert_weather: true,
+ alert_worker_finish: true,
+ alert_before_planned_date: true,
+ alert_action_after_scouting: true,
+};
+
+const initialUserInfo = {
+ first_name: '',
+ last_name: '',
+ email: '',
+ phone_number: '',
+ address: '',
+ profile_picture: '',
+};
+
+const initialFarmInfo = {
+ farm_name: '',
+ unit: 'metric',
+ currency: 'CAD',
+ date: 'MM/DD/YY',
+ phone_number: '',
+ phone_country: '',
+ address: '',
+ gridPoints: {},
+};
+
+const editUserInfo = {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: 'hourly',
+ amount: 0,
+ },
+};
+
+const addUserInfo = {
+ first_name: '',
+ last_name: '',
+ email: '',
+ role: 'Worker',
+ pay: {
+ type: '',
+ amount: null,
+ },
+};
+
+const signUpUserInfo = {
+ first_name: '',
+ last_name: '',
+ email: '',
+ password: '',
+};
+
+const entitiesReducer = combineReducers({
+ userFarmReducer,
+ // userReducer,
+ certifierSurveyReducer,
+ rolesReducer,
+ cropReducer,
+ cropVarietyReducer,
+ weatherReducer,
+ alertReducer,
+ barnReducer,
+ ceremonialReducer,
+ farmSiteBoundaryReducer,
+ fieldReducer,
+ gardenReducer,
+ greenhouseReducer,
+ surfaceWaterReducer,
+ naturalAreaReducer,
+ residenceReducer,
+ bufferZoneReducer,
+ watercourseReducer,
+ fenceReducer,
+ gateReducer,
+ waterValveReducer,
+ showedSpotlightReducer,
+ managementPlanReducer,
+ cropManagementPlanReducer,
+ plantingManagementPlanReducer,
+ containerMethodReducer,
+ bedMethodReducer,
+ rowMethodReducer,
+ broadcastMethodReducer,
+ documentReducer,
+ certifierReducer,
+ certificationReducer,
+ taskReducer,
+ cleaningTaskReducer,
+ fieldWorkTaskReducer,
+ harvestTaskReducer,
+ pestControlTaskReducer,
+ soilAmendmentTaskReducer,
+ plantTaskReducer,
+ transplantTaskReducer,
+ taskTypeReducer,
+ harvestUseTypeReducer,
+ productReducer,
+});
+
+const farmStateReducer = combineReducers({
+ notificationReducer,
+});
+
+const persistedStateReducer = combineReducers({
+ userLogReducer,
+ chooseFarmFlowReducer,
+ mapFilterSettingReducer,
+ mapCacheReducer,
+ appSettingReducer,
+});
+
+const tempStateReducer = combineReducers({
+ homeReducer,
+ mapLocationReducer,
+ hookFormPersistReducer,
+ filterReducer,
+ snackbarReducer,
+});
+
+// combine all reducers here and pass it to application
+const appReducer = combineReducers({
+ profileForms: combineForms(
+ {
+ addInfo: addUserInfo,
+ farm: initialFarmState,
+ notification: initialNotification,
+ userInfo: initialUserInfo,
+ farmInfo: initialFarmInfo,
+ editInfo: editUserInfo,
+ signUpInfo: signUpUserInfo,
+ },
+ 'profileForms',
+ ),
+ entitiesReducer,
+ farmStateReducer,
+ persistedStateReducer,
+ tempStateReducer,
+ baseReducer,
+ insightReducer,
+ financeReducer,
+});
+
+const rootReducer = (state, action) => {
+ if (state && action.type === ActionTypes.SWITCH_FARMS) {
+ // selectively only reset farmStateReducer state when switching farms
+ const { farmStateReducer, ...otherReducers } = state;
+ state = otherReducers;
+ }
+ if (action.type === PURGE) {
+ // clear redux state
+ state = undefined;
+ }
+
+ return appReducer(state, action);
+};
+
+export default rootReducer;
diff --git a/packages/webapp/src/store/sagaMiddleware.js b/packages/webapp/src/store/sagaMiddleware.js
new file mode 100644
index 0000000000..1a9586bf15
--- /dev/null
+++ b/packages/webapp/src/store/sagaMiddleware.js
@@ -0,0 +1,3 @@
+import createSagaMiddleware from 'redux-saga';
+
+export const sagaMiddleware = createSagaMiddleware();
diff --git a/packages/webapp/src/store/store.js b/packages/webapp/src/store/store.js
new file mode 100644
index 0000000000..33457d04f2
--- /dev/null
+++ b/packages/webapp/src/store/store.js
@@ -0,0 +1,31 @@
+import { persistReducer, persistStore } from 'redux-persist';
+import { configureStore } from '@reduxjs/toolkit';
+import { sagaMiddleware } from './sagaMiddleware';
+import rootReducer from './reducer';
+import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
+import storage from 'redux-persist/lib/storage';
+
+const persistConfig = {
+ key: 'root',
+ storage,
+ stateReconciler: autoMergeLevel2,
+};
+const persistedReducer = persistReducer(persistConfig, rootReducer);
+const middlewares = [sagaMiddleware];
+export const store = configureStore({
+ reducer: persistedReducer,
+ middleware: (getDefaultMiddleware) => [
+ ...getDefaultMiddleware({
+ thunk: true,
+ immutableCheck: false,
+ serializableCheck: false,
+ }),
+ ...middlewares,
+ ],
+ devTools: import.meta.env.VITE_ENV !== 'production',
+});
+
+export const purgeState = () => {
+ persistor.purge();
+};
+export const persistor = persistStore(store);
diff --git a/packages/webapp/src/stories/ActiveFilterBox/ActiveFilterBox.stories.js b/packages/webapp/src/stories/ActiveFilterBox/ActiveFilterBox.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/ActiveFilterBox/ActiveFilterBox.stories.js
rename to packages/webapp/src/stories/ActiveFilterBox/ActiveFilterBox.stories.jsx
diff --git a/packages/webapp/src/stories/Button/Button.stories.js b/packages/webapp/src/stories/Button/Button.stories.js
deleted file mode 100644
index 17a0f938b3..0000000000
--- a/packages/webapp/src/stories/Button/Button.stories.js
+++ /dev/null
@@ -1,78 +0,0 @@
-import React from 'react';
-import Button from '../../components/Form/Button';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Button',
- component: Button,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-const TemplateWithText = (args) => (
- <>
-
- Override button style by passing style object to style prop or by passing in a className
- string. To remove background color and pass in a bootstrap className, color need to be set to
- 'none'
-
-
- >
-);
-export const Primary = Template.bind({});
-Primary.args = {
- color: 'primary',
- children: 'Primary',
-};
-
-export const Secondary = Template.bind({});
-Secondary.args = {
- color: 'secondary',
- children: 'Secondary',
-};
-
-export const Success = Template.bind({});
-Success.args = {
- color: 'success',
- children: 'Success',
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- color: 'primary',
- children: 'Disabled',
- disabled: true,
-};
-
-export const PrimarySmall = Template.bind({});
-PrimarySmall.args = {
- color: 'primary',
- children: 'Primary',
- sm: true,
-};
-
-export const SecondarySmall = Template.bind({});
-SecondarySmall.args = {
- color: 'secondary',
- children: 'Secondary',
- sm: true,
-};
-
-export const DisabledSmall = Template.bind({});
-DisabledSmall.args = {
- color: 'primary',
- children: 'Disabled',
- disabled: true,
- sm: true,
-};
-
-const style = {
- background: 'linear-gradient(to right, orange , yellow, green, cyan, blue, violet)',
-};
-
-export const InjectStyle = TemplateWithText.bind({});
-InjectStyle.args = {
- color: 'primary',
- label: 'Button',
- style: style,
-};
diff --git a/packages/webapp/src/stories/Button/Button.stories.jsx b/packages/webapp/src/stories/Button/Button.stories.jsx
new file mode 100644
index 0000000000..bdb93d5157
--- /dev/null
+++ b/packages/webapp/src/stories/Button/Button.stories.jsx
@@ -0,0 +1,78 @@
+import React from 'react';
+import Button from '../../components/Form/Button';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Button',
+ component: Button,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+const TemplateWithText = (args) => (
+ <>
+
+ Override button style by passing style object to style prop or by passing in a className
+ string. To remove background color and pass in a global css className, color need to be set to
+ 'none'
+
+
+ >
+);
+export const Primary = Template.bind({});
+Primary.args = {
+ color: 'primary',
+ children: 'Primary',
+};
+
+export const Secondary = Template.bind({});
+Secondary.args = {
+ color: 'secondary',
+ children: 'Secondary',
+};
+
+export const Success = Template.bind({});
+Success.args = {
+ color: 'success',
+ children: 'Success',
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ color: 'primary',
+ children: 'Disabled',
+ disabled: true,
+};
+
+export const PrimarySmall = Template.bind({});
+PrimarySmall.args = {
+ color: 'primary',
+ children: 'Primary',
+ sm: true,
+};
+
+export const SecondarySmall = Template.bind({});
+SecondarySmall.args = {
+ color: 'secondary',
+ children: 'Secondary',
+ sm: true,
+};
+
+export const DisabledSmall = Template.bind({});
+DisabledSmall.args = {
+ color: 'primary',
+ children: 'Disabled',
+ disabled: true,
+ sm: true,
+};
+
+const style = {
+ background: 'linear-gradient(to right, orange , yellow, green, cyan, blue, violet)',
+};
+
+export const InjectStyle = TemplateWithText.bind({});
+InjectStyle.args = {
+ color: 'primary',
+ label: 'Button',
+ style: style,
+};
diff --git a/packages/webapp/src/stories/Button/DropdownButton.stories.js b/packages/webapp/src/stories/Button/DropdownButton.stories.js
deleted file mode 100644
index a510be0b0f..0000000000
--- a/packages/webapp/src/stories/Button/DropdownButton.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import DropdownButton from '../../components/Form/DropDownButton';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/DropdownButton',
- component: DropdownButton,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- options: [{ text: 'option1' }, { text: 'option2' }, { text: 'option3' }],
- children: 'Dropdown',
-};
diff --git a/packages/webapp/src/stories/Button/DropdownButton.stories.jsx b/packages/webapp/src/stories/Button/DropdownButton.stories.jsx
new file mode 100644
index 0000000000..a339cb137a
--- /dev/null
+++ b/packages/webapp/src/stories/Button/DropdownButton.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import DropdownButton from '../../components/Form/DropDownButton';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/DropdownButton',
+ component: DropdownButton,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ options: [{ text: 'option1' }, { text: 'option2' }, { text: 'option3' }],
+ children: 'Dropdown',
+};
diff --git a/packages/webapp/src/stories/Button/GoogleLoginButton.stories.js b/packages/webapp/src/stories/Button/GoogleLoginButton.stories.js
deleted file mode 100644
index 6abea77746..0000000000
--- a/packages/webapp/src/stories/Button/GoogleLoginButton.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../Pages/config/decorators';
-import GoogleLoginButton from '../../containers/GoogleLoginButton';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/GoogleLoginButton',
- decorators: decorators,
- component: GoogleLoginButton,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Button/GoogleLoginButton.stories.jsx b/packages/webapp/src/stories/Button/GoogleLoginButton.stories.jsx
new file mode 100644
index 0000000000..951f53c511
--- /dev/null
+++ b/packages/webapp/src/stories/Button/GoogleLoginButton.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../Pages/config/Decorators';
+import GoogleLoginButton from '../../containers/GoogleLoginButton';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/GoogleLoginButton',
+ decorators: decorators,
+ component: GoogleLoginButton,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Card/Card.stories.js b/packages/webapp/src/stories/Card/Card.stories.js
deleted file mode 100644
index 7e592ae94a..0000000000
--- a/packages/webapp/src/stories/Card/Card.stories.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import React from 'react';
-import Card from '../../components/Card';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Card',
- component: Card,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- color: 'primary',
- children: 'Primary',
-};
-
-export const Secondary = Template.bind({});
-Secondary.args = {
- color: 'secondary',
- children: 'Secondary',
-};
-
-export const Active = Template.bind({});
-Active.args = {
- color: 'active',
- children: 'Active',
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- color: 'disabled',
- children: 'Disabled',
-};
-
-export const Info = Template.bind({});
-Info.args = {
- color: 'info',
- children: 'info',
-};
-
-export const Blue = Template.bind({});
-Blue.args = {
- color: 'blue',
- children: 'blue',
-};
-
-export const BlueActive = Template.bind({});
-BlueActive.args = {
- color: 'blueActive',
- children: 'blueActive',
-};
-
-export const Completed = Template.bind({});
-Completed.args = {
- color: 'completed',
- children: 'completed',
-};
-
-export const CompletedActive = Template.bind({});
-CompletedActive.args = {
- color: 'completedActive',
- children: 'completedActive',
-};
-
-export const None = Template.bind({});
-None.args = {
- color: 'none',
- children: 'none',
-};
diff --git a/packages/webapp/src/stories/Card/Card.stories.jsx b/packages/webapp/src/stories/Card/Card.stories.jsx
new file mode 100644
index 0000000000..aba93d1de1
--- /dev/null
+++ b/packages/webapp/src/stories/Card/Card.stories.jsx
@@ -0,0 +1,70 @@
+import React from 'react';
+import Card from '../../components/Card';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Card',
+ component: Card,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ color: 'primary',
+ children: 'Primary',
+};
+
+export const Secondary = Template.bind({});
+Secondary.args = {
+ color: 'secondary',
+ children: 'Secondary',
+};
+
+export const Active = Template.bind({});
+Active.args = {
+ color: 'active',
+ children: 'Active',
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ color: 'disabled',
+ children: 'Disabled',
+};
+
+export const Info = Template.bind({});
+Info.args = {
+ color: 'info',
+ children: 'info',
+};
+
+export const Blue = Template.bind({});
+Blue.args = {
+ color: 'blue',
+ children: 'blue',
+};
+
+export const BlueActive = Template.bind({});
+BlueActive.args = {
+ color: 'blueActive',
+ children: 'blueActive',
+};
+
+export const Completed = Template.bind({});
+Completed.args = {
+ color: 'completed',
+ children: 'completed',
+};
+
+export const CompletedActive = Template.bind({});
+CompletedActive.args = {
+ color: 'completedActive',
+ children: 'completedActive',
+};
+
+export const None = Template.bind({});
+None.args = {
+ color: 'none',
+ children: 'none',
+};
diff --git a/packages/webapp/src/stories/Card/CardWithStatus.stories.js b/packages/webapp/src/stories/Card/CardWithStatus.stories.js
deleted file mode 100644
index 5f900ae0cb..0000000000
--- a/packages/webapp/src/stories/Card/CardWithStatus.stories.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import { CardWithStatus } from '../../components/CardWithStatus';
-
-export default {
- title: 'Components/CardWithStatus',
- component: CardWithStatus,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const TaskForReview = Template.bind({});
-TaskForReview.args = {
- color: 'secondary',
- children: 'For review',
- status: 'active',
- label: 'For Review',
- style: { height: '100px' },
-};
-
-export const TaskForReviewActive = Template.bind({});
-TaskForReviewActive.args = {
- color: 'active',
- children: 'For review selected',
- status: 'active',
- label: 'For Review',
-};
-
-export const TaskPlanned = Template.bind({});
-TaskPlanned.args = {
- color: 'secondary',
- children: 'planned',
- status: 'planned',
- label: 'Planned',
-};
-
-export const TaskPlannedActive = Template.bind({});
-TaskPlannedActive.args = {
- color: 'active',
- children: 'planned active',
- status: 'planned',
- label: 'Planned',
-};
-
-export const TaskLate = Template.bind({});
-TaskLate.args = {
- color: 'secondary',
- children: 'late',
- status: 'late',
- label: 'Late',
-};
-
-export const TaskLateActive = Template.bind({});
-TaskLateActive.args = {
- color: 'active',
- children: 'late active',
- status: 'late',
- label: 'Late',
-};
-
-export const TaskCompleted = Template.bind({});
-TaskCompleted.args = {
- color: 'completed',
- children: 'completed',
- status: 'completed',
- label: 'Completed',
- score: 0,
-};
-
-export const TaskCompletedActive = Template.bind({});
-TaskCompletedActive.args = {
- color: 'completedActive',
- children: 'completed',
- status: 'completed',
- label: 'Completed',
- score: 1,
-};
-
-export const TaskAbandoned = Template.bind({});
-TaskAbandoned.args = {
- color: 'completed',
- children: 'completed',
- status: 'abandoned',
- label: 'Abandoned',
-};
-
-export const TaskAbandonedActive = Template.bind({});
-TaskAbandonedActive.args = {
- color: 'completedActive',
- children: 'completed',
- status: 'abandoned',
- label: 'Abandoned',
-};
-
-export const TaskDisabled = Template.bind({});
-TaskDisabled.args = {
- color: 'disabled',
- children: 'Disabled',
- status: 'disabled',
- label: 'Disabled',
-};
diff --git a/packages/webapp/src/stories/Card/CardWithStatus.stories.jsx b/packages/webapp/src/stories/Card/CardWithStatus.stories.jsx
new file mode 100644
index 0000000000..4ddcf6e6f3
--- /dev/null
+++ b/packages/webapp/src/stories/Card/CardWithStatus.stories.jsx
@@ -0,0 +1,101 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { CardWithStatus } from '../../components/CardWithStatus';
+
+export default {
+ title: 'Components/CardWithStatus',
+ component: CardWithStatus,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const TaskForReview = Template.bind({});
+TaskForReview.args = {
+ color: 'secondary',
+ children: 'For review',
+ status: 'active',
+ label: 'For Review',
+ style: { height: '100px' },
+};
+
+export const TaskForReviewActive = Template.bind({});
+TaskForReviewActive.args = {
+ color: 'active',
+ children: 'For review selected',
+ status: 'active',
+ label: 'For Review',
+};
+
+export const TaskPlanned = Template.bind({});
+TaskPlanned.args = {
+ color: 'secondary',
+ children: 'planned',
+ status: 'planned',
+ label: 'Planned',
+};
+
+export const TaskPlannedActive = Template.bind({});
+TaskPlannedActive.args = {
+ color: 'active',
+ children: 'planned active',
+ status: 'planned',
+ label: 'Planned',
+};
+
+export const TaskLate = Template.bind({});
+TaskLate.args = {
+ color: 'secondary',
+ children: 'late',
+ status: 'late',
+ label: 'Late',
+};
+
+export const TaskLateActive = Template.bind({});
+TaskLateActive.args = {
+ color: 'active',
+ children: 'late active',
+ status: 'late',
+ label: 'Late',
+};
+
+export const TaskCompleted = Template.bind({});
+TaskCompleted.args = {
+ color: 'completed',
+ children: 'completed',
+ status: 'completed',
+ label: 'Completed',
+ score: 0,
+};
+
+export const TaskCompletedActive = Template.bind({});
+TaskCompletedActive.args = {
+ color: 'completedActive',
+ children: 'completed',
+ status: 'completed',
+ label: 'Completed',
+ score: 1,
+};
+
+export const TaskAbandoned = Template.bind({});
+TaskAbandoned.args = {
+ color: 'completed',
+ children: 'completed',
+ status: 'abandoned',
+ label: 'Abandoned',
+};
+
+export const TaskAbandonedActive = Template.bind({});
+TaskAbandonedActive.args = {
+ color: 'completedActive',
+ children: 'completed',
+ status: 'abandoned',
+ label: 'Abandoned',
+};
+
+export const TaskDisabled = Template.bind({});
+TaskDisabled.args = {
+ color: 'disabled',
+ children: 'Disabled',
+ status: 'disabled',
+ label: 'Disabled',
+};
diff --git a/packages/webapp/src/stories/Card/ManagementPlanCard.stories.js b/packages/webapp/src/stories/Card/ManagementPlanCard.stories.js
deleted file mode 100644
index 5c77f9da84..0000000000
--- a/packages/webapp/src/stories/Card/ManagementPlanCard.stories.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import { ManagementPlanCard } from '../../components/CardWithStatus/ManagementPlanCard/ManagementPlanCard';
-import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
-
-export default {
- title: 'Components/ManagementPlanCard',
- component: ManagementPlanCard,
- decorators: componentDecorators,
- parameters: {
- viewport: {
- viewports: INITIAL_VIEWPORTS,
- },
- },
-};
-
-const multiRowNotes = 'multi row, '.repeat(100);
-
-const Template = (args) => ;
-export const Active = Template.bind({});
-Active.args = {
- managementPlanName: 'Management Plan',
- locationName: 'Field 1',
- notes: 'Row 1',
- startDate: '01-01-2021',
- endDate: '01-02-2021',
- numberOfPendingTask: 0,
- status: 'active',
-};
-
-export const Planned = Template.bind({});
-Planned.args = {
- managementPlanName: 'Management Plan',
- locationName: 'Field 1',
- notes: 'Bed 1',
- numberOfPendingTask: 1,
- status: 'planned',
-};
-
-export const Abandoned = Template.bind({});
-Abandoned.args = {
- managementPlanName: 'Management Plan',
- locationName: 'Field 1',
- notes: multiRowNotes,
- startDate: '01-01-2021',
- endDate: '01-02-2021',
- numberOfPendingTask: 1234567,
- score: 1,
- status: 'abandoned',
-};
-
-export const Completed = Template.bind({});
-Completed.args = {
- managementPlanName: 'Management Plan',
- locationName: 'Field 1',
- startDate: '01-01-2021',
- numberOfPendingTask: 3,
- score: 4,
- status: 'completed',
-};
-
-export const iphone5 = Template.bind({});
-iphone5.parameters = {
- viewport: {
- defaultViewport: 'iphone5',
- },
-};
-iphone5.args = {
- managementPlanName: 'Management Plan',
- locationName: 'Field 1',
- notes: multiRowNotes,
- startDate: '01-01-2021',
- endDate: '01-02-2021',
- numberOfPendingTask: 1234567,
- score: 1,
- status: 'abandoned',
-};
diff --git a/packages/webapp/src/stories/Card/ManagementPlanCard.stories.jsx b/packages/webapp/src/stories/Card/ManagementPlanCard.stories.jsx
new file mode 100644
index 0000000000..53f5a49547
--- /dev/null
+++ b/packages/webapp/src/stories/Card/ManagementPlanCard.stories.jsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { ManagementPlanCard } from '../../components/CardWithStatus/ManagementPlanCard/ManagementPlanCard';
+import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport';
+
+export default {
+ title: 'Components/ManagementPlanCard',
+ component: ManagementPlanCard,
+ decorators: componentDecorators,
+ parameters: {
+ viewport: {
+ viewports: INITIAL_VIEWPORTS,
+ },
+ },
+};
+
+const multiRowNotes = 'multi row, '.repeat(100);
+
+const Template = (args) => ;
+export const Active = Template.bind({});
+Active.args = {
+ managementPlanName: 'Management Plan',
+ locationName: 'Field 1',
+ notes: 'Row 1',
+ startDate: '01-01-2021',
+ endDate: '01-02-2021',
+ numberOfPendingTask: 0,
+ status: 'active',
+};
+
+export const Planned = Template.bind({});
+Planned.args = {
+ managementPlanName: 'Management Plan',
+ locationName: 'Field 1',
+ notes: 'Bed 1',
+ numberOfPendingTask: 1,
+ status: 'planned',
+};
+
+export const Abandoned = Template.bind({});
+Abandoned.args = {
+ managementPlanName: 'Management Plan',
+ locationName: 'Field 1',
+ notes: multiRowNotes,
+ startDate: '01-01-2021',
+ endDate: '01-02-2021',
+ numberOfPendingTask: 1234567,
+ score: 1,
+ status: 'abandoned',
+};
+
+export const Completed = Template.bind({});
+Completed.args = {
+ managementPlanName: 'Management Plan',
+ locationName: 'Field 1',
+ startDate: '01-01-2021',
+ numberOfPendingTask: 3,
+ score: 4,
+ status: 'completed',
+};
+
+export const iphone5 = Template.bind({});
+iphone5.parameters = {
+ viewport: {
+ defaultViewport: 'iphone5',
+ },
+};
+iphone5.args = {
+ managementPlanName: 'Management Plan',
+ locationName: 'Field 1',
+ notes: multiRowNotes,
+ startDate: '01-01-2021',
+ endDate: '01-02-2021',
+ numberOfPendingTask: 1234567,
+ score: 1,
+ status: 'abandoned',
+};
diff --git a/packages/webapp/src/stories/Card/NewFeatureCard.stories.js b/packages/webapp/src/stories/Card/NewFeatureCard.stories.js
deleted file mode 100644
index 5b16469299..0000000000
--- a/packages/webapp/src/stories/Card/NewFeatureCard.stories.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import { NewReleaseCard } from '../../components/Card/NewReleaseCard/NewReleaseCard';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/NewReleaseCard',
- component: NewReleaseCard,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- color: 'primary',
- children: 'Primary',
-};
diff --git a/packages/webapp/src/stories/Card/NewFeatureCard.stories.jsx b/packages/webapp/src/stories/Card/NewFeatureCard.stories.jsx
new file mode 100644
index 0000000000..bc24a1613f
--- /dev/null
+++ b/packages/webapp/src/stories/Card/NewFeatureCard.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { NewReleaseCard } from '../../components/Card/NewReleaseCard/NewReleaseCard';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/NewReleaseCard',
+ component: NewReleaseCard,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ color: 'primary',
+ children: 'Primary',
+};
diff --git a/packages/webapp/src/stories/Consent/Consent.stories.js b/packages/webapp/src/stories/Consent/Consent.stories.js
deleted file mode 100644
index 7c48a12317..0000000000
--- a/packages/webapp/src/stories/Consent/Consent.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import decorators from '../Pages/config/decorators';
-import React from 'react';
-import PureConsent from '../../components/Consent';
-import text from '../../containers/Consent/locales/en/Owner.Consent.md';
-export default {
- title: 'Form/Intro/3-Consent',
- decorators: decorators,
- component: PureConsent,
-};
-
-const Template = (args) => ;
-
-export const Consent = Template.bind({});
-Consent.args = {
- onSubmit: () => {},
- onGoBack: () => {},
- checkboxArgs: { label: 'I Agree' },
- text: text,
-};
diff --git a/packages/webapp/src/stories/Consent/Consent.stories.jsx b/packages/webapp/src/stories/Consent/Consent.stories.jsx
new file mode 100644
index 0000000000..915e160ca1
--- /dev/null
+++ b/packages/webapp/src/stories/Consent/Consent.stories.jsx
@@ -0,0 +1,21 @@
+import decorators from '../Pages/config/Decorators';
+import React from 'react';
+import PureConsent from '../../components/Consent';
+import ConsentEnglish from '../../containers/Consent/locales/en/Owner.Consent.md';
+export default {
+ title: 'Form/Intro/3-Consent',
+ decorators: decorators,
+ component: PureConsent,
+};
+
+const Template = (args) => ;
+
+export const Consent = Template.bind({});
+Consent.args = {
+ onSubmit: () => {
+ },
+ onGoBack: () => {
+ },
+ checkboxArgs: { label: 'I Agree' },
+ consent: ,
+};
diff --git a/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.js b/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.js
deleted file mode 100644
index a7460532a3..0000000000
--- a/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import { ContainerWithIcon } from '../../components/ContainerWithIcon/ContainerWithIcon';
-import { componentDecorators } from '../Pages/config/decorators';
-import { ReactComponent as TrashIcon } from '../../assets/images/document/trash.svg';
-
-export default {
- title: 'Components/ContainerWithIcon',
- component: ContainerWithIcon,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Image = Template.bind({});
-Image.args = {
- icon: ,
- onIconClick: () => {
- console.log('delete');
- },
- children: (
-
- ),
-};
-
-export const RedBlock = Template.bind({});
-RedBlock.args = {
- icon: ,
- onIconClick: () => {
- console.log('delete');
- },
- children:
,
- iconBackgroundColor: 'blue',
-};
diff --git a/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.jsx b/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.jsx
new file mode 100644
index 0000000000..3a178ac393
--- /dev/null
+++ b/packages/webapp/src/stories/ContainerWithIcon/ContainerWithIcon.stories.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { ContainerWithIcon } from '../../components/ContainerWithIcon/ContainerWithIcon';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { ReactComponent as TrashIcon } from '../../assets/images/document/trash.svg';
+
+export default {
+ title: 'Components/ContainerWithIcon',
+ component: ContainerWithIcon,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Image = Template.bind({});
+Image.args = {
+ icon: ,
+ onIconClick: () => {
+ console.log('delete');
+ },
+ children: (
+
+ ),
+};
+
+export const RedBlock = Template.bind({});
+RedBlock.args = {
+ icon: ,
+ onIconClick: () => {
+ console.log('delete');
+ },
+ children:
,
+ iconBackgroundColor: 'blue',
+};
diff --git a/packages/webapp/src/stories/CropHeader/CropHeader.stories.js b/packages/webapp/src/stories/CropHeader/CropHeader.stories.js
deleted file mode 100644
index ec462ef45a..0000000000
--- a/packages/webapp/src/stories/CropHeader/CropHeader.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import CropHeader from '../../components/Crop/cropHeader';
-
-export default {
- title: 'Components/CropHeader',
- component: CropHeader,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Blueberry 1',
- supplier: 'supplier',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
-};
diff --git a/packages/webapp/src/stories/CropHeader/CropHeader.stories.jsx b/packages/webapp/src/stories/CropHeader/CropHeader.stories.jsx
new file mode 100644
index 0000000000..bc50bc6ddf
--- /dev/null
+++ b/packages/webapp/src/stories/CropHeader/CropHeader.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import CropHeader from '../../components/Crop/CropHeader';
+
+export default {
+ title: 'Components/CropHeader',
+ component: CropHeader,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Blueberry 1',
+ supplier: 'supplier',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+};
diff --git a/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.js b/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.js
deleted file mode 100644
index 1b61d918f8..0000000000
--- a/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import CropStatusInfoBox from '../../components/CropCatalogue/CropStatusInfoBox';
-
-export default {
- title: 'Components/CropStatusInfoBox',
- component: CropStatusInfoBox,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Default = Template.bind({});
-Default.args = {
- status: {
- active: 8,
- planned: 8,
- past: 8,
- },
- // defaultDate: 'Sept 12, 2021',
-};
-
-export const WithoutStatus = Template.bind({});
-WithoutStatus.args = {
- // defaultDate: 'Sept 12, 2021',
-};
diff --git a/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.jsx b/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.jsx
new file mode 100644
index 0000000000..4d4e58e0a2
--- /dev/null
+++ b/packages/webapp/src/stories/CropStatusInfoBox/CropStatusInfoBox.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import CropStatusInfoBox from '../../components/CropCatalogue/CropStatusInfoBox';
+
+export default {
+ title: 'Components/CropStatusInfoBox',
+ component: CropStatusInfoBox,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Default = Template.bind({});
+Default.args = {
+ status: {
+ active: 8,
+ planned: 8,
+ past: 8,
+ },
+ // defaultDate: 'Sept 12, 2021',
+};
+
+export const WithoutStatus = Template.bind({});
+WithoutStatus.args = {
+ // defaultDate: 'Sept 12, 2021',
+};
diff --git a/packages/webapp/src/stories/CropTile/CropTile.stories.js b/packages/webapp/src/stories/CropTile/CropTile.stories.js
deleted file mode 100644
index 2ad0e39ceb..0000000000
--- a/packages/webapp/src/stories/CropTile/CropTile.stories.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import PureCropTile from '../../components/CropTile';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/CropTile/CropTile',
- component: PureCropTile,
- decorators: componentDecorators,
-};
-
-const Template = (args) => (
-
-);
-
-export const Variety = Template.bind({});
-Variety.args = {
- title: 'Blueberry',
- src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
- alt: 'blueberry',
-};
-
-export const CropTemplate = Template.bind({});
-CropTemplate.args = {
- title: 'Blueberry',
- src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
- alt: 'blueberry',
- isCropTemplate: true,
-};
-
-export const WithManagementPlan = Template.bind({});
-WithManagementPlan.args = {
- title: 'Blueberry',
- cropCount: {
- active: 8,
- planned: 8,
- past: 8,
- },
- src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
- alt: 'blueberry',
-};
-
-export const NeedsManagementPlan = Template.bind({});
-NeedsManagementPlan.args = {
- title: 'Blueberry',
- needsPlan: true,
- src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
- alt: 'blueberry',
-};
diff --git a/packages/webapp/src/stories/CropTile/CropTile.stories.jsx b/packages/webapp/src/stories/CropTile/CropTile.stories.jsx
new file mode 100644
index 0000000000..bbce8bedd3
--- /dev/null
+++ b/packages/webapp/src/stories/CropTile/CropTile.stories.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import PureCropTile from '../../components/CropTile';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/CropTile/CropTile',
+ component: PureCropTile,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => (
+
+);
+
+export const Variety = Template.bind({});
+Variety.args = {
+ title: 'Blueberry',
+ src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
+ alt: 'blueberry',
+};
+
+export const CropTemplate = Template.bind({});
+CropTemplate.args = {
+ title: 'Blueberry',
+ src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
+ alt: 'blueberry',
+ isCropTemplate: true,
+};
+
+export const WithManagementPlan = Template.bind({});
+WithManagementPlan.args = {
+ title: 'Blueberry',
+ cropCount: {
+ active: 8,
+ planned: 8,
+ past: 8,
+ },
+ src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
+ alt: 'blueberry',
+};
+
+export const NeedsManagementPlan = Template.bind({});
+NeedsManagementPlan.args = {
+ title: 'Blueberry',
+ needsPlan: true,
+ src: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
+ alt: 'blueberry',
+};
diff --git a/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.js b/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.js
deleted file mode 100644
index c597af68f1..0000000000
--- a/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react';
-import PureManagementPlanTile from '../../components/CropTile/ManagementPlanTile';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/CropTile/ManagementPlanTile',
- component: PureManagementPlanTile,
- decorators: componentDecorators,
-};
-
-const Template = (args) => (
-
-);
-export const Active = Template.bind({});
-Active.args = {
- managementPlan: {
- crop_variety_name: 'Bolero',
- start_date: '2020-12-25T15:02:31.440Z',
- crop_translation_key: 'CARROT',
- crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
- },
- status: 'active',
-};
-
-export const Planned = Template.bind({});
-Planned.args = {
- managementPlan: {
- crop_variety_name: 'Bolero',
- start_date: '2020-12-25T15:02:31.440Z',
- crop_translation_key: 'CARROT',
- crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
- },
- status: 'planned',
-};
-
-export const Past = Template.bind({});
-Past.args = {
- managementPlan: {
- crop_variety_name: 'Bolero',
- start_date: '2020-12-25T15:02:31.440Z',
- crop_translation_key: 'CARROT',
- crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
- },
- status: 'past',
-};
-
-export const Selected = Template.bind({});
-Selected.args = {
- managementPlan: {
- crop_variety_name: 'Bolero',
- start_date: '2020-12-25T15:02:31.440Z',
- crop_translation_key: 'CARROT',
- crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
- },
- status: 'past',
- isSelected: true,
-};
diff --git a/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.jsx b/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.jsx
new file mode 100644
index 0000000000..270250a373
--- /dev/null
+++ b/packages/webapp/src/stories/CropTile/ManagementPlanTile.stories.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import PureManagementPlanTile from '../../components/CropTile/ManagementPlanTile';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/CropTile/ManagementPlanTile',
+ component: PureManagementPlanTile,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => (
+
+);
+export const Active = Template.bind({});
+Active.args = {
+ managementPlan: {
+ crop_variety_name: 'Bolero',
+ start_date: '2020-12-25T15:02:31.440Z',
+ crop_translation_key: 'CARROT',
+ crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
+ },
+ status: 'active',
+};
+
+export const Planned = Template.bind({});
+Planned.args = {
+ managementPlan: {
+ crop_variety_name: 'Bolero',
+ start_date: '2020-12-25T15:02:31.440Z',
+ crop_translation_key: 'CARROT',
+ crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
+ },
+ status: 'planned',
+};
+
+export const Past = Template.bind({});
+Past.args = {
+ managementPlan: {
+ crop_variety_name: 'Bolero',
+ start_date: '2020-12-25T15:02:31.440Z',
+ crop_translation_key: 'CARROT',
+ crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
+ },
+ status: 'past',
+};
+
+export const Selected = Template.bind({});
+Selected.args = {
+ managementPlan: {
+ crop_variety_name: 'Bolero',
+ start_date: '2020-12-25T15:02:31.440Z',
+ crop_translation_key: 'CARROT',
+ crop_variety_photo_url: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/carrot.webp`,
+ },
+ status: 'past',
+ isSelected: true,
+};
diff --git a/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.js b/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.js
deleted file mode 100644
index e476ff4eae..0000000000
--- a/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import { DocumentIcon } from '../../components/Icons/DocumentIcon';
-
-import { componentDecoratorsGreyBackground } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/DocumentIcon',
- decorators: componentDecoratorsGreyBackground,
- component: DocumentIcon,
-};
-const Template = (args) => ;
-
-export const PDF = Template.bind({});
-
-PDF.args = {
- extensionName: 'pdf',
-};
-
-export const DOCX = Template.bind({});
-DOCX.args = {
- extensionName: 'docx',
-};
diff --git a/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.jsx b/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.jsx
new file mode 100644
index 0000000000..052d37c949
--- /dev/null
+++ b/packages/webapp/src/stories/DocumentIcon/DocumentIcon.stories.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { DocumentIcon } from '../../components/Icons/DocumentIcon';
+
+import { componentDecoratorsGreyBackground } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/DocumentIcon',
+ decorators: componentDecoratorsGreyBackground,
+ component: DocumentIcon,
+};
+const Template = (args) => ;
+
+export const PDF = Template.bind({});
+
+PDF.args = {
+ extensionName: 'pdf',
+};
+
+export const DOCX = Template.bind({});
+DOCX.args = {
+ extensionName: 'docx',
+};
diff --git a/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.js b/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.js
deleted file mode 100644
index 1d8eddb85f..0000000000
--- a/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import PureDocumentTile from '../../containers/Documents/DocumentTile';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/DocumentTile',
- component: PureDocumentTile,
- decorators: componentDecorators,
-};
-
-const Template = (args) => (
-
-);
-
-export const Variety = Template.bind({});
-Variety.args = {
- title: 'Document Name I have a very long name, hahaha',
- type: 'Crop Compliance',
- date: "May 01 21'",
- preview: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
- imageComponent: (props) => ,
-};
diff --git a/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.jsx b/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.jsx
new file mode 100644
index 0000000000..ed4f9274b1
--- /dev/null
+++ b/packages/webapp/src/stories/DocumentTile/DocumentTile.stories.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import PureDocumentTile from '../../containers/Documents/DocumentTile';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/DocumentTile',
+ component: PureDocumentTile,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => (
+
+);
+
+export const Variety = Template.bind({});
+Variety.args = {
+ title: 'Document Name I have a very long name, hahaha',
+ type: 'Crop Compliance',
+ date: "May 01 21'",
+ preview: `https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp`,
+ imageComponent: (props) => ,
+};
diff --git a/packages/webapp/src/stories/DropdownAndFilter/PureTaskDropdownFilter.stories.jsx b/packages/webapp/src/stories/DropdownAndFilter/PureTaskDropdownFilter.stories.jsx
new file mode 100644
index 0000000000..92a0e1ae64
--- /dev/null
+++ b/packages/webapp/src/stories/DropdownAndFilter/PureTaskDropdownFilter.stories.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import DropdownAndFilter from '../../components/PopupFilter/PureTaskDropdownFilter';
+
+export default {
+ title: 'Components/DropdownAndFilter',
+ component: DropdownAndFilter,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const InActive = Template.bind({});
+InActive.args = {};
+
+export const Active = Template.bind({});
+Active.args = {
+ isFilterActive: true,
+};
+
+export const DropdownOpen = Template.bind({});
+DropdownOpen.args = {
+ isFilterActive: true,
+ isDropDownOpen: true,
+};
diff --git a/packages/webapp/src/stories/Filter/Filter.stories.js b/packages/webapp/src/stories/Filter/Filter.stories.js
deleted file mode 100644
index d7a01cb010..0000000000
--- a/packages/webapp/src/stories/Filter/Filter.stories.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import Filter from '../../components/Filter';
-
-export default {
- title: 'Components/Filter',
- component: Filter,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- subject: 'Status',
- items: [
- {
- value: 'active',
- label: 'Active',
- },
- {
- value: 'planned',
- label: 'Planned',
- },
- {
- value: 'complete',
- label: 'Complete',
- },
- {
- value: 'abandoned',
- label: 'Abandoned',
- },
- {
- value: 'needs_plan',
- label: 'Needs plan',
- },
- ],
- filterRef: { current: {} },
-};
-Primary.parameters = {
- chromatic: { disable: true },
-};
-
-export const Empty = Template.bind({});
-Empty.args = {
- subject: 'Status',
- items: [],
- filterRef: { current: {} },
-};
-Empty.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/Filter/Filter.stories.jsx b/packages/webapp/src/stories/Filter/Filter.stories.jsx
new file mode 100644
index 0000000000..2ebd697db8
--- /dev/null
+++ b/packages/webapp/src/stories/Filter/Filter.stories.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import FilterPillSelect from '../../components/Filter/FilterPillSelect';
+
+export default {
+ title: 'Components/Filter',
+ component: FilterPillSelect,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ subject: 'Status',
+ options: [
+ {
+ value: 'active',
+ label: 'Active',
+ },
+ {
+ value: 'planned',
+ label: 'Planned',
+ },
+ {
+ value: 'complete',
+ label: 'Complete',
+ },
+ {
+ value: 'abandoned',
+ label: 'Abandoned',
+ },
+ {
+ value: 'needs_plan',
+ label: 'Needs plan',
+ },
+ ],
+ filterRef: { current: {} },
+};
+Primary.parameters = {
+ chromatic: { disable: true },
+};
+
+export const Empty = Template.bind({});
+Empty.args = {
+ subject: 'Status',
+ options: [],
+ filterRef: { current: {} },
+};
+Empty.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/FilterDateRange/FilterDateRange.stories.jsx b/packages/webapp/src/stories/FilterDateRange/FilterDateRange.stories.jsx
new file mode 100644
index 0000000000..7b7f501d53
--- /dev/null
+++ b/packages/webapp/src/stories/FilterDateRange/FilterDateRange.stories.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { FilterDateRange } from '../../components/Filter/FilterDateRange';
+
+export default {
+ title: 'Components/FilterDateRange',
+ component: FilterDateRange,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ subject: 'Filter by date range',
+};
+
+export const WithFromToDate = Template.bind({});
+WithFromToDate.args = {
+ defaultFromDate: '2022-02-01',
+ defaultToDate: '2022-02-10',
+ subject: 'Filter by date range',
+};
+export const WithFromDate = Template.bind({});
+WithFromDate.args = {
+ defaultFromDate: '2022-02-01',
+ subject: 'Filter by date range',
+};
+export const WithToDate = Template.bind({});
+WithToDate.args = {
+ defaultToDate: '2022-02-10',
+ subject: 'Filter by date range',
+};
diff --git a/packages/webapp/src/stories/FilterPill/FilterCheckBoxPill.stories.js b/packages/webapp/src/stories/FilterPill/FilterCheckBoxPill.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/FilterPill/FilterCheckBoxPill.stories.js
rename to packages/webapp/src/stories/FilterPill/FilterCheckBoxPill.stories.jsx
diff --git a/packages/webapp/src/stories/FilterPill/FilterPill.stories.js b/packages/webapp/src/stories/FilterPill/FilterPill.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/FilterPill/FilterPill.stories.js
rename to packages/webapp/src/stories/FilterPill/FilterPill.stories.jsx
diff --git a/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.js b/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.js
deleted file mode 100644
index 01028ff3fe..0000000000
--- a/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.js
+++ /dev/null
@@ -1,180 +0,0 @@
-import React from 'react';
-import FinanceGroup from '../../components/Finances/FinanceGroup';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/FinanceGroup',
- component: FinanceGroup,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const EstimatedCropRevenue = Template.bind({});
-EstimatedCropRevenue.args = {
- headerTitle: 'Bolero, Carrot',
- totalAmount: 600,
- isDropDown: true,
- financeItemsProps: [
- {
- title: 'Plan 1',
- subtitle: "May 8, '21 | Bed 2",
- amount: 100,
- isPlan: true,
- onClickForward: () => {
- console.log('Plan 1 clicked');
- },
- },
- {
- title: 'Plan 2',
- subtitle: "Apr 17, '21 | Bed 1",
- amount: 500,
- isPlan: true,
- onClickForward: () => {
- console.log('Plan 2 clicked');
- },
- },
- ],
-};
-
-export const EstimatedCropRevenueWithLargeSpecifyBedNote = Template.bind({});
-EstimatedCropRevenueWithLargeSpecifyBedNote.args = {
- headerTitle: 'Bolero, Carrot',
- totalAmount: 600,
- isDropDown: true,
- financeItemsProps: [
- {
- title: 'Plan 1',
- subtitle:
- "May 8, '21 | Large note bed that should overflow into the next line in small viewport",
- amount: 100,
- isPlan: true,
- onClickForward: () => {
- console.log('Plan 1 clicked');
- },
- },
- {
- title: 'Plan 2',
- subtitle: "Apr 17, '21 | Bed 1",
- amount: 500,
- isPlan: true,
- onClickForward: () => {
- console.log('Plan 2 clicked');
- },
- },
- ],
-};
-
-export const EstimatedNonCropRevenue = Template.bind({});
-EstimatedNonCropRevenue.args = {
- headerTitle: 'Donation',
- totalAmount: 600,
- isDropDown: true,
- financeItemsProps: [
- {
- title: 'Description 1',
- amount: 300,
- onClickForward: () => {
- console.log('Donation 1 clicked');
- },
- },
- {
- title: 'Description 2',
- amount: 300,
- onClickForward: () => {
- console.log('Donation 2 clicked');
- },
- },
- ],
-};
-
-export const EstimatedNonCropRevenueWithLongDescription = Template.bind({});
-EstimatedNonCropRevenueWithLongDescription.args = {
- headerTitle: 'Donation',
- totalAmount: 600,
- isDropDown: true,
- financeItemsProps: [
- {
- title: 'Description 1 that is very long to overflow to next line in small viewport',
- amount: 300,
- onClickForward: () => {
- console.log('Donation 1 clicked');
- },
- },
- {
- title: 'Description 2',
- amount: 300,
- onClickForward: () => {
- console.log('Donation 2 clicked');
- },
- },
- ],
-};
-
-export const ActualCropRevenue = Template.bind({});
-ActualCropRevenue.args = {
- headerTitle: "May 8, '21",
- headerClickForward: () => {
- console.log('Edit income');
- },
- totalAmount: 300,
- isDropDown: false,
- financeItemsProps: [
- {
- title: 'Parsnip',
- subtitle: '15 kg',
- amount: 150.0,
- },
- {
- title: 'Rainbow Blend, Carrot',
- subtitle: '10 kg',
- amount: 150.0,
- },
- ],
-};
-
-export const ActualCropRevenueWithCustomer = Template.bind({});
-ActualCropRevenueWithCustomer.args = {
- headerTitle: "May 8, '21",
- headerSubtitle: 'Customer Name',
- headerClickForward: () => {
- console.log('Edit income');
- },
- totalAmount: 300,
- isDropDown: false,
- financeItemsProps: [
- {
- title: 'Parsnip',
- subtitle: '15 kg',
- amount: 150.0,
- },
- {
- title: 'Rainbow Blend, Carrot',
- subtitle: '10 kg',
- amount: 150.0,
- },
- ],
-};
-
-export const ActualNonCropRevenue = Template.bind({});
-ActualNonCropRevenue.args = {
- headerTitle: "May 8, '21",
- headerClickForward: () => {
- console.log('Edit income');
- },
- totalAmount: 800,
- isDropDown: false,
- financeItemsProps: [
- {
- title: 'Donation',
- subtitle: 'Description',
- amount: 400.0,
- },
- {
- title: 'Equipment Rental',
- subtitle:
- 'This is a long description that goes to multiple lines (in a sufficiently small viewport)',
- amount: 150.0,
- },
- ],
-};
diff --git a/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.jsx b/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.jsx
new file mode 100644
index 0000000000..22b71d81e8
--- /dev/null
+++ b/packages/webapp/src/stories/FinanceGroup/FinanceGroup.stories.jsx
@@ -0,0 +1,180 @@
+import React from 'react';
+import FinanceGroup from '../../components/Finances/FinanceGroup';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/FinanceGroup',
+ component: FinanceGroup,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const EstimatedCropRevenue = Template.bind({});
+EstimatedCropRevenue.args = {
+ headerTitle: 'Bolero, Carrot',
+ totalAmount: 600,
+ isDropDown: true,
+ financeItemsProps: [
+ {
+ title: 'Plan 1',
+ subtitle: "May 8, '21 | Bed 2",
+ amount: 100,
+ isPlan: true,
+ onClickForward: () => {
+ console.log('Plan 1 clicked');
+ },
+ },
+ {
+ title: 'Plan 2',
+ subtitle: "Apr 17, '21 | Bed 1",
+ amount: 500,
+ isPlan: true,
+ onClickForward: () => {
+ console.log('Plan 2 clicked');
+ },
+ },
+ ],
+};
+
+export const EstimatedCropRevenueWithLargeSpecifyBedNote = Template.bind({});
+EstimatedCropRevenueWithLargeSpecifyBedNote.args = {
+ headerTitle: 'Bolero, Carrot',
+ totalAmount: 600,
+ isDropDown: true,
+ financeItemsProps: [
+ {
+ title: 'Plan 1',
+ subtitle:
+ "May 8, '21 | Large note bed that should overflow into the next line in small viewport",
+ amount: 100,
+ isPlan: true,
+ onClickForward: () => {
+ console.log('Plan 1 clicked');
+ },
+ },
+ {
+ title: 'Plan 2',
+ subtitle: "Apr 17, '21 | Bed 1",
+ amount: 500,
+ isPlan: true,
+ onClickForward: () => {
+ console.log('Plan 2 clicked');
+ },
+ },
+ ],
+};
+
+export const EstimatedNonCropRevenue = Template.bind({});
+EstimatedNonCropRevenue.args = {
+ headerTitle: 'Donation',
+ totalAmount: 600,
+ isDropDown: true,
+ financeItemsProps: [
+ {
+ title: 'Description 1',
+ amount: 300,
+ onClickForward: () => {
+ console.log('Donation 1 clicked');
+ },
+ },
+ {
+ title: 'Description 2',
+ amount: 300,
+ onClickForward: () => {
+ console.log('Donation 2 clicked');
+ },
+ },
+ ],
+};
+
+export const EstimatedNonCropRevenueWithLongDescription = Template.bind({});
+EstimatedNonCropRevenueWithLongDescription.args = {
+ headerTitle: 'Donation',
+ totalAmount: 600,
+ isDropDown: true,
+ financeItemsProps: [
+ {
+ title: 'Description 1 that is very long to overflow to next line in small viewport',
+ amount: 300,
+ onClickForward: () => {
+ console.log('Donation 1 clicked');
+ },
+ },
+ {
+ title: 'Description 2',
+ amount: 300,
+ onClickForward: () => {
+ console.log('Donation 2 clicked');
+ },
+ },
+ ],
+};
+
+export const ActualCropRevenue = Template.bind({});
+ActualCropRevenue.args = {
+ headerTitle: "May 8, '21",
+ headerClickForward: () => {
+ console.log('Edit income');
+ },
+ totalAmount: 300,
+ isDropDown: false,
+ financeItemsProps: [
+ {
+ title: 'Parsnip',
+ subtitle: '15 kg',
+ amount: 150.0,
+ },
+ {
+ title: 'Rainbow Blend, Carrot',
+ subtitle: '10 kg',
+ amount: 150.0,
+ },
+ ],
+};
+
+export const ActualCropRevenueWithCustomer = Template.bind({});
+ActualCropRevenueWithCustomer.args = {
+ headerTitle: "May 8, '21",
+ headerSubtitle: 'Customer Name',
+ headerClickForward: () => {
+ console.log('Edit income');
+ },
+ totalAmount: 300,
+ isDropDown: false,
+ financeItemsProps: [
+ {
+ title: 'Parsnip',
+ subtitle: '15 kg',
+ amount: 150.0,
+ },
+ {
+ title: 'Rainbow Blend, Carrot',
+ subtitle: '10 kg',
+ amount: 150.0,
+ },
+ ],
+};
+
+export const ActualNonCropRevenue = Template.bind({});
+ActualNonCropRevenue.args = {
+ headerTitle: "May 8, '21",
+ headerClickForward: () => {
+ console.log('Edit income');
+ },
+ totalAmount: 800,
+ isDropDown: false,
+ financeItemsProps: [
+ {
+ title: 'Donation',
+ subtitle: 'Description',
+ amount: 400.0,
+ },
+ {
+ title: 'Equipment Rental',
+ subtitle:
+ 'This is a long description that goes to multiple lines (in a sufficiently small viewport)',
+ amount: 150.0,
+ },
+ ],
+};
diff --git a/packages/webapp/src/stories/Footer/Footer.stories.js b/packages/webapp/src/stories/Footer/Footer.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/Footer/Footer.stories.js
rename to packages/webapp/src/stories/Footer/Footer.stories.jsx
diff --git a/packages/webapp/src/stories/Form/Errors/Errors.stories.js b/packages/webapp/src/stories/Form/Errors/Errors.stories.js
deleted file mode 100644
index 5f88a088f8..0000000000
--- a/packages/webapp/src/stories/Form/Errors/Errors.stories.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import React from 'react';
-import { PasswordError } from '../../../components/Form/Errors';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/InputPassword/PasswordError',
- component: PasswordError,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const TooShort = Template.bind({});
-TooShort.args = {
- isTooShort: false,
- hasNoUpperCase: true,
- hasNoDigit: true,
- hasNoSymbol: true,
-};
-
-export const NoUpperCase = Template.bind({});
-NoUpperCase.args = {
- isTooShort: true,
- hasNoUpperCase: false,
- hasNoDigit: true,
- hasNoSymbol: true,
-};
-
-export const NoDigit = Template.bind({});
-NoDigit.args = {
- isTooShort: true,
- hasNoUpperCase: true,
- hasNoDigit: false,
- hasNoSymbol: true,
-};
-
-export const NoSymbol = Template.bind({});
-NoSymbol.args = {
- isTooShort: true,
- hasNoUpperCase: true,
- hasNoDigit: true,
- hasNoSymbol: false,
-};
diff --git a/packages/webapp/src/stories/Form/Errors/Errors.stories.jsx b/packages/webapp/src/stories/Form/Errors/Errors.stories.jsx
new file mode 100644
index 0000000000..816bc27726
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Errors/Errors.stories.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { PasswordError } from '../../../components/Form/Errors';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/InputPassword/PasswordError',
+ component: PasswordError,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const TooShort = Template.bind({});
+TooShort.args = {
+ isTooShort: false,
+ hasNoUpperCase: true,
+ hasNoDigit: true,
+ hasNoSymbol: true,
+};
+
+export const NoUpperCase = Template.bind({});
+NoUpperCase.args = {
+ isTooShort: true,
+ hasNoUpperCase: false,
+ hasNoDigit: true,
+ hasNoSymbol: true,
+};
+
+export const NoDigit = Template.bind({});
+NoDigit.args = {
+ isTooShort: true,
+ hasNoUpperCase: true,
+ hasNoDigit: false,
+ hasNoSymbol: true,
+};
+
+export const NoSymbol = Template.bind({});
+NoSymbol.args = {
+ isTooShort: true,
+ hasNoUpperCase: true,
+ hasNoDigit: true,
+ hasNoSymbol: false,
+};
diff --git a/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.js b/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.js
deleted file mode 100644
index 64edae3811..0000000000
--- a/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
-import { decoratorsWithStore } from '../../Pages/config/decorators';
-import { Underlined } from '../../../components/Typography';
-import { useForm } from 'react-hook-form';
-
-const ImagePickerWithHookForm = (props) => {
- const { register, handleSubmit, watch } = useForm({
- mode: 'onChange',
- });
- console.log(watch());
- return (
-
- );
-};
-
-export default {
- title: 'Components/ImagePickerWrapper',
- component: ImagePickerWithHookForm,
- decorators: decoratorsWithStore,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- children: Pick an image ,
- uploadDirectory: 'storybook/',
-};
diff --git a/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.jsx b/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.jsx
new file mode 100644
index 0000000000..3fbaf249aa
--- /dev/null
+++ b/packages/webapp/src/stories/Form/ImagePickerWrapper/ImagePickerWrapper.stories.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
+import { decoratorsWithStore } from '../../Pages/config/Decorators';
+import { Underlined } from '../../../components/Typography';
+import { useForm } from 'react-hook-form';
+
+const ImagePickerWithHookForm = (props) => {
+ const { register, handleSubmit, watch } = useForm({
+ mode: 'onChange',
+ });
+ console.log(watch());
+ return (
+
+ );
+};
+
+export default {
+ title: 'Components/ImagePickerWrapper',
+ component: ImagePickerWithHookForm,
+ decorators: decoratorsWithStore,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ children: Pick an image ,
+ uploadDirectory: 'storybook/',
+};
diff --git a/packages/webapp/src/stories/Form/Input/DurationInput.stories.js b/packages/webapp/src/stories/Form/Input/DurationInput.stories.js
deleted file mode 100644
index dd5ac921a1..0000000000
--- a/packages/webapp/src/stories/Form/Input/DurationInput.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import InputDuration from '../../../components/Form/InputDuration';
-import { componentDecorators } from '../../Pages/config/decorators';
-import { useForm } from 'react-hook-form';
-
-export default {
- title: 'Components/InputDuration',
- component: InputDuration,
- decorators: componentDecorators,
-};
-
-const Template = (args) => {
- const { register, watch } = useForm({ mode: 'onChange' });
- return ;
-};
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'default',
- startDate: '5-26-2021',
-};
diff --git a/packages/webapp/src/stories/Form/Input/DurationInput.stories.jsx b/packages/webapp/src/stories/Form/Input/DurationInput.stories.jsx
new file mode 100644
index 0000000000..bedb275488
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Input/DurationInput.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import InputDuration from '../../../components/Form/InputDuration';
+import { componentDecorators } from '../../Pages/config/Decorators';
+import { useForm } from 'react-hook-form';
+
+export default {
+ title: 'Components/InputDuration',
+ component: InputDuration,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => {
+ const { register, watch } = useForm({ mode: 'onChange' });
+ return ;
+};
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'default',
+ startDate: '5-26-2021',
+};
diff --git a/packages/webapp/src/stories/Form/Input/Input.stories.js b/packages/webapp/src/stories/Form/Input/Input.stories.js
deleted file mode 100644
index b18da05080..0000000000
--- a/packages/webapp/src/stories/Form/Input/Input.stories.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import React from 'react';
-import Input from '../../../components/Form/Input';
-import { Underlined } from '../../../components/Typography';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/Input',
- component: Input,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'default',
-};
-
-export const Number = Template.bind({});
-Number.args = {
- label: 'number',
- type: 'number',
-};
-
-export const WithUnit = Template.bind({});
-WithUnit.args = {
- label: 'number',
- type: 'number',
- unit: 'unit',
-};
-
-export const WithCurrency = Template.bind({});
-WithCurrency.args = {
- label: 'number',
- type: 'number',
- currency: '$',
-};
-
-export const WithTooltip = Template.bind({});
-WithTooltip.args = {
- label: 'With Tooltip',
- toolTipContent:
- 'Gender information is collected for research purposes only and will only be shared with personally identifying information removed',
-};
-
-export const WithDefaultValue = Template.bind({});
-WithDefaultValue.args = {
- label: 'With default value',
- defaultValue: 'With default value',
-};
-
-export const Optional = Template.bind({});
-Optional.args = {
- label: 'optional',
- optional: true,
-};
-
-export const HasLeaf = Template.bind({});
-HasLeaf.args = {
- label: 'Leaf',
- hasLeaf: true,
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- disabled: true,
- label: 'disabled',
-};
-
-export const WithIcon = Template.bind({});
-WithIcon.args = {
- icon: icon
,
- label: 'With icon',
-};
-
-export const WithError = Template.bind({});
-WithError.args = {
- errors: 'error error error error',
- label: 'With error',
-};
-
-export const WithInfo = Template.bind({});
-WithInfo.args = {
- info: 'info info info info info',
- label: 'With info',
-};
-
-export const SearchBar = Template.bind({});
-SearchBar.args = {
- placeholder: 'Search',
- isSearchBar: true,
-};
-
-export const Password = Template.bind({});
-Password.args = {
- label: 'Password',
- type: 'password',
-};
-
-export const PasswordWithLink = Template.bind({});
-PasswordWithLink.args = {
- label: 'Password',
- type: 'password',
- icon: Forget password ,
-};
diff --git a/packages/webapp/src/stories/Form/Input/Input.stories.jsx b/packages/webapp/src/stories/Form/Input/Input.stories.jsx
new file mode 100644
index 0000000000..24e9150a87
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Input/Input.stories.jsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import Input from '../../../components/Form/Input';
+import { Underlined } from '../../../components/Typography';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Input',
+ component: Input,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'default',
+};
+
+export const Number = Template.bind({});
+Number.args = {
+ label: 'number',
+ type: 'number',
+};
+
+export const WithUnit = Template.bind({});
+WithUnit.args = {
+ label: 'number',
+ type: 'number',
+ unit: 'unit',
+};
+
+export const WithCurrency = Template.bind({});
+WithCurrency.args = {
+ label: 'number',
+ type: 'number',
+ currency: '$',
+};
+
+export const WithTooltip = Template.bind({});
+WithTooltip.args = {
+ label: 'With Tooltip',
+ toolTipContent:
+ 'Gender information is collected for research purposes only and will only be shared with personally identifying information removed',
+};
+
+export const WithDefaultValue = Template.bind({});
+WithDefaultValue.args = {
+ label: 'With default value',
+ defaultValue: 'With default value',
+};
+
+export const Optional = Template.bind({});
+Optional.args = {
+ label: 'optional',
+ optional: true,
+};
+
+export const HasLeaf = Template.bind({});
+HasLeaf.args = {
+ label: 'Leaf',
+ hasLeaf: true,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ disabled: true,
+ label: 'disabled',
+};
+
+export const WithIcon = Template.bind({});
+WithIcon.args = {
+ icon: icon
,
+ label: 'With icon',
+};
+
+export const WithError = Template.bind({});
+WithError.args = {
+ errors: 'error error error error',
+ label: 'With error',
+};
+
+export const WithInfo = Template.bind({});
+WithInfo.args = {
+ info: 'info info info info info',
+ label: 'With info',
+};
+
+export const SearchBar = Template.bind({});
+SearchBar.args = {
+ placeholder: 'Search',
+ isSearchBar: true,
+};
+
+export const Password = Template.bind({});
+Password.args = {
+ label: 'Password',
+ type: 'password',
+};
+
+export const PasswordWithLink = Template.bind({});
+PasswordWithLink.args = {
+ label: 'Password',
+ type: 'password',
+ icon: Forget password ,
+};
diff --git a/packages/webapp/src/stories/Form/Input/TextArea.stories.js b/packages/webapp/src/stories/Form/Input/TextArea.stories.js
deleted file mode 100644
index d87efd0c37..0000000000
--- a/packages/webapp/src/stories/Form/Input/TextArea.stories.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import TextArea from '../../../components/Form/TextArea';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/Input/TextArea',
- component: TextArea,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'default',
-};
diff --git a/packages/webapp/src/stories/Form/Input/TextArea.stories.jsx b/packages/webapp/src/stories/Form/Input/TextArea.stories.jsx
new file mode 100644
index 0000000000..9478bb8c06
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Input/TextArea.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import TextArea from '../../../components/Form/TextArea';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Input/TextArea',
+ component: TextArea,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'default',
+};
diff --git a/packages/webapp/src/stories/Form/Input/Unit.stories.js b/packages/webapp/src/stories/Form/Input/Unit.stories.js
deleted file mode 100644
index f4bc36b3cb..0000000000
--- a/packages/webapp/src/stories/Form/Input/Unit.stories.js
+++ /dev/null
@@ -1,274 +0,0 @@
-import React from 'react';
-import Unit, { getUnitOptionMap } from '../../../components/Form/Unit';
-import { componentDecorators } from '../../Pages/config/decorators';
-import { bufferZoneEnum, fieldEnum, waterValveEnum } from '../../../containers/constants';
-import { area_perimeter, area_total_area, crop_age, line_width, water_valve_flow_rate } from '../../../util/unit';
-import { useForm } from 'react-hook-form';
-import convert from 'convert-units';
-
-const UnitWithHookForm = (props) => {
- const {
- register,
- setValue,
- getValues,
- watch,
- setError,
- control,
- handleSubmit,
-
- formState: { errors },
- } = useForm({
- mode: 'onChange',
- defaultValues: props.defaultValues,
- });
- return (
-
- );
-};
-
-export default {
- title: 'Components/Input/Unit',
- component: UnitWithHookForm,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'Default',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- unitType: area_total_area,
- system: 'imperial',
- required: true,
-};
-
-export const HasLeaf = Template.bind({});
-HasLeaf.args = {
- label: 'Default',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- unitType: area_total_area,
- system: 'imperial',
- required: true,
- hasLeaf: true,
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- label: 'sqft',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- defaultValue: 999,
- unitType: area_total_area,
- system: 'imperial',
- required: true,
- disabled: true,
-};
-
-export const WithOneUnit = Template.bind({});
-WithOneUnit.args = {
- label: 'WithOneUnit',
- name: bufferZoneEnum?.width,
- displayUnitName: bufferZoneEnum?.width_unit,
- unitType: line_width,
- system: 'imperial',
- required: true,
-};
-
-export const WithOneUnitDisabled = Template.bind({});
-WithOneUnitDisabled.args = {
- label: 'ft',
- name: bufferZoneEnum?.width,
- displayUnitName: bufferZoneEnum?.width_unit,
- unitType: line_width,
- defaultValue: 999,
- system: 'imperial',
- required: true,
- disabled: true,
-};
-
-export const WithToolTip = Template.bind({});
-WithToolTip.args = {
- label: 'WithToolTip',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- unitType: area_total_area,
- system: 'imperial',
- required: true,
- toolTipContent: 'toolTip',
-};
-
-export const SquareMeterAreaTotalArea = Template.bind({});
-SquareMeterAreaTotalArea.args = {
- label: 'SquareMeter',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- defaultValue: 999,
- unitType: area_total_area,
- system: 'metric',
- required: true,
-};
-
-export const HectareAreaTotalArea = Template.bind({});
-HectareAreaTotalArea.args = {
- label: 'Hectare',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- defaultValue: 1001,
- unitType: area_total_area,
- system: 'metric',
- required: true,
-};
-
-export const AcreAreaTotalArea = Template.bind({});
-AcreAreaTotalArea.args = {
- label: 'Acre',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- defaultValue:
- convert(1).from(area_total_area.imperial.defaultUnit).to(area_total_area.databaseUnit) * 10890,
- unitType: area_total_area,
- system: 'imperial',
- required: true,
-};
-
-export const MeterAreaPerimeter = Template.bind({});
-MeterAreaPerimeter.args = {
- label: 'Meter',
- name: fieldEnum.perimeter,
- displayUnitName: fieldEnum?.perimeter_unit,
- defaultValue: 999,
- unitType: area_perimeter,
- system: 'metric',
- required: true,
-};
-
-export const InchLineWidth = Template.bind({});
-InchLineWidth.args = {
- label: 'Inch',
- name: bufferZoneEnum.length,
- displayUnitName: bufferZoneEnum.length_unit,
- defaultValue: convert(1).from(line_width.imperial.defaultUnit).to(line_width.databaseUnit) * 19,
- unitType: line_width,
- system: 'imperial',
- required: true,
-};
-
-export const FeetAreaPerimeter = Template.bind({});
-FeetAreaPerimeter.args = {
- label: 'Feet',
- name: fieldEnum?.perimeter,
- displayUnitName: fieldEnum?.perimeter_unit,
- defaultValue:
- convert(1).from(area_perimeter.imperial.defaultUnit).to(area_perimeter.databaseUnit) * 1319,
- unitType: area_perimeter,
- system: 'imperial',
- required: true,
-};
-
-export const MileAreaPerimeter = Template.bind({});
-MileAreaPerimeter.args = {
- label: 'Mile',
- name: fieldEnum?.perimeter,
- displayUnitName: fieldEnum?.perimeter_unit,
- defaultValue:
- convert(1).from(area_perimeter.imperial.defaultUnit).to(area_perimeter.databaseUnit) * 1320,
- unitType: area_perimeter,
- system: 'imperial',
- required: true,
-};
-
-export const LitrePerHourWaterValveFlowRate = Template.bind({});
-LitrePerHourWaterValveFlowRate.args = {
- label: 'LitrePerHour',
- name: waterValveEnum.flow_rate,
- displayUnitName: waterValveEnum.flow_rate_unit,
- defaultValue:
- convert(1)
- .from(water_valve_flow_rate.metric.defaultUnit)
- .to(water_valve_flow_rate.databaseUnit) * 59,
- unitType: water_valve_flow_rate,
- system: 'metric',
- required: true,
-};
-
-export const gallonPerHourWaterValveFlowRate = Template.bind({});
-gallonPerHourWaterValveFlowRate.args = {
- label: 'gallonPerHour',
- name: waterValveEnum.flow_rate,
- displayUnitName: waterValveEnum.flow_rate_unit,
- defaultValue:
- convert(1)
- .from(water_valve_flow_rate.imperial.defaultUnit)
- .to(water_valve_flow_rate.databaseUnit) * 0.99,
- unitType: water_valve_flow_rate,
- system: 'imperial',
- required: true,
-};
-
-export const gallonPerMinWaterValveFlowRate = Template.bind({});
-gallonPerMinWaterValveFlowRate.args = {
- label: 'gallonPerMin',
- name: waterValveEnum.flow_rate,
- displayUnitName: waterValveEnum.flow_rate_unit,
- defaultValue:
- convert(1)
- .from(water_valve_flow_rate.imperial.defaultUnit)
- .to(water_valve_flow_rate.databaseUnit) * 1,
- unitType: water_valve_flow_rate,
- system: 'imperial',
- required: true,
-};
-
-export const WeeksCropAge = Template.bind({});
-WeeksCropAge.args = {
- label: 'Weeks',
- name: 'age',
- displayUnitName: 'age_unit',
- defaultValue: 4,
- unitType: crop_age,
- system: 'metric',
- required: true,
-};
-
-export const DisabledWithDefaultValues = Template.bind({});
-DisabledWithDefaultValues.args = {
- label: 'SquareMeter',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- unitType: area_total_area,
- system: 'metric',
- required: true,
- defaultValues: {
- [fieldEnum?.total_area]: 999,
- [fieldEnum?.total_area_unit]: getUnitOptionMap()['m2'],
- },
- disabled: true,
-};
-
-export const StringAsUnit = Template.bind({});
-StringAsUnit.args = {
- label: 'SquareMeter',
- name: fieldEnum?.total_area,
- displayUnitName: fieldEnum?.total_area_unit,
- unitType: area_total_area,
- system: 'metric',
- required: true,
- defaultValues: {
- [fieldEnum?.total_area]: 999,
- [fieldEnum?.total_area_unit]: 'm2',
- },
- disabled: true,
-};
diff --git a/packages/webapp/src/stories/Form/Input/Unit.stories.jsx b/packages/webapp/src/stories/Form/Input/Unit.stories.jsx
new file mode 100644
index 0000000000..bb0f1ecbec
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Input/Unit.stories.jsx
@@ -0,0 +1,280 @@
+import React from 'react';
+import Unit, { getUnitOptionMap } from '../../../components/Form/Unit';
+import { componentDecorators } from '../../Pages/config/Decorators';
+import { bufferZoneEnum, fieldEnum, waterValveEnum } from '../../../containers/constants';
+import {
+ area_perimeter,
+ area_total_area,
+ crop_age,
+ line_width,
+ water_valve_flow_rate,
+} from '../../../util/convert-units/unit';
+import { useForm } from 'react-hook-form';
+import { convert } from '../../../util/convert-units/convert';
+
+const UnitWithHookForm = (props) => {
+ const {
+ register,
+ setValue,
+ getValues,
+ watch,
+ setError,
+ control,
+ handleSubmit,
+
+ formState: { errors },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: props.defaultValues,
+ });
+ return (
+
+ );
+};
+
+export default {
+ title: 'Components/Input/Unit',
+ component: UnitWithHookForm,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'Default',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ unitType: area_total_area,
+ system: 'imperial',
+ required: true,
+};
+
+export const HasLeaf = Template.bind({});
+HasLeaf.args = {
+ label: 'Default',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ unitType: area_total_area,
+ system: 'imperial',
+ required: true,
+ hasLeaf: true,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ label: 'sqft',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ defaultValue: 999,
+ unitType: area_total_area,
+ system: 'imperial',
+ required: true,
+ disabled: true,
+};
+
+export const WithOneUnit = Template.bind({});
+WithOneUnit.args = {
+ label: 'WithOneUnit',
+ name: bufferZoneEnum?.width,
+ displayUnitName: bufferZoneEnum?.width_unit,
+ unitType: line_width,
+ system: 'imperial',
+ required: true,
+};
+
+export const WithOneUnitDisabled = Template.bind({});
+WithOneUnitDisabled.args = {
+ label: 'ft',
+ name: bufferZoneEnum?.width,
+ displayUnitName: bufferZoneEnum?.width_unit,
+ unitType: line_width,
+ defaultValue: 999,
+ system: 'imperial',
+ required: true,
+ disabled: true,
+};
+
+export const WithToolTip = Template.bind({});
+WithToolTip.args = {
+ label: 'WithToolTip',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ unitType: area_total_area,
+ system: 'imperial',
+ required: true,
+ toolTipContent: 'toolTip',
+};
+
+export const SquareMeterAreaTotalArea = Template.bind({});
+SquareMeterAreaTotalArea.args = {
+ label: 'SquareMeter',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ defaultValue: 999,
+ unitType: area_total_area,
+ system: 'metric',
+ required: true,
+};
+
+export const HectareAreaTotalArea = Template.bind({});
+HectareAreaTotalArea.args = {
+ label: 'Hectare',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ defaultValue: 1001,
+ unitType: area_total_area,
+ system: 'metric',
+ required: true,
+};
+
+export const AcreAreaTotalArea = Template.bind({});
+AcreAreaTotalArea.args = {
+ label: 'Acre',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ defaultValue:
+ convert(1).from(area_total_area.imperial.defaultUnit).to(area_total_area.databaseUnit) * 10890,
+ unitType: area_total_area,
+ system: 'imperial',
+ required: true,
+};
+
+export const MeterAreaPerimeter = Template.bind({});
+MeterAreaPerimeter.args = {
+ label: 'Meter',
+ name: fieldEnum.perimeter,
+ displayUnitName: fieldEnum?.perimeter_unit,
+ defaultValue: 999,
+ unitType: area_perimeter,
+ system: 'metric',
+ required: true,
+};
+
+export const InchLineWidth = Template.bind({});
+InchLineWidth.args = {
+ label: 'Inch',
+ name: bufferZoneEnum.length,
+ displayUnitName: bufferZoneEnum.length_unit,
+ defaultValue: convert(1).from(line_width.imperial.defaultUnit).to(line_width.databaseUnit) * 19,
+ unitType: line_width,
+ system: 'imperial',
+ required: true,
+};
+
+export const FeetAreaPerimeter = Template.bind({});
+FeetAreaPerimeter.args = {
+ label: 'Feet',
+ name: fieldEnum?.perimeter,
+ displayUnitName: fieldEnum?.perimeter_unit,
+ defaultValue:
+ convert(1).from(area_perimeter.imperial.defaultUnit).to(area_perimeter.databaseUnit) * 1319,
+ unitType: area_perimeter,
+ system: 'imperial',
+ required: true,
+};
+
+export const MileAreaPerimeter = Template.bind({});
+MileAreaPerimeter.args = {
+ label: 'Mile',
+ name: fieldEnum?.perimeter,
+ displayUnitName: fieldEnum?.perimeter_unit,
+ defaultValue:
+ convert(1).from(area_perimeter.imperial.defaultUnit).to(area_perimeter.databaseUnit) * 1320,
+ unitType: area_perimeter,
+ system: 'imperial',
+ required: true,
+};
+
+export const LitrePerHourWaterValveFlowRate = Template.bind({});
+LitrePerHourWaterValveFlowRate.args = {
+ label: 'LitrePerHour',
+ name: waterValveEnum.flow_rate,
+ displayUnitName: waterValveEnum.flow_rate_unit,
+ defaultValue:
+ convert(1)
+ .from(water_valve_flow_rate.metric.defaultUnit)
+ .to(water_valve_flow_rate.databaseUnit) * 59,
+ unitType: water_valve_flow_rate,
+ system: 'metric',
+ required: true,
+};
+
+export const gallonPerHourWaterValveFlowRate = Template.bind({});
+gallonPerHourWaterValveFlowRate.args = {
+ label: 'gallonPerHour',
+ name: waterValveEnum.flow_rate,
+ displayUnitName: waterValveEnum.flow_rate_unit,
+ defaultValue:
+ convert(1)
+ .from(water_valve_flow_rate.imperial.defaultUnit)
+ .to(water_valve_flow_rate.databaseUnit) * 0.99,
+ unitType: water_valve_flow_rate,
+ system: 'imperial',
+ required: true,
+};
+
+export const gallonPerMinWaterValveFlowRate = Template.bind({});
+gallonPerMinWaterValveFlowRate.args = {
+ label: 'gallonPerMin',
+ name: waterValveEnum.flow_rate,
+ displayUnitName: waterValveEnum.flow_rate_unit,
+ defaultValue:
+ convert(1)
+ .from(water_valve_flow_rate.imperial.defaultUnit)
+ .to(water_valve_flow_rate.databaseUnit) * 1,
+ unitType: water_valve_flow_rate,
+ system: 'imperial',
+ required: true,
+};
+
+export const WeeksCropAge = Template.bind({});
+WeeksCropAge.args = {
+ label: 'Weeks',
+ name: 'age',
+ displayUnitName: 'age_unit',
+ defaultValue: 4,
+ unitType: crop_age,
+ system: 'metric',
+ required: true,
+};
+
+export const DisabledWithDefaultValues = Template.bind({});
+DisabledWithDefaultValues.args = {
+ label: 'SquareMeter',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ unitType: area_total_area,
+ system: 'metric',
+ required: true,
+ defaultValues: {
+ [fieldEnum?.total_area]: 999,
+ [fieldEnum?.total_area_unit]: getUnitOptionMap()['m2'],
+ },
+ disabled: true,
+};
+
+export const StringAsUnit = Template.bind({});
+StringAsUnit.args = {
+ label: 'SquareMeter',
+ name: fieldEnum?.total_area,
+ displayUnitName: fieldEnum?.total_area_unit,
+ unitType: area_total_area,
+ system: 'metric',
+ required: true,
+ defaultValues: {
+ [fieldEnum?.total_area]: 999,
+ [fieldEnum?.total_area_unit]: 'm2',
+ },
+ disabled: true,
+};
diff --git a/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.js b/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.js
deleted file mode 100644
index 3cc7ff7abc..0000000000
--- a/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import InputAutoSize from '../../../components/Form/InputAutoSize';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/InputAutoSize',
- component: InputAutoSize,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const WithDefaultValue = Template.bind({});
-WithDefaultValue.args = {
- label: 'default value',
- defaultValue: 'default value',
- rowsMax: 4,
-};
-
-export const Optional = Template.bind({});
-Optional.args = {
- label: 'optional',
- rowsMax: 4,
- optional: true,
-};
-
-export const Primary = Template.bind({});
-Primary.args = {
- label: 'primary',
- rowsMax: 4,
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- label: 'disabled',
- rowsMax: 4,
- disabled: true,
- defaultValue: 'disabled',
-};
-
-export const WithError = Template.bind({});
-WithError.args = {
- label: 'error',
- rowsMax: 4,
- errors: 'error',
-};
-
-export const MultiRow = Template.bind({});
-MultiRow.args = {
- label: 'multi row',
- rowsMax: 4,
- defaultValue: 'multi row, '.repeat(100),
-};
diff --git a/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.jsx b/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.jsx
new file mode 100644
index 0000000000..9cfc58e2a1
--- /dev/null
+++ b/packages/webapp/src/stories/Form/InputAutoSize/InputAutoSize.stories.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import InputAutoSize from '../../../components/Form/InputAutoSize';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/InputAutoSize',
+ component: InputAutoSize,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const WithDefaultValue = Template.bind({});
+WithDefaultValue.args = {
+ label: 'default value',
+ defaultValue: 'default value',
+ rowsMax: 4,
+};
+
+export const Optional = Template.bind({});
+Optional.args = {
+ label: 'optional',
+ rowsMax: 4,
+ optional: true,
+};
+
+export const Primary = Template.bind({});
+Primary.args = {
+ label: 'primary',
+ rowsMax: 4,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ label: 'disabled',
+ rowsMax: 4,
+ disabled: true,
+ defaultValue: 'disabled',
+};
+
+export const WithError = Template.bind({});
+WithError.args = {
+ label: 'error',
+ rowsMax: 4,
+ errors: 'error',
+};
+
+export const MultiRow = Template.bind({});
+MultiRow.args = {
+ label: 'multi row',
+ rowsMax: 4,
+ defaultValue: 'multi row, '.repeat(100),
+};
diff --git a/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.js b/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.js
deleted file mode 100644
index 725470a0d2..0000000000
--- a/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import NativeDatePickerWrapper from '../../../components/Form/NativeDatePicker/NativeDatePickerWrapper';
-import { componentDecorators } from '../../Pages/config/decorators';
-import { Underlined } from '../../../components/Typography';
-
-export default {
- title: 'Components/NativeDatePickerWrapper',
- component: NativeDatePickerWrapper,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- children: Pick a date ,
-};
diff --git a/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.jsx b/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.jsx
new file mode 100644
index 0000000000..bc992ddd10
--- /dev/null
+++ b/packages/webapp/src/stories/Form/NativeDatePickerWrapper/NativeDatePickerWrapper.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import NativeDatePickerWrapper from '../../../components/Form/NativeDatePicker/NativeDatePickerWrapper';
+import { componentDecorators } from '../../Pages/config/Decorators';
+import { Underlined } from '../../../components/Typography';
+
+export default {
+ title: 'Components/NativeDatePickerWrapper',
+ component: NativeDatePickerWrapper,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ children: Pick a date ,
+};
diff --git a/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.js b/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.js
deleted file mode 100644
index 127ddd4db5..0000000000
--- a/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import React from 'react';
-import ReactSelect from '../../../components/Form/ReactSelect';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-const options = [
- { value: 'chocolate', label: 'Chocolate' },
- { value: 'strawberry', label: 'Strawberry' },
- { value: 'vanilla', label: 'Vanilla' },
- { label: 'Sand', value: 'sand' },
- { label: 'Loamy Sand', value: 'loamySand' },
- { label: 'Sandy Loam', value: 'sandyLoam' },
- { label: 'Loam', value: 'loam' },
- { label: 'Silt Loam', value: 'siltLoam' },
- { label: 'Silt', value: 'silt' },
- { label: 'Sandy Clay Loam', value: 'sandyClayLoam' },
- { label: 'Clay Loam', value: 'clayLoam' },
- { label: 'Silty Clay Loam', value: 'siltyClayLoam' },
- { label: 'Sandy Clay', value: 'sandyClay' },
- { label: 'Silty Clay', value: 'siltyClay' },
- { label: 'Clay', value: 'clay' },
- { label: '0-5cm', value: 5 },
- { label: '0-10cm', value: 10 },
- { label: '0-20cm', value: 20 },
- { label: '21-30cm', value: 30 },
- { label: '30-50cm', value: 50 },
- { label: '51-100cm', value: 100 },
-];
-
-export default {
- title: 'Components/ReactSelect',
- component: ReactSelect,
- decorators: componentDecorators,
-};
-
-const Template = (args) => (
- <>
-
- >
-);
-
-export const Default = Template.bind({});
-Default.args = {
- options: options,
- label: 'label',
- placeholder: 'placeholder',
- defaultMenuIsOpen: true,
-};
-
-export const WithTooltip = Template.bind({});
-WithTooltip.args = {
- options: options,
- label: 'label',
- placeholder: 'placeholder',
- defaultMenuIsOpen: true,
- toolTipContent:
- 'Gender information is collected for research purposes only and will only be shared with personally identifying information removed',
-};
-
-export const Multi = Template.bind({});
-Multi.args = {
- options: options,
- label: 'label',
- placeholder: 'placeholder',
- defaultMenuIsOpen: true,
- isMulti: true,
-};
-export const Creatable = Template.bind({});
-Creatable.args = {
- options: options,
- label: 'label',
- placeholder: 'placeholder',
- creatable: true,
-};
-export const Disabled = Template.bind({});
-Disabled.args = {
- options: options,
- label: 'label',
- placeholder: 'placeholder',
- isDisabled: true,
-};
diff --git a/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.jsx b/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.jsx
new file mode 100644
index 0000000000..45c7903534
--- /dev/null
+++ b/packages/webapp/src/stories/Form/ReactSelect/ReactSelect.stories.jsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import ReactSelect from '../../../components/Form/ReactSelect';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+const options = [
+ { value: 'chocolate', label: 'Chocolate' },
+ { value: 'strawberry', label: 'Strawberry' },
+ { value: 'vanilla', label: 'Vanilla' },
+ { label: 'Sand', value: 'sand' },
+ { label: 'Loamy Sand', value: 'loamySand' },
+ { label: 'Sandy Loam', value: 'sandyLoam' },
+ { label: 'Loam', value: 'loam' },
+ { label: 'Silt Loam', value: 'siltLoam' },
+ { label: 'Silt', value: 'silt' },
+ { label: 'Sandy Clay Loam', value: 'sandyClayLoam' },
+ { label: 'Clay Loam', value: 'clayLoam' },
+ { label: 'Silty Clay Loam', value: 'siltyClayLoam' },
+ { label: 'Sandy Clay', value: 'sandyClay' },
+ { label: 'Silty Clay', value: 'siltyClay' },
+ { label: 'Clay', value: 'clay' },
+ { label: '0-5cm', value: 5 },
+ { label: '0-10cm', value: 10 },
+ { label: '0-20cm', value: 20 },
+ { label: '21-30cm', value: 30 },
+ { label: '30-50cm', value: 50 },
+ { label: '51-100cm', value: 100 },
+];
+
+export default {
+ title: 'Components/ReactSelect',
+ component: ReactSelect,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => (
+ <>
+
+ >
+);
+
+export const Default = Template.bind({});
+Default.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ defaultMenuIsOpen: true,
+};
+
+export const WithTooltip = Template.bind({});
+WithTooltip.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ defaultMenuIsOpen: true,
+ toolTipContent:
+ 'Gender information is collected for research purposes only and will only be shared with personally identifying information removed',
+};
+
+export const Multi = Template.bind({});
+Multi.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ defaultMenuIsOpen: true,
+ isMulti: true,
+};
+export const Creatable = Template.bind({});
+Creatable.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ creatable: true,
+};
+export const Disabled = Template.bind({});
+Disabled.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ isDisabled: true,
+};
+export const IsMulti = Template.bind({});
+IsMulti.args = {
+ options: options,
+ label: 'label',
+ placeholder: 'placeholder',
+ isMulti: true,
+};
diff --git a/packages/webapp/src/stories/Form/Slider/Slider.stories.js b/packages/webapp/src/stories/Form/Slider/Slider.stories.js
deleted file mode 100644
index 83d3b47595..0000000000
--- a/packages/webapp/src/stories/Form/Slider/Slider.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import PureSlider from '../../../components/Form/Slider/TimeSlider';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/Slider',
- component: PureSlider,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'Duration',
- setValue: () => {},
-};
diff --git a/packages/webapp/src/stories/Form/Slider/Slider.stories.jsx b/packages/webapp/src/stories/Form/Slider/Slider.stories.jsx
new file mode 100644
index 0000000000..f0918ac9bf
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Slider/Slider.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import PureSlider from '../../../components/Form/Slider/TimeSlider';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Slider',
+ component: PureSlider,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'Duration',
+ setValue: () => {},
+};
diff --git a/packages/webapp/src/stories/Form/Switch/Switch.stories.jsx b/packages/webapp/src/stories/Form/Switch/Switch.stories.jsx
new file mode 100644
index 0000000000..e62d2bbcc4
--- /dev/null
+++ b/packages/webapp/src/stories/Form/Switch/Switch.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import Switch from '../../../components/Form/Switch';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Switch',
+ component: Switch,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {};
+
+export const Checked = Template.bind({});
+Checked.args = {
+ checked: true,
+};
+
+export const WithLabel = Template.bind({});
+WithLabel.args = {
+ checked: true,
+ label: 'Switch',
+};
diff --git a/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.js b/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.js
deleted file mode 100644
index 63afbd3f9b..0000000000
--- a/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import Checkbox from '../../../components/Form/Checkbox';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/Checkbox',
- component: Checkbox,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'checkbox',
-};
-
-export const Checked = Template.bind({});
-Checked.args = {
- label: 'checkbox',
- checked: true,
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- label: 'disabled',
- disabled: true,
-};
-
-export const CheckedAndDisabled = Template.bind({});
-CheckedAndDisabled.args = {
- label: 'disabled',
- disabled: true,
- checked: true,
-};
-
-export const WithError = Template.bind({});
-WithError.args = {
- errors: 'error error error error',
-};
-
-const classes = {
- checkbox: { backgroundColor: 'yellow' },
- label: { fontSize: '50px' },
- container: { marginLeft: '100px' },
-};
-
-export const SM = Template.bind({});
-SM.args = {
- label: 'checkbox',
- sm: true,
-};
-
-export const WithClasses = Template.bind({});
-WithClasses.args = {
- errors: 'error error error error',
- classes: classes,
-};
diff --git a/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.jsx b/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.jsx
new file mode 100644
index 0000000000..f199d145dc
--- /dev/null
+++ b/packages/webapp/src/stories/Form/checkbox/Checkbox.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Checkbox from '../../../components/Form/Checkbox';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Checkbox',
+ component: Checkbox,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'checkbox',
+};
+
+export const Checked = Template.bind({});
+Checked.args = {
+ label: 'checkbox',
+ checked: true,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ label: 'disabled',
+ disabled: true,
+};
+
+export const CheckedAndDisabled = Template.bind({});
+CheckedAndDisabled.args = {
+ label: 'disabled',
+ disabled: true,
+ checked: true,
+};
+
+export const WithError = Template.bind({});
+WithError.args = {
+ errors: 'error error error error',
+};
+
+const classes = {
+ checkbox: { backgroundColor: 'yellow' },
+ label: { fontSize: '50px' },
+ container: { marginLeft: '100px' },
+};
+
+export const SM = Template.bind({});
+SM.args = {
+ label: 'checkbox',
+ sm: true,
+};
+
+export const WithClasses = Template.bind({});
+WithClasses.args = {
+ errors: 'error error error error',
+ classes: classes,
+};
diff --git a/packages/webapp/src/stories/Form/radio/Radio.stories.js b/packages/webapp/src/stories/Form/radio/Radio.stories.js
deleted file mode 100644
index 4662664c9b..0000000000
--- a/packages/webapp/src/stories/Form/radio/Radio.stories.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-import Radio from '../../../components/Form/Radio';
-import { componentDecorators } from '../../Pages/config/decorators';
-
-export default {
- title: 'Components/Radio',
- component: Radio,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {
- label: 'checkbox',
-};
-
-export const Checked = Template.bind({});
-Checked.args = {
- label: 'checkbox',
- checked: true,
-};
-
-export const Disabled = Template.bind({});
-Disabled.args = {
- label: 'disabled',
- disabled: true,
-};
-
-export const CheckedAndDisabled = Template.bind({});
-CheckedAndDisabled.args = {
- label: 'disabled',
- disabled: true,
- checked: true,
-};
diff --git a/packages/webapp/src/stories/Form/radio/Radio.stories.jsx b/packages/webapp/src/stories/Form/radio/Radio.stories.jsx
new file mode 100644
index 0000000000..9735c25a91
--- /dev/null
+++ b/packages/webapp/src/stories/Form/radio/Radio.stories.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import Radio from '../../../components/Form/Radio';
+import { componentDecorators } from '../../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Radio',
+ component: Radio,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {
+ label: 'checkbox',
+};
+
+export const Checked = Template.bind({});
+Checked.args = {
+ label: 'checkbox',
+ checked: true,
+};
+
+export const Disabled = Template.bind({});
+Disabled.args = {
+ label: 'disabled',
+ disabled: true,
+};
+
+export const CheckedAndDisabled = Template.bind({});
+CheckedAndDisabled.args = {
+ label: 'disabled',
+ disabled: true,
+ checked: true,
+};
diff --git a/packages/webapp/src/stories/Form/radio/RadioGroup.stories.js b/packages/webapp/src/stories/Form/radio/RadioGroup.stories.js
deleted file mode 100644
index cdf46a51c3..0000000000
--- a/packages/webapp/src/stories/Form/radio/RadioGroup.stories.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import React from 'react';
-import RadioGroup from '../../../components/Form/RadioGroup';
-import { componentDecorators } from '../../Pages/config/decorators';
-import { useForm } from 'react-hook-form';
-
-const RadioGroupWithHookForm = ({ defaultValues, ...props }) => {
- const {
- control,
- handleSubmit,
- getValues,
- formState: { isValid },
- } = useForm({
- mode: 'onChange',
- defaultValues: defaultValues,
- });
- return (
-
- );
-};
-
-export default {
- title: 'Components/Radio/RadioGroup',
- component: RadioGroupWithHookForm,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Column = Template.bind({});
-Column.args = {
- name: 'bool',
-};
-
-export const Row = Template.bind({});
-Row.args = {
- name: 'bool',
- row: true,
-};
-
-export const WithNotSure = Template.bind({});
-WithNotSure.args = {
- name: 'bool',
- showNotSure: true,
-};
-
-export const Required = Template.bind({});
-Required.args = {
- name: 'bool',
- required: true,
-};
-
-export const DefaultYes = Template.bind({});
-DefaultYes.args = {
- name: 'bool',
- row: true,
- defaultValues: { bool: true },
-};
-
-export const DefaultNo = Template.bind({});
-DefaultNo.args = {
- name: 'bool',
- row: true,
- defaultValues: { bool: false },
-};
-
-export const RadioOptions = Template.bind({});
-RadioOptions.args = {
- name: 'bool',
- radios: [
- { label: 'option1', value: 'option1', defaultChecked: true },
- { label: 'option2', value: 'option2' },
- { label: 'option3', value: 'option3' },
- { label: 'option4', value: 'option4' },
- ],
-};
diff --git a/packages/webapp/src/stories/Form/radio/RadioGroup.stories.jsx b/packages/webapp/src/stories/Form/radio/RadioGroup.stories.jsx
new file mode 100644
index 0000000000..60d2d48e38
--- /dev/null
+++ b/packages/webapp/src/stories/Form/radio/RadioGroup.stories.jsx
@@ -0,0 +1,81 @@
+import React from 'react';
+import RadioGroup from '../../../components/Form/RadioGroup';
+import { componentDecorators } from '../../Pages/config/Decorators';
+import { useForm } from 'react-hook-form';
+
+const RadioGroupWithHookForm = ({ defaultValues, ...props }) => {
+ const {
+ control,
+ handleSubmit,
+ getValues,
+ formState: { isValid },
+ } = useForm({
+ mode: 'onChange',
+ defaultValues: defaultValues,
+ });
+ return (
+
+ );
+};
+
+export default {
+ title: 'Components/Radio/RadioGroup',
+ component: RadioGroupWithHookForm,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Column = Template.bind({});
+Column.args = {
+ name: 'bool',
+};
+
+export const Row = Template.bind({});
+Row.args = {
+ name: 'bool',
+ row: true,
+};
+
+export const WithNotSure = Template.bind({});
+WithNotSure.args = {
+ name: 'bool',
+ showNotSure: true,
+};
+
+export const Required = Template.bind({});
+Required.args = {
+ name: 'bool',
+ required: true,
+};
+
+export const DefaultYes = Template.bind({});
+DefaultYes.args = {
+ name: 'bool',
+ row: true,
+ defaultValues: { bool: true },
+};
+
+export const DefaultNo = Template.bind({});
+DefaultNo.args = {
+ name: 'bool',
+ row: true,
+ defaultValues: { bool: false },
+};
+
+export const RadioOptions = Template.bind({});
+RadioOptions.args = {
+ name: 'bool',
+ radios: [
+ { label: 'option1', value: 'option1', defaultChecked: true },
+ { label: 'option2', value: 'option2' },
+ { label: 'option3', value: 'option3' },
+ { label: 'option4', value: 'option4' },
+ ],
+};
diff --git a/packages/webapp/src/stories/Loading/Loading.stories.js b/packages/webapp/src/stories/Loading/Loading.stories.js
deleted file mode 100644
index 3e1f11ebc0..0000000000
--- a/packages/webapp/src/stories/Loading/Loading.stories.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { Loading } from '../../components/Loading/Loading';
-import Spinner from '../../components/Spinner';
-import decorator from '../Pages/config/decorators';
-import Form from '../../components/Form';
-import Button from '../../components/Form/Button';
-import PageTitle from '../../components/PageTitle/v2';
-
-export default {
- title: 'Components/Loading',
- component: Loading,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-const TemplateWithText = (args) => (
-
-);
-export const Primary = Template.bind({});
-Primary.args = {};
-
-export const InForm = TemplateWithText.bind({});
-InForm.args = {};
-
-export const Transparent = () => ;
diff --git a/packages/webapp/src/stories/Loading/Loading.stories.jsx b/packages/webapp/src/stories/Loading/Loading.stories.jsx
new file mode 100644
index 0000000000..459abee9a6
--- /dev/null
+++ b/packages/webapp/src/stories/Loading/Loading.stories.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { Loading } from '../../components/Loading/Loading';
+import Spinner from '../../components/Spinner';
+import decorator from '../Pages/config/Decorators';
+import Form from '../../components/Form';
+import Button from '../../components/Form/Button';
+import PageTitle from '../../components/PageTitle/v2';
+
+export default {
+ title: 'Components/Loading',
+ component: Loading,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+const TemplateWithText = (args) => (
+
+);
+export const Primary = Template.bind({});
+Primary.args = {};
+
+export const InForm = TemplateWithText.bind({});
+InForm.args = {};
+
+export const Transparent = () => ;
diff --git a/packages/webapp/src/stories/MenuItem/CertiferSelectionMenuItem.stories.js b/packages/webapp/src/stories/MenuItem/CertiferSelectionMenuItem.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/MenuItem/CertiferSelectionMenuItem.stories.js
rename to packages/webapp/src/stories/MenuItem/CertiferSelectionMenuItem.stories.jsx
diff --git a/packages/webapp/src/stories/MenuItem/ChooseFarmMenuItem.stories.js b/packages/webapp/src/stories/MenuItem/ChooseFarmMenuItem.stories.jsx
similarity index 100%
rename from packages/webapp/src/stories/MenuItem/ChooseFarmMenuItem.stories.js
rename to packages/webapp/src/stories/MenuItem/ChooseFarmMenuItem.stories.jsx
diff --git a/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.js b/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.js
deleted file mode 100644
index e0da023855..0000000000
--- a/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import AbandonManagementPlanModal from '../../components/Modals/AbandonManagementPlanModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/AbandonManagementPlanModal',
- decorators: componentDecorators,
- component: AbandonManagementPlanModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.jsx b/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.jsx
new file mode 100644
index 0000000000..29a117928e
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/AbandonManagementPlanModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import AbandonManagementPlanModal from '../../components/Modals/AbandonManagementPlanModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/AbandonManagementPlanModal',
+ decorators: componentDecorators,
+ component: AbandonManagementPlanModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.js b/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.js
deleted file mode 100644
index 961c3eb954..0000000000
--- a/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import AdjustAreaModal from '../../components/Map/Modals/AdjustArea';
-
-export default {
- title: 'Components/Modals/AdjustAreaModal',
- decorators: componentDecorators,
- component: AdjustAreaModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.jsx b/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.jsx
new file mode 100644
index 0000000000..4710a888db
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/AdjustAreaTutorialModal.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import AdjustAreaModal from '../../components/Map/Modals/AdjustArea';
+
+export default {
+ title: 'Components/Modals/AdjustAreaModal',
+ decorators: componentDecorators,
+ component: AdjustAreaModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.js b/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.js
deleted file mode 100644
index db547f2a73..0000000000
--- a/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import AdjustLineModal from '../../components/Map/Modals/AdjustLine';
-
-export default {
- title: 'Components/Modals/AdjustLineModal',
- decorators: componentDecorators,
- component: AdjustLineModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.jsx b/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.jsx
new file mode 100644
index 0000000000..5bed81ac95
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/AdjustLineTutorialModal.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import AdjustLineModal from '../../components/Map/Modals/AdjustLine';
+
+export default {
+ title: 'Components/Modals/AdjustLineModal',
+ decorators: componentDecorators,
+ component: AdjustLineModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.js b/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.js
deleted file mode 100644
index a0003fa839..0000000000
--- a/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import ArchiveDocumentModal from '../../components/Modals/ArchiveDocumentModal';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Modals/ArchiveDocumentModal',
- decorators: componentDecorators,
- component: ArchiveDocumentModal,
-};
-
-const Template = () => ;
-
-export const Primary = Template.bind({});
diff --git a/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.jsx b/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.jsx
new file mode 100644
index 0000000000..df7a937714
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ArchiveDocumentModal.stories.jsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import ArchiveDocumentModal from '../../components/Modals/ArchiveDocumentModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Modals/ArchiveDocumentModal',
+ decorators: componentDecorators,
+ component: ArchiveDocumentModal,
+};
+
+const Template = () => ;
+
+export const Primary = Template.bind({});
diff --git a/packages/webapp/src/stories/Modal/CancelFlowModal.stories.js b/packages/webapp/src/stories/Modal/CancelFlowModal.stories.js
deleted file mode 100644
index 4edb658ca9..0000000000
--- a/packages/webapp/src/stories/Modal/CancelFlowModal.stories.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import CancelFlowModal from '../../components/Modals/CancelFlowModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/CancelFlowModal',
- decorators: componentDecorators,
- component: CancelFlowModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- flow: 'MANAGEMENT_PLAN',
- dismissModal: () => {
- console.log('dismissing modal');
- },
- handleCancel: () => {
- console.log('cancelling flow');
- },
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/CancelFlowModal.stories.jsx b/packages/webapp/src/stories/Modal/CancelFlowModal.stories.jsx
new file mode 100644
index 0000000000..f58f12b6f0
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/CancelFlowModal.stories.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import CancelFlowModal from '../../components/Modals/CancelFlowModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/CancelFlowModal',
+ decorators: componentDecorators,
+ component: CancelFlowModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ flow: 'MANAGEMENT_PLAN',
+ dismissModal: () => {
+ console.log('dismissing modal');
+ },
+ handleCancel: () => {
+ console.log('cancelling flow');
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.js b/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.js
deleted file mode 100644
index 03011e75aa..0000000000
--- a/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import DrawAreaModal from '../../components/Map/Modals/DrawArea';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/DrawAreaModal',
- decorators: componentDecorators,
- component: DrawAreaModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.jsx b/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.jsx
new file mode 100644
index 0000000000..724f481e69
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/DrawAreaTutorialModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import DrawAreaModal from '../../components/Map/Modals/DrawArea';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/DrawAreaModal',
+ decorators: componentDecorators,
+ component: DrawAreaModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.js b/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.js
deleted file mode 100644
index 6700e69ac3..0000000000
--- a/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import DrawLineModal from '../../components/Map/Modals/DrawLine';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/DrawLineModal',
- decorators: componentDecorators,
- component: DrawLineModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.jsx b/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.jsx
new file mode 100644
index 0000000000..d38a481665
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/DrawLineTutorialModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import DrawLineModal from '../../components/Map/Modals/DrawLine';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/DrawLineModal',
+ decorators: componentDecorators,
+ component: DrawLineModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.js b/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.js
deleted file mode 100644
index cead46d58b..0000000000
--- a/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import EditCropVarietyModal from '../../components/Modals/EditCropVarietyModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/EditCropVarietyModal',
- decorators: componentDecorators,
- component: EditCropVarietyModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- dismissModal: () => {
- console.log('dismissing modal');
- },
- handleEdit: () => {
- console.log('push to edit crop');
- },
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.jsx b/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.jsx
new file mode 100644
index 0000000000..356153bb6a
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/EditCropVarietyModal.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import EditCropVarietyModal from '../../components/Modals/EditCropVarietyModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/EditCropVarietyModal',
+ decorators: componentDecorators,
+ component: EditCropVarietyModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ dismissModal: () => {
+ console.log('dismissing modal');
+ },
+ handleEdit: () => {
+ console.log('push to edit crop');
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/ExportMapModal.stories.js b/packages/webapp/src/stories/Modal/ExportMapModal.stories.js
deleted file mode 100644
index 2db8c82d96..0000000000
--- a/packages/webapp/src/stories/Modal/ExportMapModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import ExportMapModal from '../../components/Modals/ExportMapModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/ExportMapModal',
- decorators: componentDecorators,
- component: ExportMapModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/ExportMapModal.stories.jsx b/packages/webapp/src/stories/Modal/ExportMapModal.stories.jsx
new file mode 100644
index 0000000000..bb9a689fa1
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ExportMapModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import ExportMapModal from '../../components/Modals/ExportMapModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/ExportMapModal',
+ decorators: componentDecorators,
+ component: ExportMapModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.js b/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.js
deleted file mode 100644
index 56feede6c8..0000000000
--- a/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { componentDecoratorsGreyBackground } from '../Pages/config/decorators';
-import FarmSwitchPureOutroSplash from '../../components/FarmSwitchOutro';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/FarmSwitchModal',
- decorators: componentDecoratorsGreyBackground,
- component: FarmSwitchPureOutroSplash,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = { farm_name: 'liteFarm' };
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.jsx b/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.jsx
new file mode 100644
index 0000000000..813e478b8a
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/FarmSwitchModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { componentDecoratorsGreyBackground } from '../Pages/config/Decorators';
+import FarmSwitchPureOutroSplash from '../../components/FarmSwitchOutro';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/FarmSwitchModal',
+ decorators: componentDecoratorsGreyBackground,
+ component: FarmSwitchPureOutroSplash,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = { farm_name: 'liteFarm' };
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.js b/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.js
deleted file mode 100644
index 131c938b97..0000000000
--- a/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import FileSizeExceedModal from '../../components/Modals/FileSizeExceedModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/FileSizeExceedModal',
- decorators: componentDecorators,
- component: FileSizeExceedModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.jsx b/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.jsx
new file mode 100644
index 0000000000..0a897fffa3
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/FileSizeExceedModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import FileSizeExceedModal from '../../components/Modals/FileSizeExceedModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/FileSizeExceedModal',
+ decorators: componentDecorators,
+ component: FileSizeExceedModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/ImageModal.stories.js b/packages/webapp/src/stories/Modal/ImageModal.stories.js
deleted file mode 100644
index c447a46da9..0000000000
--- a/packages/webapp/src/stories/Modal/ImageModal.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import ImageModal from '../../components/Modals/ImageModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/ImageModal',
- decorators: componentDecorators,
- component: ImageModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- src: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/planting_method/Rows_1.jpg',
- alt: 'Rows_1',
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/ImageModal.stories.jsx b/packages/webapp/src/stories/Modal/ImageModal.stories.jsx
new file mode 100644
index 0000000000..9fa981bd68
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ImageModal.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import ImageModal from '../../components/Modals/ImageModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/ImageModal',
+ decorators: componentDecorators,
+ component: ImageModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ src: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/planting_method/Rows_1.jpg',
+ alt: 'Rows_1',
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.js b/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.js
deleted file mode 100644
index 6bd748cb2f..0000000000
--- a/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import IncompleteTaskModal from '../../components/Modals/IncompleteTaskModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/IncompleteTaskModal',
- decorators: componentDecorators,
- component: IncompleteTaskModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.jsx b/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.jsx
new file mode 100644
index 0000000000..c81e6f7f50
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/IncompleteTasksModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import IncompleteTaskModal from '../../components/Modals/IncompleteTaskModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/IncompleteTaskModal',
+ decorators: componentDecorators,
+ component: IncompleteTaskModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/MapTutorialModal.stories.js b/packages/webapp/src/stories/Modal/MapTutorialModal.stories.js
deleted file mode 100644
index e371346e72..0000000000
--- a/packages/webapp/src/stories/Modal/MapTutorialModal.stories.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import MapTutorialModal from '../../components/Modals/MapTutorialModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/MapTutorialModal',
- decorators: componentDecorators,
- component: MapTutorialModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- title: 'Tutorial title',
- steps: ['Step 1', 'Step 2', 'Step 3'],
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const NoBullet = Template.bind({});
-NoBullet.args = {
- title: 'Tutorial title',
- steps: ['Step 1', 'Step 2', 'Step 3'],
- hasNoBullet: true,
-};
-NoBullet.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/MapTutorialModal.stories.jsx b/packages/webapp/src/stories/Modal/MapTutorialModal.stories.jsx
new file mode 100644
index 0000000000..ae3bf4082d
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/MapTutorialModal.stories.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import MapTutorialModal from '../../components/Modals/MapTutorialModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/MapTutorialModal',
+ decorators: componentDecorators,
+ component: MapTutorialModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ title: 'Tutorial title',
+ steps: ['Step 1', 'Step 2', 'Step 3'],
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const NoBullet = Template.bind({});
+NoBullet.args = {
+ title: 'Tutorial title',
+ steps: ['Step 1', 'Step 2', 'Step 3'],
+ hasNoBullet: true,
+};
+NoBullet.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/ModalComponentV2.stories.js b/packages/webapp/src/stories/Modal/ModalComponentV2.stories.js
deleted file mode 100644
index 9514a18e4a..0000000000
--- a/packages/webapp/src/stories/Modal/ModalComponentV2.stories.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import React from 'react';
-import ModalComponent from '../../components/Modals/ModalComponent/v2';
-import { componentDecorators } from '../Pages/config/decorators';
-import { Label } from '../../components/Typography';
-import Button from '../../components/Form/Button';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-import styles from '../../components/Modals/CancelFlowModal/styles.module.scss';
-import { ReactComponent as Email } from '../../assets/images/export/email/Email.svg';
-
-export default {
- title: 'Components/Modals/ModalComponentV2',
- decorators: componentDecorators,
- component: ModalComponent,
-};
-
-const Template = (args) => ;
-
-export const Warning = Template.bind({});
-Warning.args = {
- title: 'Cancel your management plan?',
- contents: ['Any information you’ve entered will be discarded. Do you want to proceed?'],
- warning: true,
- buttonGroup: (
- <>
- <>
-
- {'No'}
-
-
- {'Yes'}
-
- >
- >
- ),
-};
-Warning.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Error = Template.bind({});
-Error.args = {
- title: 'Unable to retire',
- contents: [
- 'All crops and tasks associated with Field 1 need to be expired in order to retire the location.',
- ],
- error: true,
-};
-Error.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Primary = Template.bind({});
-Primary.args = {
- title: 'Link sent',
- contents: ['A link has been sent. Please check your email.'],
- icon: ,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Children = Template.bind({});
-Children.args = {
- title: 'Link sent',
- children: A link has been sent. Please check your email. ,
- buttonGroup: Click ,
- icon: ,
-};
-Children.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/ModalComponentV2.stories.jsx b/packages/webapp/src/stories/Modal/ModalComponentV2.stories.jsx
new file mode 100644
index 0000000000..cc0fea8059
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ModalComponentV2.stories.jsx
@@ -0,0 +1,71 @@
+import React from 'react';
+import ModalComponent from '../../components/Modals/ModalComponent/v2';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { Label } from '../../components/Typography';
+import Button from '../../components/Form/Button';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+import styles from '../../components/Modals/CancelFlowModal/styles.module.scss';
+import { ReactComponent as Email } from '../../assets/images/export/email/Email.svg';
+
+export default {
+ title: 'Components/Modals/ModalComponentV2',
+ decorators: componentDecorators,
+ component: ModalComponent,
+};
+
+const Template = (args) => ;
+
+export const Warning = Template.bind({});
+Warning.args = {
+ title: 'Cancel your management plan?',
+ contents: ['Any information you’ve entered will be discarded. Do you want to proceed?'],
+ warning: true,
+ buttonGroup: (
+ <>
+ <>
+
+ {'No'}
+
+
+ {'Yes'}
+
+ >
+ >
+ ),
+};
+Warning.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Error = Template.bind({});
+Error.args = {
+ title: 'Unable to retire',
+ contents: [
+ 'All crops and tasks associated with Field 1 need to be expired in order to retire the location.',
+ ],
+ error: true,
+};
+Error.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Primary = Template.bind({});
+Primary.args = {
+ title: 'Link sent',
+ contents: ['A link has been sent. Please check your email.'],
+ icon: ,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Children = Template.bind({});
+Children.args = {
+ title: 'Link sent',
+ children: A link has been sent. Please check your email. ,
+ buttonGroup: Click ,
+ icon: ,
+};
+Children.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.js b/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.js
deleted file mode 100644
index 1a216baceb..0000000000
--- a/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { NoCropManagementPlanModal } from '../../components/Modals/NoCropManagementPlanModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/NoCropManagementPlanModal',
- decorators: componentDecorators,
- component: NoCropManagementPlanModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.jsx b/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.jsx
new file mode 100644
index 0000000000..9f7e372709
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/NoCropManagementPlanModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { NoCropManagementPlanModal } from '../../components/Modals/NoCropManagementPlanModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/NoCropManagementPlanModal',
+ decorators: componentDecorators,
+ component: NoCropManagementPlanModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/PlantTaskModal.stories.js b/packages/webapp/src/stories/Modal/PlantTaskModal.stories.js
deleted file mode 100644
index e6640e085e..0000000000
--- a/packages/webapp/src/stories/Modal/PlantTaskModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import { PlantingTaskModal } from '../../components/Modals/PlantingTaskModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/PlantingTaskModal',
- decorators: componentDecorators,
- component: PlantingTaskModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/PlantTaskModal.stories.jsx b/packages/webapp/src/stories/Modal/PlantTaskModal.stories.jsx
new file mode 100644
index 0000000000..70cd5b94bc
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/PlantTaskModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { PlantingTaskModal } from '../../components/Modals/PlantingTaskModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/PlantingTaskModal',
+ decorators: componentDecorators,
+ component: PlantingTaskModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/PreparingExportModal.stories.js b/packages/webapp/src/stories/Modal/PreparingExportModal.stories.js
deleted file mode 100644
index 9424591da6..0000000000
--- a/packages/webapp/src/stories/Modal/PreparingExportModal.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import PreparingExportModal from '../../components/Modals/PreparingExportModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/PreparingExportModal',
- decorators: componentDecorators,
- component: PreparingExportModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/PreparingExportModal.stories.jsx b/packages/webapp/src/stories/Modal/PreparingExportModal.stories.jsx
new file mode 100644
index 0000000000..1adac8d4bb
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/PreparingExportModal.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import PreparingExportModal from '../../components/Modals/PreparingExportModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/PreparingExportModal',
+ decorators: componentDecorators,
+ component: PreparingExportModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.js b/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.js
deleted file mode 100644
index ffd251750e..0000000000
--- a/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import RequestConfirmationModal from '../../components/Modals/RequestConfirmationModal';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/RequestConfirmationModal',
- decorators: componentDecorators,
- component: RequestConfirmationModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.jsx b/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.jsx
new file mode 100644
index 0000000000..b1d9023831
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/RequestConfirmationModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import RequestConfirmationModal from '../../components/Modals/RequestConfirmationModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/RequestConfirmationModal',
+ decorators: componentDecorators,
+ component: RequestConfirmationModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.js b/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.js
deleted file mode 100644
index 0a695f4984..0000000000
--- a/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import ResetPasswordModal from '../../components/Modals/ResetPassword';
-import { componentDecorators } from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/ResetPasswordModal',
- decorators: componentDecorators,
- component: ResetPasswordModal,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.jsx b/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.jsx
new file mode 100644
index 0000000000..98f722fd44
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ResetPasswordModal.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import ResetPasswordModal from '../../components/Modals/ResetPassword';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/ResetPasswordModal',
+ decorators: componentDecorators,
+ component: ResetPasswordModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.js b/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.js
deleted file mode 100644
index e8fd9cc405..0000000000
--- a/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import ResetSuccessModal from '../../components/Modals/ResetPasswordSuccess';
-import { componentDecoratorsWithoutPadding } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Modals/ResetSuccessModal',
- component: ResetSuccessModal,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
diff --git a/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.jsx b/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.jsx
new file mode 100644
index 0000000000..5273417b54
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/ResetSuccessModal.stories.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import ResetSuccessModal from '../../components/Modals/ResetPasswordSuccess';
+import { componentDecoratorsWithoutPadding } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Modals/ResetSuccessModal',
+ component: ResetSuccessModal,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
diff --git a/packages/webapp/src/stories/Modal/RevokeUserAccessModal.stories.jsx b/packages/webapp/src/stories/Modal/RevokeUserAccessModal.stories.jsx
new file mode 100644
index 0000000000..5f49c5bedf
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/RevokeUserAccessModal.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import RevokeUserAccessModal from '../../components/Modals/RevokeUserAccessModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/RevokeUserAccessModal',
+ decorators: componentDecorators,
+ component: RevokeUserAccessModal,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ dismissModal: () => {
+ console.log('dismissing modal');
+ },
+ onRevoke: () => {
+ console.log('revoke access');
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.js b/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.js
deleted file mode 100644
index 55784632e3..0000000000
--- a/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import React from 'react';
-import TaskQuickAssignModal from '../../components/Modals/QuickAssignModal';
-import { componentDecorators } from '../Pages/config/decorators';
-
-const props = {
- task_id: 2333,
- due_date: 'Oct 7, 2021',
- isAssigned: true,
- users: [
- {
- user_id: '104942873090979111002',
- first_name: 'litefarm',
- last_name: 'dev',
- },
- {
- user_id: '104942873090979111001',
- first_name: 'litefarm1',
- last_name: 'dev',
- },
- {
- user_id: '104942873090979111000',
- first_name: 'litefarm2',
- last_name: 'dev',
- },
- ],
- user: {
- is_admin: true,
- user_id: '104942873090979111002',
- first_name: 'litefarm',
- last_name: 'dev',
- },
-};
-
-export default {
- title: 'Components/Modals/TaskQuickAssignModal',
- decorators: componentDecorators,
- component: TaskQuickAssignModal,
-};
-
-const Template = (args) => ;
-
-export const Admin = Template.bind({});
-Admin.args = props;
-
-export const Worker = Template.bind({});
-Worker.args = {
- ...props,
- user: { ...props.user, is_admin: false },
-};
diff --git a/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.jsx b/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.jsx
new file mode 100644
index 0000000000..891b6937b1
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/TaskQuickAssignModal.stories.jsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import TaskQuickAssignModal from '../../components/Modals/QuickAssignModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+const props = {
+ task_id: 2333,
+ due_date: 'Oct 7, 2021',
+ isAssigned: true,
+ users: [
+ {
+ user_id: '104942873090979111002',
+ first_name: 'litefarm',
+ last_name: 'dev',
+ },
+ {
+ user_id: '104942873090979111001',
+ first_name: 'litefarm1',
+ last_name: 'dev',
+ },
+ {
+ user_id: '104942873090979111000',
+ first_name: 'litefarm2',
+ last_name: 'dev',
+ },
+ {
+ user_id: '104942873090979111005',
+ first_name: 'litefarm3',
+ last_name: 'dev',
+ },
+ {
+ user_id: '104942873090979111006',
+ first_name: 'litefarm4',
+ last_name: 'dev',
+ },
+ {
+ user_id: '104942873090979111007',
+ first_name: 'litefarm5',
+ last_name: 'dev',
+ },
+ ],
+ user: {
+ is_admin: true,
+ user_id: '104942873090979111002',
+ first_name: 'litefarm',
+ last_name: 'dev',
+ },
+};
+
+export default {
+ title: 'Components/Modals/TaskQuickAssignModal',
+ decorators: componentDecorators,
+ component: TaskQuickAssignModal,
+};
+
+const Template = (args) => ;
+
+export const Admin = Template.bind({});
+Admin.args = props;
+
+export const Worker = Template.bind({});
+Worker.args = {
+ ...props,
+ user: { ...props.user, is_admin: false },
+};
diff --git a/packages/webapp/src/stories/Modal/UpdateTaskDateModal.stories.jsx b/packages/webapp/src/stories/Modal/UpdateTaskDateModal.stories.jsx
new file mode 100644
index 0000000000..ab99d00af5
--- /dev/null
+++ b/packages/webapp/src/stories/Modal/UpdateTaskDateModal.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import UpdateTaskDateModal from '../../components/Modals/UpdateTaskDateModal';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Modals/UpdateTaskDateModal',
+ decorators: componentDecorators,
+ component: UpdateTaskDateModal,
+};
+
+const Template = (args) => ;
+
+export const Admin = Template.bind({});
+Admin.args = {
+ due_date: '2022-02-02',
+};
diff --git a/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.js b/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.js
deleted file mode 100644
index 69c0d1141e..0000000000
--- a/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
-import decorator from '../Pages/config/decorators';
-import { Post } from '../Pages/LocationDetails/AreaDetails/Barn/Barn.stories';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/MuiFullPagePopup',
- decorators: decorator,
- component: MuiFullPagePopup,
-};
-
-const Template = (args) => ;
-
-export const Barn = Template.bind({});
-Barn.args = {
- open: true,
- children: ,
-};
-Barn.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.jsx b/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.jsx
new file mode 100644
index 0000000000..0d251ecab2
--- /dev/null
+++ b/packages/webapp/src/stories/MuiFullPagePopup/MuiFullPagePopup.stories.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import MuiFullPagePopup from '../../components/MuiFullPagePopup/v2';
+import decorator from '../Pages/config/Decorators';
+import { Post } from '../Pages/LocationDetails/AreaDetails/Barn/Barn.stories';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/MuiFullPagePopup',
+ decorators: decorator,
+ component: MuiFullPagePopup,
+};
+
+const Template = (args) => ;
+
+export const Barn = Template.bind({});
+Barn.args = {
+ open: true,
+ children: ,
+};
+Barn.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Navigation/NavBar.stories.js b/packages/webapp/src/stories/Navigation/NavBar.stories.js
deleted file mode 100644
index 6b0ee1325e..0000000000
--- a/packages/webapp/src/stories/Navigation/NavBar.stories.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import { action } from '@storybook/addon-actions';
-import { Provider } from 'react-redux';
-import { Router } from 'react-router-dom';
-import history from './../../history';
-import NavBar from '../../components/Navigation/NavBar';
-import NoFarmNavBar from '../../components/Navigation/NoFarmNavBar';
-import { themeWrapper, useI18next } from '../Pages/config/decorators';
-
-const store = {
- getState: () => {
- return {
- entitiesReducer: {
- userFarmReducer: {
- farm_id: 'farm_id',
- user_id: 'user_id',
- },
- showedSpotlightReducer: {},
- },
- };
- },
- subscribe: () => 0,
- dispatch: action('dispatch'),
-};
-
-export default {
- title: 'Components/Navbar',
- decorators: [
- (story) => {
- const ready = useI18next();
- return ready ? (
-
- {story()}
-
- ) : (
- 'loading'
- );
- },
- themeWrapper,
- ],
- component: NavBar,
-};
-
-export const SignupNavbar = (() => ).bind({});
-
-const Template = (args) => ;
-
-export const HomeNavbar = Template.bind({});
-
-HomeNavbar.args = {
- tooltipInteraction: { profile: false },
- auth: {
- logout: () => {},
- isAuthenticated: () => true,
- },
- history: {
- push: () => {},
- location: { pathname: '/home' },
- replace: () => {},
- },
-};
-
-export const HomeNavbarWithSpotlight = Template.bind({});
-
-HomeNavbarWithSpotlight.args = {
- showSpotLight: true,
- resetSpotlight: () => {},
-};
-
-export const HomeNavbarWithProfileFloater = Template.bind({});
-HomeNavbarWithProfileFloater.args = {
- resetSpotlight: () => {},
- defaultOpenFloater: 'profile',
-};
diff --git a/packages/webapp/src/stories/Navigation/NavBar.stories.jsx b/packages/webapp/src/stories/Navigation/NavBar.stories.jsx
new file mode 100644
index 0000000000..02ba8dcd78
--- /dev/null
+++ b/packages/webapp/src/stories/Navigation/NavBar.stories.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { action } from '@storybook/addon-actions';
+import { Provider } from 'react-redux';
+import { Router } from 'react-router-dom';
+import history from './../../history';
+import NavBar from '../../components/Navigation/NavBar';
+import NoFarmNavBar from '../../components/Navigation/NoFarmNavBar';
+
+const store = {
+ getState: () => {
+ return {
+ entitiesReducer: {
+ userFarmReducer: {
+ farm_id: 'farm_id',
+ user_id: 'user_id',
+ },
+ showedSpotlightReducer: {},
+ },
+ };
+ },
+ subscribe: () => 0,
+ dispatch: action('dispatch'),
+};
+
+export default {
+ title: 'Components/Navbar',
+ component: NavBar,
+};
+
+export const SignupNavbar = (() => ).bind({});
+
+const Template = (args) => ;
+
+export const HomeNavbar = Template.bind({});
+
+HomeNavbar.args = {
+ tooltipInteraction: { profile: false },
+ auth: {
+ logout: () => {},
+ isAuthenticated: () => true,
+ },
+ history: {
+ push: () => {},
+ location: { pathname: '/home' },
+ replace: () => {},
+ },
+};
+
+export const HomeNavbarWithSpotlight = Template.bind({});
+
+HomeNavbarWithSpotlight.args = {
+ showSpotLight: true,
+ resetSpotlight: () => {},
+};
+
+export const HomeNavbarWithProfileFloater = Template.bind({});
+HomeNavbarWithProfileFloater.args = {
+ resetSpotlight: () => {},
+ defaultOpenFloater: 'profile',
+};
diff --git a/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.js b/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.js
deleted file mode 100644
index 0162b848a0..0000000000
--- a/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import { PureProfileFloaterComponent } from '../../components/ProfileFloater';
-import { componentDecoratorsWithoutPadding } from '../Pages/config/decorators';
-import SlideMenu from '../../components/Navigation/NavBar/slideMenu';
-
-export default {
- title: 'Components/Navbar/Drawer',
- decorators: componentDecoratorsWithoutPadding,
- component: PureProfileFloaterComponent,
-};
-
-export const WithManageMenuOpenAndFinance = ((args) => ).bind({});
-WithManageMenuOpenAndFinance.args = {
- manageOpen: true,
- showFinances: true,
-};
-
-export const WithoutManageMenuOpenOrFinance = ((args) => ).bind({});
-WithoutManageMenuOpenOrFinance.args = {
- manageOpen: false,
- showFinances: false,
-};
diff --git a/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.jsx b/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.jsx
new file mode 100644
index 0000000000..a7df1b2b88
--- /dev/null
+++ b/packages/webapp/src/stories/Navigation/NavBarDrawer.stories.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { PureProfileFloaterComponent } from '../../components/Navigation/Floater/ProfileFloater';
+import { componentDecoratorsWithoutPadding } from '../Pages/config/Decorators';
+import SlideMenu from '../../components/Navigation/NavBar/slideMenu';
+
+export default {
+ title: 'Components/Navbar/Drawer',
+ decorators: componentDecoratorsWithoutPadding,
+ component: PureProfileFloaterComponent,
+};
+
+export const WithManageMenuOpenAndFinance = ((args) => ).bind({});
+WithManageMenuOpenAndFinance.args = {
+ manageOpen: true,
+ showFinances: true,
+};
+
+export const WithoutManageMenuOpenOrFinance = ((args) => ).bind({});
+WithoutManageMenuOpenOrFinance.args = {
+ manageOpen: false,
+ showFinances: false,
+};
diff --git a/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.js b/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.js
deleted file mode 100644
index f948be630d..0000000000
--- a/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { PureNotificationFloaterComponent } from '../../components/NotificationFloater';
-import { PureMyFarmFloaterComponent } from '../../components/MyFarmFloater';
-import { PureProfileFloaterComponent } from '../../components/ProfileFloater';
-import { componentDecoratorsGreyBackground } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Navbar/FloaterComponent',
- decorators: componentDecoratorsGreyBackground,
- component: PureProfileFloaterComponent,
-};
-
-export const NotificationFloater = (() => ).bind({});
-
-export const MyFarmFloater = (() => ).bind({});
-
-export const ProfileFloater = ((args) => ).bind({});
-ProfileFloater.args = {};
diff --git a/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.jsx b/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.jsx
new file mode 100644
index 0000000000..0e6c7c8015
--- /dev/null
+++ b/packages/webapp/src/stories/Navigation/NavBarDropdown.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { PureMyFarmFloaterComponent } from '../../components/Navigation/Floater/MyFarmFloater';
+import { PureProfileFloaterComponent } from '../../components/Navigation/Floater/ProfileFloater';
+import { componentDecoratorsGreyBackground } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Navbar/FloaterComponent',
+ decorators: componentDecoratorsGreyBackground,
+ component: PureProfileFloaterComponent,
+};
+
+
+export const MyFarmFloater = (() => ).bind({});
+
+export const ProfileFloater = ((args) => ).bind({});
+ProfileFloater.args = {};
diff --git a/packages/webapp/src/stories/PageBreak/PageBreak.stories.js b/packages/webapp/src/stories/PageBreak/PageBreak.stories.js
deleted file mode 100644
index b91e136a50..0000000000
--- a/packages/webapp/src/stories/PageBreak/PageBreak.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import PageBreak from '../../components/PageBreak';
-import Square from '../../components/Square';
-
-export default {
- title: 'Components/PageBreak',
- component: PageBreak,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Default = Template.bind({});
-Default.args = {};
-
-export const WithLabel = Template.bind({});
-WithLabel.args = {
- label: 'label',
-};
-
-export const WithLabelAndChildren = Template.bind({});
-WithLabelAndChildren.args = {
- label: 'Active',
- children: 8 ,
-};
diff --git a/packages/webapp/src/stories/PageBreak/PageBreak.stories.jsx b/packages/webapp/src/stories/PageBreak/PageBreak.stories.jsx
new file mode 100644
index 0000000000..a46d2130b4
--- /dev/null
+++ b/packages/webapp/src/stories/PageBreak/PageBreak.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import PageBreak from '../../components/PageBreak';
+import Square from '../../components/Square';
+
+export default {
+ title: 'Components/PageBreak',
+ component: PageBreak,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Default = Template.bind({});
+Default.args = {};
+
+export const WithLabel = Template.bind({});
+WithLabel.args = {
+ label: 'label',
+};
+
+export const WithLabelAndChildren = Template.bind({});
+WithLabelAndChildren.args = {
+ label: 'Active',
+ children: 8 ,
+};
diff --git a/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.js b/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.js
deleted file mode 100644
index e767a0e225..0000000000
--- a/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import MultiStepPageTitle from '../../components/PageTitle/MultiStepPageTitle';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/PageTitle/MultiStepPageTitle',
- component: MultiStepPageTitle,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- title: 'title',
- onCancel: () => {},
- onGoBack: () => {},
- value: 50,
-};
-export const Title = Template.bind({});
-Title.args = {
- title: 'title',
-};
-
-export const WithoutCancel = Template.bind({});
-WithoutCancel.args = {
- title: 'title',
- onGoBack: () => {},
-};
diff --git a/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.jsx b/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.jsx
new file mode 100644
index 0000000000..6607db112b
--- /dev/null
+++ b/packages/webapp/src/stories/PageTitle/MultiStepPageTitle.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import MultiStepPageTitle from '../../components/PageTitle/MultiStepPageTitle';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/PageTitle/MultiStepPageTitle',
+ component: MultiStepPageTitle,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ title: 'title',
+ onCancel: () => {},
+ onGoBack: () => {},
+ value: 50,
+};
+export const Title = Template.bind({});
+Title.args = {
+ title: 'title',
+};
+
+export const WithoutCancel = Template.bind({});
+WithoutCancel.args = {
+ title: 'title',
+ onGoBack: () => {},
+};
diff --git a/packages/webapp/src/stories/PageTitle/PageTitle.stories.js b/packages/webapp/src/stories/PageTitle/PageTitle.stories.js
deleted file mode 100644
index 753aeb310f..0000000000
--- a/packages/webapp/src/stories/PageTitle/PageTitle.stories.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import PageTitle from '../../components/PageTitle/v2';
-import decorator from '../Pages/config/decorators';
-
-export default {
- title: 'Components/PageTitle',
- component: PageTitle,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- title: 'title',
- onCancel: () => {},
- onGoBack: () => {},
-};
-export const Title = Template.bind({});
-Title.args = {
- title: 'title',
-};
-
-export const WithoutCancel = Template.bind({});
-WithoutCancel.args = {
- title: 'title',
- onGoBack: () => {},
-};
diff --git a/packages/webapp/src/stories/PageTitle/PageTitle.stories.jsx b/packages/webapp/src/stories/PageTitle/PageTitle.stories.jsx
new file mode 100644
index 0000000000..835fc2c8b3
--- /dev/null
+++ b/packages/webapp/src/stories/PageTitle/PageTitle.stories.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import PageTitle from '../../components/PageTitle/v2';
+import decorator from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/PageTitle',
+ component: PageTitle,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ title: 'title',
+ onCancel: () => {},
+ onGoBack: () => {},
+};
+export const Title = Template.bind({});
+Title.args = {
+ title: 'title',
+};
+
+export const WithoutCancel = Template.bind({});
+WithoutCancel.args = {
+ title: 'title',
+ onGoBack: () => {},
+};
diff --git a/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.js b/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.js
deleted file mode 100644
index 4f58872bfb..0000000000
--- a/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-import AddCropVariety from '../../../components/AddCropVariety/';
-import decorators from '../config/decorators';
-import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
-import { AddLink } from '../../../components/Typography';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Crop/AddCropVariety',
- decorators: decorators,
- component: AddCropVariety,
-};
-
-const Template = (args) => ;
-
-const cropEnum = {
- variety: 'VARIETY',
- supplier: 'SUPPLIER',
- seed_type: 'SEED_TYPE',
- life_cycle: 'LIFE_CYCLE',
-};
-
-export const Primary = Template.bind({});
-Primary.args = {
- cropEnum: cropEnum,
- disabled: true,
- crop: {
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 31,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APRICOT',
- },
- match: {
- params: {
- crop_id: '31',
- },
- },
- useHookFormPersist: () => ({}),
- imageUploader: (
-
- {'Add image'}
-
- ),
- handleGoBack: () => {},
- handleCancel: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.jsx b/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.jsx
new file mode 100644
index 0000000000..2af892fb57
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/AddCropVariety/AddCropVariety.stories.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import AddCropVariety from '../../../components/AddCropVariety/';
+import decorators from '../config/Decorators';
+import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
+import { AddLink } from '../../../components/Typography';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Crop/AddCropVariety',
+ decorators: decorators,
+ component: AddCropVariety,
+};
+
+const Template = (args) => ;
+
+const cropEnum = {
+ variety: 'VARIETY',
+ supplier: 'SUPPLIER',
+ seed_type: 'SEED_TYPE',
+ life_cycle: 'LIFE_CYCLE',
+};
+
+export const Primary = Template.bind({});
+Primary.args = {
+ cropEnum: cropEnum,
+ disabled: true,
+ crop: {
+ crop_common_name: 'Apricot',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 31,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APRICOT',
+ },
+ match: {
+ params: {
+ crop_id: '31',
+ },
+ },
+ useHookFormPersist: () => ({}),
+ imageUploader: (
+
+ {'Add image'}
+
+ ),
+ handleGoBack: () => {},
+ handleCancel: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.js b/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.js
deleted file mode 100644
index 086d91bcb8..0000000000
--- a/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import PureAddNewCrop from '../../../components/AddNewCrop';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Crop/AddNewCrop',
- decorators: decorators,
- component: PureAddNewCrop,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- useHookFormPersist: () => ({}),
- handleGoBack: () => {},
- handleCancel: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WithDropdownOpen = Template.bind({});
-WithDropdownOpen.args = {
- useHookFormPersist: () => ({}),
- isPhysiologyAnatomyDropDownOpen: true,
- handleGoBack: () => {},
- handleCancel: () => {},
-};
-WithDropdownOpen.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.jsx b/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.jsx
new file mode 100644
index 0000000000..a3e6fe7adb
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/AddNewCrop/AddNewCrop.stories.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import PureAddNewCrop from '../../../components/AddNewCrop';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Crop/AddNewCrop',
+ decorators: decorators,
+ component: PureAddNewCrop,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ useHookFormPersist: () => ({}),
+ handleGoBack: () => {},
+ handleCancel: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WithDropdownOpen = Template.bind({});
+WithDropdownOpen.args = {
+ useHookFormPersist: () => ({}),
+ isPhysiologyAnatomyDropDownOpen: true,
+ handleGoBack: () => {},
+ handleCancel: () => {},
+};
+WithDropdownOpen.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.js b/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.js
deleted file mode 100644
index 44f48f8233..0000000000
--- a/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import React from 'react';
-import PureCertificationReportingPeriod from '../../../components/CertificationReportingPeriod';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/Certifications/ReportingPeriod',
- decorators: decorators,
- component: PureCertificationReportingPeriod,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- onSubmit: () => console.log('onSubmit called'),
- onError: () => console.log('onError called'),
- handleGoBack: () => console.log('handleGoBack called'),
- handleCancel: () => console.log('handleCancel called'),
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.jsx b/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.jsx
new file mode 100644
index 0000000000..205d639eb3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/CertificationReportingPeriod/CertificationReportingPeriod.stories.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import PureCertificationReportingPeriod from '../../../components/CertificationReportingPeriod';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/Certifications/ReportingPeriod',
+ decorators: decorators,
+ component: PureCertificationReportingPeriod,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ onSubmit: () => console.log('onSubmit called'),
+ onError: () => console.log('onError called'),
+ handleGoBack: () => console.log('handleGoBack called'),
+ handleCancel: () => console.log('handleCancel called'),
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.js b/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.js
deleted file mode 100644
index 86cef64a69..0000000000
--- a/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import ChooseFarm from '../../../containers/ChooseFarm/';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/ChooseFarm',
- decorators: decorators,
- component: ChooseFarm,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.jsx b/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.jsx
new file mode 100644
index 0000000000..eb0a01ed7f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ChooseFarm/ChooseFarmScreen.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import ChooseFarm from '../../../containers/ChooseFarm/';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/ChooseFarm',
+ decorators: decorators,
+ component: ChooseFarm,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.js b/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.js
deleted file mode 100644
index c2732b2bd6..0000000000
--- a/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PureChooseFarmScreen from '../../../components/ChooseFarm';
-import {
- Active,
- Secondary,
- SecondaryWithoutOwnerName,
-} from '../../MenuItem/ChooseFarmMenuItem.stories';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/PureChooseFarmScreen',
- decorators: decorators,
- component: PureChooseFarmScreen,
-};
-
-const farms = [Secondary.args, SecondaryWithoutOwnerName.args];
-
-const Template = (args) => ;
-
-export const NotSearchable = Template.bind({});
-NotSearchable.args = {
- isOnBoarding: true,
- farms: [Active.args, ...farms],
-};
-NotSearchable.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Searchable = Template.bind({});
-Searchable.args = {
- isOnBoarding: false,
- isSearchable: true,
- farms: [...farms, ...farms, ...farms, Active.args],
-};
-Searchable.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.jsx b/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.jsx
new file mode 100644
index 0000000000..5398a66e0a
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ChooseFarm/PureChooseFarmScreen.stories.jsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PureChooseFarmScreen from '../../../components/ChooseFarm';
+import {
+ Active,
+ Secondary,
+ SecondaryWithoutOwnerName,
+} from '../../MenuItem/ChooseFarmMenuItem.stories';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/PureChooseFarmScreen',
+ decorators: decorators,
+ component: PureChooseFarmScreen,
+};
+
+const farms = [Secondary.args, SecondaryWithoutOwnerName.args];
+
+const Template = (args) => ;
+
+export const NotSearchable = Template.bind({});
+NotSearchable.args = {
+ isOnBoarding: true,
+ farms: [Active.args, ...farms],
+};
+NotSearchable.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Searchable = Template.bind({});
+Searchable.args = {
+ isOnBoarding: false,
+ isSearchable: true,
+ farms: [...farms, ...farms, ...farms, Active.args],
+};
+Searchable.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.js b/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.js
deleted file mode 100644
index c2f1048673..0000000000
--- a/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import PureCropDetail from '../../../components/Crop/detail';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Detail',
- component: PureCropDetail,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const Detail = Template.bind({});
-Detail.args = {
- history: {
- location: { pathname: '/crop/2/detail' },
- },
- match: {
- params: {
- variety_id: 'variety_id',
- },
- },
- variety: {
- cropName: 'Carrot',
- varietyName: 'Nantes',
- supplierName: 'Buckerfields',
- supplier: 'Supplier 1',
- },
-};
diff --git a/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.jsx b/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.jsx
new file mode 100644
index 0000000000..32d0431998
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/CropDetail/CropDetail.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import PureCropDetail from '../../../components/Crop/Detail';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Detail',
+ component: PureCropDetail,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const Detail = Template.bind({});
+Detail.args = {
+ history: {
+ location: { pathname: '/crop/2/detail' },
+ },
+ match: {
+ params: {
+ variety_id: 'variety_id',
+ },
+ },
+ variety: {
+ cropName: 'Carrot',
+ varietyName: 'Nantes',
+ supplierName: 'Buckerfields',
+ supplier: 'Supplier 1',
+ },
+};
diff --git a/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.js b/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.js
deleted file mode 100644
index a362b5821d..0000000000
--- a/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.js
+++ /dev/null
@@ -1,2143 +0,0 @@
-import React from 'react';
-import PureCropList from '../../../components/CropListPage';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Page/CropList',
- component: PureCropList,
- decorators: decorator,
-};
-
-const crops = [
- {
- ca: 14,
- crop_common_name: 'Black pepper',
- crop_genus: 'Piper',
- crop_group: 'Beverage and spice crops',
- crop_id: 82,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- crop_specie: 'nigrum ',
- crop_subgroup: 'Permanent spice crops',
- crop_translation_key: 'BLACK_PEPPER',
- cu: 0.09,
- depletion_fraction: 0.4,
- end_kc: 0.99,
- energy: 27,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.46,
- fl: null,
- folate: 29,
- initial_kc: 0.75,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 256,
- lipid: 0.45,
- max_height: null,
- max_rooting_depth: 0.99,
- mg: 17,
- mid_kc: 1.04,
- mn: 0.1,
- na: 13,
- niacin: 1.24,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 18,
- ph: 32,
- protein: 1.66,
- refuse: null,
- reviewed: true,
- riboflavin: 0.05,
- se: null,
- thiamin: 0.08,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.36,
- vitc: 82.7,
- vite: null,
- vitk: null,
- zn: 0.25,
- compliance_file_url: null,
- crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 143,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 14,
- crop_common_name: 'Black pepper',
- crop_genus: 'Piper',
- crop_group: 'Beverage and spice crops',
- crop_id: 82,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- crop_specie: 'nigrum ',
- crop_subgroup: 'Permanent spice crops',
- crop_translation_key: 'BLACK_PEPPER',
- cu: 0.094,
- depletion_fraction: 0.4,
- end_kc: 0.99,
- energy: 27,
- farm_id: null,
- fe: 0.46,
- fl: null,
- folate: 29,
- initial_kc: 0.75,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 256,
- lipid: 0.45,
- max_height: null,
- max_rooting_depth: 0.99,
- mg: 17,
- mid_kc: 1.04,
- mn: 0.1,
- na: 13,
- niacin: 1.242,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 18,
- ph: 32,
- protein: 1.66,
- refuse: null,
- reviewed: true,
- riboflavin: 0.054,
- se: null,
- thiamin: 0.081,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.357,
- vitc: 82.7,
- vite: null,
- vitk: null,
- zn: 0.25,
- },
- crop_variety: {
- ca: 14,
- compliance_file_url: null,
- crop_id: 82,
- crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- cu: 0.09,
- energy: 27,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.46,
- folate: 29,
- genetically_engineered: null,
- k: 256,
- lifecycle: 'ANNUAL',
- lipid: 0.45,
- mg: 17,
- mn: 0.1,
- na: 13,
- niacin: 1.24,
- nutrient_credits: null,
- organic: null,
- ph: 32,
- protein: 1.66,
- riboflavin: 0.05,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.08,
- treated: null,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.36,
- vitc: 82.7,
- zn: 0.25,
- },
- },
- {
- ca: 44,
- crop_common_name: 'Artichoke',
- crop_genus: 'Cynara',
- crop_group: 'Vegetables and melons',
- crop_id: 66,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
- crop_specie: 'scolymus ',
- crop_subgroup: 'Leafy or stem vegetables',
- crop_translation_key: 'ARTICHOKE',
- cu: 0.23,
- depletion_fraction: 0.45,
- end_kc: 0.95,
- energy: 47,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 1.28,
- fl: null,
- folate: 68,
- initial_kc: 0.5,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 370,
- lipid: 0.15,
- max_height: 0.7,
- max_rooting_depth: 0.75,
- mg: 60,
- mid_kc: 1,
- mn: 0.26,
- na: 94,
- niacin: 1.05,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 90,
- protein: 3.27,
- refuse: null,
- reviewed: true,
- riboflavin: 0.07,
- se: null,
- thiamin: 0.07,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.12,
- vitc: 11.7,
- vite: null,
- vitk: null,
- zn: 0.49,
- compliance_file_url: null,
- crop_variety_id: '19336a35-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 142,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 44,
- crop_common_name: 'Artichoke',
- crop_genus: 'Cynara',
- crop_group: 'Vegetables and melons',
- crop_id: 66,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
- crop_specie: 'scolymus ',
- crop_subgroup: 'Leafy or stem vegetables',
- crop_translation_key: 'ARTICHOKE',
- cu: 0.231,
- depletion_fraction: 0.45,
- end_kc: 0.95,
- energy: 47,
- farm_id: null,
- fe: 1.28,
- fl: null,
- folate: 68,
- initial_kc: 0.5,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 370,
- lipid: 0.15,
- max_height: 0.7,
- max_rooting_depth: 0.75,
- mg: 60,
- mid_kc: 1,
- mn: 0.256,
- na: 94,
- niacin: 1.046,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 90,
- protein: 3.27,
- refuse: null,
- reviewed: true,
- riboflavin: 0.066,
- se: null,
- thiamin: 0.072,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.116,
- vitc: 11.7,
- vite: null,
- vitk: null,
- zn: 0.49,
- },
- crop_variety: {
- ca: 44,
- compliance_file_url: null,
- crop_id: 66,
- crop_variety_id: '19336a35-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
- cu: 0.23,
- energy: 47,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 1.28,
- folate: 68,
- genetically_engineered: null,
- k: 370,
- lifecycle: 'ANNUAL',
- lipid: 0.15,
- mg: 60,
- mn: 0.26,
- na: 94,
- niacin: 1.05,
- nutrient_credits: null,
- organic: null,
- ph: 90,
- protein: 3.27,
- riboflavin: 0.07,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.07,
- treated: null,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.12,
- vitc: 11.7,
- zn: 0.49,
- },
- },
- {
- ca: 6,
- crop_common_name: 'Arrowroot',
- crop_genus: 'Maranta',
- crop_group: 'Potatoes and yams',
- crop_id: 147,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'arundinacea ',
- crop_subgroup: 'High starch Root/tuber crops',
- crop_translation_key: 'ARROWROOT',
- cu: 0.12,
- depletion_fraction: 0.36,
- end_kc: 0.602667,
- energy: 65,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 2.22,
- fl: null,
- folate: 338,
- initial_kc: 0.433333,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 454,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.583333,
- mg: 25,
- mid_kc: 1.03433,
- mn: 0.17,
- na: 26,
- niacin: 1.69,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 15,
- ph: 98,
- protein: 4.24,
- refuse: null,
- reviewed: true,
- riboflavin: 0.06,
- se: null,
- thiamin: 0.14,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.27,
- vitc: 1.9,
- vite: null,
- vitk: null,
- zn: 0.63,
- compliance_file_url: null,
- crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 141,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 6,
- crop_common_name: 'Arrowroot',
- crop_genus: 'Maranta',
- crop_group: 'Potatoes and yams',
- crop_id: 147,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'arundinacea ',
- crop_subgroup: 'High starch Root/tuber crops',
- crop_translation_key: 'ARROWROOT',
- cu: 0.121,
- depletion_fraction: 0.36,
- end_kc: 0.602667,
- energy: 65,
- farm_id: null,
- fe: 2.22,
- fl: null,
- folate: 338,
- initial_kc: 0.433333,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 454,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.583333,
- mg: 25,
- mid_kc: 1.03433,
- mn: 0.174,
- na: 26,
- niacin: 1.693,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 15,
- ph: 98,
- protein: 4.24,
- refuse: null,
- reviewed: true,
- riboflavin: 0.059,
- se: null,
- thiamin: 0.143,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.266,
- vitc: 1.9,
- vite: null,
- vitk: null,
- zn: 0.63,
- },
- crop_variety: {
- ca: 6,
- compliance_file_url: null,
- crop_id: 147,
- crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- cu: 0.12,
- energy: 65,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 2.22,
- folate: 338,
- genetically_engineered: null,
- k: 454,
- lifecycle: 'ANNUAL',
- lipid: 0.2,
- mg: 25,
- mn: 0.17,
- na: 26,
- niacin: 1.69,
- nutrient_credits: null,
- organic: null,
- ph: 98,
- protein: 4.24,
- riboflavin: 0.06,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.14,
- treated: null,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.27,
- vitc: 1.9,
- zn: 0.63,
- },
- },
- {
- ca: null,
- crop_common_name: 'Alfalfa for fodder',
- crop_genus: 'Medicago',
- crop_group: 'Other crops',
- crop_id: 142,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- crop_specie: 'sativa ',
- crop_subgroup: 'Grasses and other fodder crops',
- crop_translation_key: 'ALFALFA_FOR_FODDER',
- cu: null,
- depletion_fraction: 0.55,
- end_kc: 0.85,
- energy: null,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: null,
- fl: null,
- folate: null,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: null,
- lipid: null,
- max_height: null,
- max_rooting_depth: 2,
- mg: null,
- mid_kc: 0.85,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: null,
- ph: null,
- protein: null,
- refuse: null,
- reviewed: true,
- riboflavin: null,
- se: null,
- thiamin: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- vite: null,
- vitk: null,
- zn: null,
- compliance_file_url: null,
- crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 135,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: null,
- crop_common_name: 'Alfalfa for fodder',
- crop_genus: 'Medicago',
- crop_group: 'Other crops',
- crop_id: 142,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- crop_specie: 'sativa ',
- crop_subgroup: 'Grasses and other fodder crops',
- crop_translation_key: 'ALFALFA_FOR_FODDER',
- cu: null,
- depletion_fraction: 0.55,
- end_kc: 0.85,
- energy: null,
- farm_id: null,
- fe: null,
- fl: null,
- folate: null,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: null,
- lipid: null,
- max_height: null,
- max_rooting_depth: 2,
- mg: null,
- mid_kc: 0.85,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: null,
- ph: null,
- protein: null,
- refuse: null,
- reviewed: true,
- riboflavin: null,
- se: null,
- thiamin: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- vite: null,
- vitk: null,
- zn: null,
- },
- crop_variety: {
- ca: null,
- compliance_file_url: null,
- crop_id: 142,
- crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- cu: null,
- energy: null,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: null,
- folate: null,
- genetically_engineered: null,
- k: null,
- lifecycle: 'ANNUAL',
- lipid: null,
- mg: null,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- organic: null,
- ph: null,
- protein: null,
- riboflavin: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: null,
- treated: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- zn: null,
- },
- },
- {
- ca: 60,
- crop_common_name: 'Salsify',
- crop_genus: 'Tragopogon',
- crop_group: 'Vegetables and melons',
- crop_id: 167,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'porrifolius ',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- crop_translation_key: 'SALSIFY',
- cu: 0.09,
- depletion_fraction: 0.308333,
- end_kc: 0.866667,
- energy: 82,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.7,
- fl: null,
- folate: 26,
- initial_kc: 0.725,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 380,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.525,
- mg: 23,
- mid_kc: 1.01667,
- mn: 0.27,
- na: 20,
- niacin: 0.5,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 13,
- ph: 75,
- protein: 3.3,
- refuse: null,
- reviewed: true,
- riboflavin: 0.22,
- se: null,
- thiamin: 0.08,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.28,
- vitc: 8,
- vite: null,
- vitk: null,
- zn: 0.38,
- compliance_file_url: null,
- crop_variety_id: '19336a12-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 158154,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 158154,
- estimated_revenue: 158154,
- management_plan_id: 134,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 60,
- crop_common_name: 'Salsify',
- crop_genus: 'Tragopogon',
- crop_group: 'Vegetables and melons',
- crop_id: 167,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'porrifolius ',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- crop_translation_key: 'SALSIFY',
- cu: 0.089,
- depletion_fraction: 0.308333,
- end_kc: 0.866667,
- energy: 82,
- farm_id: null,
- fe: 0.7,
- fl: null,
- folate: 26,
- initial_kc: 0.725,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 380,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.525,
- mg: 23,
- mid_kc: 1.01667,
- mn: 0.268,
- na: 20,
- niacin: 0.5,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 13,
- ph: 75,
- protein: 3.3,
- refuse: null,
- reviewed: true,
- riboflavin: 0.22,
- se: null,
- thiamin: 0.08,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.277,
- vitc: 8,
- vite: null,
- vitk: null,
- zn: 0.38,
- },
- crop_variety: {
- ca: 60,
- compliance_file_url: null,
- crop_id: 167,
- crop_variety_id: '19336a12-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- cu: 0.09,
- energy: 82,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.7,
- folate: 26,
- genetically_engineered: null,
- k: 380,
- lifecycle: 'ANNUAL',
- lipid: 0.2,
- mg: 23,
- mn: 0.27,
- na: 20,
- niacin: 0.5,
- nutrient_credits: null,
- organic: null,
- ph: 75,
- protein: 3.3,
- riboflavin: 0.22,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.08,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.28,
- vitc: 8,
- zn: 0.38,
- },
- },
- {
- ca: 14,
- crop_common_name: 'Black pepper',
- crop_genus: 'Piper',
- crop_group: 'Beverage and spice crops',
- crop_id: 82,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- crop_specie: 'nigrum ',
- crop_subgroup: 'Permanent spice crops',
- crop_translation_key: 'BLACK_PEPPER',
- cu: 0.09,
- depletion_fraction: 0.4,
- end_kc: 0.99,
- energy: 27,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.46,
- fl: null,
- folate: 29,
- initial_kc: 0.75,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 256,
- lipid: 0.45,
- max_height: null,
- max_rooting_depth: 0.99,
- mg: 17,
- mid_kc: 1.04,
- mn: 0.1,
- na: 13,
- niacin: 1.24,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 18,
- ph: 32,
- protein: 1.66,
- refuse: null,
- reviewed: true,
- riboflavin: 0.05,
- se: null,
- thiamin: 0.08,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.36,
- vitc: 82.7,
- vite: null,
- vitk: null,
- zn: 0.25,
- compliance_file_url: null,
- crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2020-05-14T07:00:00.000Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 144,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2020-04-14T07:00:00.000Z',
- crop: {
- ca: 14,
- crop_common_name: 'Black pepper',
- crop_genus: 'Piper',
- crop_group: 'Beverage and spice crops',
- crop_id: 82,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- crop_specie: 'nigrum ',
- crop_subgroup: 'Permanent spice crops',
- crop_translation_key: 'BLACK_PEPPER',
- cu: 0.094,
- depletion_fraction: 0.4,
- end_kc: 0.99,
- energy: 27,
- farm_id: null,
- fe: 0.46,
- fl: null,
- folate: 29,
- initial_kc: 0.75,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 256,
- lipid: 0.45,
- max_height: null,
- max_rooting_depth: 0.99,
- mg: 17,
- mid_kc: 1.04,
- mn: 0.1,
- na: 13,
- niacin: 1.242,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 18,
- ph: 32,
- protein: 1.66,
- refuse: null,
- reviewed: true,
- riboflavin: 0.054,
- se: null,
- thiamin: 0.081,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.357,
- vitc: 82.7,
- vite: null,
- vitk: null,
- zn: 0.25,
- },
- crop_variety: {
- ca: 14,
- compliance_file_url: null,
- crop_id: 82,
- crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
- cu: 0.09,
- energy: 27,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.46,
- folate: 29,
- genetically_engineered: null,
- k: 256,
- lifecycle: 'ANNUAL',
- lipid: 0.45,
- mg: 17,
- mn: 0.1,
- na: 13,
- niacin: 1.24,
- nutrient_credits: null,
- organic: null,
- ph: 32,
- protein: 1.66,
- riboflavin: 0.05,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.08,
- treated: null,
- vita_rae: 17,
- vitb12: 0,
- vitb6: 0.36,
- vitc: 82.7,
- zn: 0.25,
- },
- },
- {
- ca: 13,
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 31,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- crop_specie: 'armeniaca ',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APRICOT',
- cu: 0.08,
- depletion_fraction: 0.5,
- end_kc: 0.6518,
- energy: 48,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.39,
- fl: null,
- folate: 9,
- initial_kc: 0.55,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 259,
- lipid: 0.39,
- max_height: 3,
- max_rooting_depth: 1.5,
- mg: 10,
- mid_kc: 0.9,
- mn: 0.08,
- na: 1,
- niacin: 0.6,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 7,
- ph: 23,
- protein: 1.4,
- refuse: null,
- reviewed: true,
- riboflavin: 0.04,
- se: null,
- thiamin: 0.03,
- vita_rae: 96,
- vitb12: 0,
- vitb6: 0.05,
- vitc: 10,
- vite: null,
- vitk: null,
- zn: 0.2,
- compliance_file_url: null,
- crop_variety_id: '19336a27-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 139,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 13,
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 31,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- crop_specie: 'armeniaca ',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APRICOT',
- cu: 0.078,
- depletion_fraction: 0.5,
- end_kc: 0.6518,
- energy: 48,
- farm_id: null,
- fe: 0.39,
- fl: null,
- folate: 9,
- initial_kc: 0.55,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 259,
- lipid: 0.39,
- max_height: 3,
- max_rooting_depth: 1.5,
- mg: 10,
- mid_kc: 0.9,
- mn: 0.077,
- na: 1,
- niacin: 0.6,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 7,
- ph: 23,
- protein: 1.4,
- refuse: null,
- reviewed: true,
- riboflavin: 0.04,
- se: null,
- thiamin: 0.03,
- vita_rae: 96,
- vitb12: 0,
- vitb6: 0.054,
- vitc: 10,
- vite: null,
- vitk: null,
- zn: 0.2,
- },
- crop_variety: {
- ca: 13,
- compliance_file_url: null,
- crop_id: 31,
- crop_variety_id: '19336a27-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- cu: 0.08,
- energy: 48,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.39,
- folate: 9,
- genetically_engineered: null,
- k: 259,
- lifecycle: 'ANNUAL',
- lipid: 0.39,
- mg: 10,
- mn: 0.08,
- na: 1,
- niacin: 0.6,
- nutrient_credits: null,
- organic: null,
- ph: 23,
- protein: 1.4,
- riboflavin: 0.04,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.03,
- treated: null,
- vita_rae: 96,
- vitb12: 0,
- vitb6: 0.05,
- vitc: 10,
- zn: 0.2,
- },
- },
- {
- ca: 6,
- crop_common_name: 'Apple',
- crop_genus: 'Malus',
- crop_group: 'Fruit and nuts',
- crop_id: 25,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
- crop_specie: 'sylvestris ',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APPLE',
- cu: 0.03,
- depletion_fraction: 0.5,
- end_kc: 0.3,
- energy: 52,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.12,
- fl: null,
- folate: 3,
- initial_kc: 0.5,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 107,
- lipid: 0.17,
- max_height: 0.8,
- max_rooting_depth: 0.45,
- mg: 5,
- mid_kc: 0.3,
- mn: 0.04,
- na: 1,
- niacin: 0.09,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 10,
- ph: 11,
- protein: 0.26,
- refuse: null,
- reviewed: true,
- riboflavin: 0.03,
- se: null,
- thiamin: 0.02,
- vita_rae: 3,
- vitb12: 0,
- vitb6: 0.04,
- vitc: 4.6,
- vite: null,
- vitk: null,
- zn: 0.04,
- compliance_file_url: null,
- crop_variety_id: '19336a11-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 138,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 6,
- crop_common_name: 'Apple',
- crop_genus: 'Malus',
- crop_group: 'Fruit and nuts',
- crop_id: 25,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
- crop_specie: 'sylvestris ',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APPLE',
- cu: 0.027,
- depletion_fraction: 0.5,
- end_kc: 0.3,
- energy: 52,
- farm_id: null,
- fe: 0.12,
- fl: null,
- folate: 3,
- initial_kc: 0.5,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 107,
- lipid: 0.17,
- max_height: 0.8,
- max_rooting_depth: 0.45,
- mg: 5,
- mid_kc: 0.3,
- mn: 0.035,
- na: 1,
- niacin: 0.091,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 10,
- ph: 11,
- protein: 0.26,
- refuse: null,
- reviewed: true,
- riboflavin: 0.026,
- se: null,
- thiamin: 0.017,
- vita_rae: 3,
- vitb12: 0,
- vitb6: 0.041,
- vitc: 4.6,
- vite: null,
- vitk: null,
- zn: 0.04,
- },
- crop_variety: {
- ca: 6,
- compliance_file_url: null,
- crop_id: 25,
- crop_variety_id: '19336a11-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
- cu: 0.03,
- energy: 52,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 0.12,
- folate: 3,
- genetically_engineered: null,
- k: 107,
- lifecycle: 'ANNUAL',
- lipid: 0.17,
- mg: 5,
- mn: 0.04,
- na: 1,
- niacin: 0.09,
- nutrient_credits: null,
- organic: null,
- ph: 11,
- protein: 0.26,
- riboflavin: 0.03,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.02,
- treated: null,
- vita_rae: 3,
- vitb12: 0,
- vitb6: 0.04,
- vitc: 4.6,
- zn: 0.04,
- },
- },
- {
- ca: 646,
- crop_common_name: 'Anise seeds',
- crop_genus: 'Pimpinella',
- crop_group: 'Beverage and spice crops',
- crop_id: 81,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
- crop_specie: 'anisum ',
- crop_subgroup: 'Temporary spice crops',
- crop_translation_key: 'ANISE_SEEDS',
- cu: 0.91,
- depletion_fraction: 0.4,
- end_kc: 1.1,
- energy: 337,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 36.96,
- fl: null,
- folate: 10,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 1441,
- lipid: 15.9,
- max_height: null,
- max_rooting_depth: 0.6,
- mg: 170,
- mid_kc: 1.15,
- mn: 2.3,
- na: 16,
- niacin: 3.06,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 440,
- protein: 17.6,
- refuse: null,
- reviewed: true,
- riboflavin: 0.29,
- se: null,
- thiamin: 0.34,
- vita_rae: 16,
- vitb12: 0,
- vitb6: 0.65,
- vitc: 21,
- vite: null,
- vitk: null,
- zn: 5.3,
- compliance_file_url: null,
- crop_variety_id: '19336a21-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 137,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 646,
- crop_common_name: 'Anise seeds',
- crop_genus: 'Pimpinella',
- crop_group: 'Beverage and spice crops',
- crop_id: 81,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
- crop_specie: 'anisum ',
- crop_subgroup: 'Temporary spice crops',
- crop_translation_key: 'ANISE_SEEDS',
- cu: 0.91,
- depletion_fraction: 0.4,
- end_kc: 1.1,
- energy: 337,
- farm_id: null,
- fe: 36.96,
- fl: null,
- folate: 10,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 1441,
- lipid: 15.9,
- max_height: null,
- max_rooting_depth: 0.6,
- mg: 170,
- mid_kc: 1.15,
- mn: 2.3,
- na: 16,
- niacin: 3.06,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 440,
- protein: 17.6,
- refuse: null,
- reviewed: true,
- riboflavin: 0.29,
- se: null,
- thiamin: 0.34,
- vita_rae: 16,
- vitb12: 0,
- vitb6: 0.65,
- vitc: 21,
- vite: null,
- vitk: null,
- zn: 5.3,
- },
- crop_variety: {
- ca: 646,
- compliance_file_url: null,
- crop_id: 81,
- crop_variety_id: '19336a21-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
- cu: 0.91,
- energy: 337,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 36.96,
- folate: 10,
- genetically_engineered: null,
- k: 1441,
- lifecycle: 'ANNUAL',
- lipid: 15.9,
- mg: 170,
- mn: 2.3,
- na: 16,
- niacin: 3.06,
- nutrient_credits: null,
- organic: null,
- ph: 440,
- protein: 17.6,
- riboflavin: 0.29,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.34,
- treated: null,
- vita_rae: 16,
- vitb12: 0,
- vitb6: 0.65,
- vitc: 21,
- zn: 5.3,
- },
- },
- {
- ca: null,
- crop_common_name: 'Alfalfa for fodder',
- crop_genus: 'Medicago',
- crop_group: 'Other crops',
- crop_id: 142,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- crop_specie: 'sativa ',
- crop_subgroup: 'Grasses and other fodder crops',
- crop_translation_key: 'ALFALFA_FOR_FODDER',
- cu: null,
- depletion_fraction: 0.55,
- end_kc: 0.85,
- energy: null,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: null,
- fl: null,
- folate: null,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: null,
- lipid: null,
- max_height: null,
- max_rooting_depth: 2,
- mg: null,
- mid_kc: 0.85,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: null,
- ph: null,
- protein: null,
- refuse: null,
- reviewed: true,
- riboflavin: null,
- se: null,
- thiamin: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- vite: null,
- vitk: null,
- zn: null,
- compliance_file_url: null,
- crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 136,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-13T07:00:00.000Z',
- crop: {
- ca: null,
- crop_common_name: 'Alfalfa for fodder',
- crop_genus: 'Medicago',
- crop_group: 'Other crops',
- crop_id: 142,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- crop_specie: 'sativa ',
- crop_subgroup: 'Grasses and other fodder crops',
- crop_translation_key: 'ALFALFA_FOR_FODDER',
- cu: null,
- depletion_fraction: 0.55,
- end_kc: 0.85,
- energy: null,
- farm_id: null,
- fe: null,
- fl: null,
- folate: null,
- initial_kc: 0.6,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: null,
- lipid: null,
- max_height: null,
- max_rooting_depth: 2,
- mg: null,
- mid_kc: 0.85,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: null,
- ph: null,
- protein: null,
- refuse: null,
- reviewed: true,
- riboflavin: null,
- se: null,
- thiamin: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- vite: null,
- vitk: null,
- zn: null,
- },
- crop_variety: {
- ca: null,
- compliance_file_url: null,
- crop_id: 142,
- crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
- cu: null,
- energy: null,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: null,
- folate: null,
- genetically_engineered: null,
- k: null,
- lifecycle: 'ANNUAL',
- lipid: null,
- mg: null,
- mn: null,
- na: null,
- niacin: null,
- nutrient_credits: 200,
- organic: null,
- ph: null,
- protein: null,
- riboflavin: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: null,
- treated: null,
- vita_rae: null,
- vitb12: null,
- vitb6: null,
- vitc: null,
- zn: null,
- },
- },
- {
- ca: 6,
- crop_common_name: 'Arrowroot',
- crop_genus: 'Maranta',
- crop_group: 'Potatoes and yams',
- crop_id: 147,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'arundinacea ',
- crop_subgroup: 'High starch Root/tuber crops',
- crop_translation_key: 'ARROWROOT',
- cu: 0.12,
- depletion_fraction: 0.36,
- end_kc: 0.602667,
- energy: 65,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 2.22,
- fl: null,
- folate: 338,
- initial_kc: 0.433333,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 454,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.583333,
- mg: 25,
- mid_kc: 1.03433,
- mn: 0.17,
- na: 26,
- niacin: 1.69,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 15,
- ph: 98,
- protein: 4.24,
- refuse: null,
- reviewed: true,
- riboflavin: 0.06,
- se: null,
- thiamin: 0.14,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.27,
- vitc: 1.9,
- vite: null,
- vitk: null,
- zn: 0.63,
- compliance_file_url: null,
- crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- genetically_engineered: null,
- lifecycle: 'ANNUAL',
- organic: null,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- treated: null,
- location: {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- area_used: 1582,
- bed_config: null,
- harvest_date: '2021-05-14T17:10:00.144Z',
- estimated_production: 1582,
- estimated_revenue: 1582,
- management_plan_id: 140,
- is_by_bed: false,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- crop: {
- ca: 6,
- crop_common_name: 'Arrowroot',
- crop_genus: 'Maranta',
- crop_group: 'Potatoes and yams',
- crop_id: 147,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- crop_specie: 'arundinacea ',
- crop_subgroup: 'High starch Root/tuber crops',
- crop_translation_key: 'ARROWROOT',
- cu: 0.121,
- depletion_fraction: 0.36,
- end_kc: 0.602667,
- energy: 65,
- farm_id: null,
- fe: 2.22,
- fl: null,
- folate: 338,
- initial_kc: 0.433333,
- is_avg_depth: true,
- is_avg_kc: true,
- is_avg_nutrient: false,
- k: 454,
- lipid: 0.2,
- max_height: null,
- max_rooting_depth: 0.583333,
- mg: 25,
- mid_kc: 1.03433,
- mn: 0.174,
- na: 26,
- niacin: 1.693,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 15,
- ph: 98,
- protein: 4.24,
- refuse: null,
- reviewed: true,
- riboflavin: 0.059,
- se: null,
- thiamin: 0.143,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.266,
- vitc: 1.9,
- vite: null,
- vitk: null,
- zn: 0.63,
- },
- crop_variety: {
- ca: 6,
- compliance_file_url: null,
- crop_id: 147,
- crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
- crop_variety_name: '',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
- cu: 0.12,
- energy: 65,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- fe: 2.22,
- folate: 338,
- genetically_engineered: null,
- k: 454,
- lifecycle: 'ANNUAL',
- lipid: 0.2,
- mg: 25,
- mn: 0.17,
- na: 26,
- niacin: 1.69,
- nutrient_credits: null,
- organic: null,
- ph: 98,
- protein: 4.24,
- riboflavin: 0.06,
- searched: null,
- seeding_type: 'SEED',
- supplier: null,
- thiamin: 0.14,
- treated: null,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.27,
- vitc: 1.9,
- zn: 0.63,
- },
- },
-];
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- activeCrops: crops,
- pastCrops: crops,
- plannedCrops: crops.slice(2, 5),
- isAdmin: true,
- match: {
- url: '/field/3da7abb4-9d44-11eb-bbf7-1bc17302df43/crops',
- params: { location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43' },
- },
- history: { location: { pathname: '/field/3da7abb4-9d44-11eb-bbf7-1bc17302df43/crops' } },
-};
diff --git a/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.jsx b/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.jsx
new file mode 100644
index 0000000000..097efa8fb4
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/CropListPage/CropListPage.stories.jsx
@@ -0,0 +1,2143 @@
+import React from 'react';
+import PureCropList from '../../../components/CropListPage';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Page/CropList',
+ component: PureCropList,
+ decorators: decorator,
+};
+
+const crops = [
+ {
+ ca: 14,
+ crop_common_name: 'Black pepper',
+ crop_genus: 'Piper',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 82,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ crop_specie: 'nigrum ',
+ crop_subgroup: 'Permanent spice crops',
+ crop_translation_key: 'BLACK_PEPPER',
+ cu: 0.09,
+ depletion_fraction: 0.4,
+ end_kc: 0.99,
+ energy: 27,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.46,
+ fl: null,
+ folate: 29,
+ initial_kc: 0.75,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 256,
+ lipid: 0.45,
+ max_height: null,
+ max_rooting_depth: 0.99,
+ mg: 17,
+ mid_kc: 1.04,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.24,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 18,
+ ph: 32,
+ protein: 1.66,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.05,
+ se: null,
+ thiamin: 0.08,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.36,
+ vitc: 82.7,
+ vite: null,
+ vitk: null,
+ zn: 0.25,
+ compliance_file_url: null,
+ crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 143,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 14,
+ crop_common_name: 'Black pepper',
+ crop_genus: 'Piper',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 82,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ crop_specie: 'nigrum ',
+ crop_subgroup: 'Permanent spice crops',
+ crop_translation_key: 'BLACK_PEPPER',
+ cu: 0.094,
+ depletion_fraction: 0.4,
+ end_kc: 0.99,
+ energy: 27,
+ farm_id: null,
+ fe: 0.46,
+ fl: null,
+ folate: 29,
+ initial_kc: 0.75,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 256,
+ lipid: 0.45,
+ max_height: null,
+ max_rooting_depth: 0.99,
+ mg: 17,
+ mid_kc: 1.04,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.242,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 18,
+ ph: 32,
+ protein: 1.66,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.054,
+ se: null,
+ thiamin: 0.081,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.357,
+ vitc: 82.7,
+ vite: null,
+ vitk: null,
+ zn: 0.25,
+ },
+ crop_variety: {
+ ca: 14,
+ compliance_file_url: null,
+ crop_id: 82,
+ crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ cu: 0.09,
+ energy: 27,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.46,
+ folate: 29,
+ genetically_engineered: null,
+ k: 256,
+ lifecycle: 'ANNUAL',
+ lipid: 0.45,
+ mg: 17,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.24,
+ nutrient_credits: null,
+ organic: null,
+ ph: 32,
+ protein: 1.66,
+ riboflavin: 0.05,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.08,
+ treated: null,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.36,
+ vitc: 82.7,
+ zn: 0.25,
+ },
+ },
+ {
+ ca: 44,
+ crop_common_name: 'Artichoke',
+ crop_genus: 'Cynara',
+ crop_group: 'Vegetables and melons',
+ crop_id: 66,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
+ crop_specie: 'scolymus ',
+ crop_subgroup: 'Leafy or stem vegetables',
+ crop_translation_key: 'ARTICHOKE',
+ cu: 0.23,
+ depletion_fraction: 0.45,
+ end_kc: 0.95,
+ energy: 47,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 1.28,
+ fl: null,
+ folate: 68,
+ initial_kc: 0.5,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 370,
+ lipid: 0.15,
+ max_height: 0.7,
+ max_rooting_depth: 0.75,
+ mg: 60,
+ mid_kc: 1,
+ mn: 0.26,
+ na: 94,
+ niacin: 1.05,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 90,
+ protein: 3.27,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.07,
+ se: null,
+ thiamin: 0.07,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.12,
+ vitc: 11.7,
+ vite: null,
+ vitk: null,
+ zn: 0.49,
+ compliance_file_url: null,
+ crop_variety_id: '19336a35-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 142,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 44,
+ crop_common_name: 'Artichoke',
+ crop_genus: 'Cynara',
+ crop_group: 'Vegetables and melons',
+ crop_id: 66,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
+ crop_specie: 'scolymus ',
+ crop_subgroup: 'Leafy or stem vegetables',
+ crop_translation_key: 'ARTICHOKE',
+ cu: 0.231,
+ depletion_fraction: 0.45,
+ end_kc: 0.95,
+ energy: 47,
+ farm_id: null,
+ fe: 1.28,
+ fl: null,
+ folate: 68,
+ initial_kc: 0.5,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 370,
+ lipid: 0.15,
+ max_height: 0.7,
+ max_rooting_depth: 0.75,
+ mg: 60,
+ mid_kc: 1,
+ mn: 0.256,
+ na: 94,
+ niacin: 1.046,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 90,
+ protein: 3.27,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.066,
+ se: null,
+ thiamin: 0.072,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.116,
+ vitc: 11.7,
+ vite: null,
+ vitk: null,
+ zn: 0.49,
+ },
+ crop_variety: {
+ ca: 44,
+ compliance_file_url: null,
+ crop_id: 66,
+ crop_variety_id: '19336a35-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/artichoke.webp',
+ cu: 0.23,
+ energy: 47,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 1.28,
+ folate: 68,
+ genetically_engineered: null,
+ k: 370,
+ lifecycle: 'ANNUAL',
+ lipid: 0.15,
+ mg: 60,
+ mn: 0.26,
+ na: 94,
+ niacin: 1.05,
+ nutrient_credits: null,
+ organic: null,
+ ph: 90,
+ protein: 3.27,
+ riboflavin: 0.07,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.07,
+ treated: null,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.12,
+ vitc: 11.7,
+ zn: 0.49,
+ },
+ },
+ {
+ ca: 6,
+ crop_common_name: 'Arrowroot',
+ crop_genus: 'Maranta',
+ crop_group: 'Potatoes and yams',
+ crop_id: 147,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'arundinacea ',
+ crop_subgroup: 'High starch Root/tuber crops',
+ crop_translation_key: 'ARROWROOT',
+ cu: 0.12,
+ depletion_fraction: 0.36,
+ end_kc: 0.602667,
+ energy: 65,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 2.22,
+ fl: null,
+ folate: 338,
+ initial_kc: 0.433333,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 454,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.583333,
+ mg: 25,
+ mid_kc: 1.03433,
+ mn: 0.17,
+ na: 26,
+ niacin: 1.69,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 15,
+ ph: 98,
+ protein: 4.24,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.06,
+ se: null,
+ thiamin: 0.14,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.27,
+ vitc: 1.9,
+ vite: null,
+ vitk: null,
+ zn: 0.63,
+ compliance_file_url: null,
+ crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 141,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 6,
+ crop_common_name: 'Arrowroot',
+ crop_genus: 'Maranta',
+ crop_group: 'Potatoes and yams',
+ crop_id: 147,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'arundinacea ',
+ crop_subgroup: 'High starch Root/tuber crops',
+ crop_translation_key: 'ARROWROOT',
+ cu: 0.121,
+ depletion_fraction: 0.36,
+ end_kc: 0.602667,
+ energy: 65,
+ farm_id: null,
+ fe: 2.22,
+ fl: null,
+ folate: 338,
+ initial_kc: 0.433333,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 454,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.583333,
+ mg: 25,
+ mid_kc: 1.03433,
+ mn: 0.174,
+ na: 26,
+ niacin: 1.693,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 15,
+ ph: 98,
+ protein: 4.24,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.059,
+ se: null,
+ thiamin: 0.143,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.266,
+ vitc: 1.9,
+ vite: null,
+ vitk: null,
+ zn: 0.63,
+ },
+ crop_variety: {
+ ca: 6,
+ compliance_file_url: null,
+ crop_id: 147,
+ crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ cu: 0.12,
+ energy: 65,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 2.22,
+ folate: 338,
+ genetically_engineered: null,
+ k: 454,
+ lifecycle: 'ANNUAL',
+ lipid: 0.2,
+ mg: 25,
+ mn: 0.17,
+ na: 26,
+ niacin: 1.69,
+ nutrient_credits: null,
+ organic: null,
+ ph: 98,
+ protein: 4.24,
+ riboflavin: 0.06,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.14,
+ treated: null,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.27,
+ vitc: 1.9,
+ zn: 0.63,
+ },
+ },
+ {
+ ca: null,
+ crop_common_name: 'Alfalfa for fodder',
+ crop_genus: 'Medicago',
+ crop_group: 'Other crops',
+ crop_id: 142,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ crop_specie: 'sativa ',
+ crop_subgroup: 'Grasses and other fodder crops',
+ crop_translation_key: 'ALFALFA_FOR_FODDER',
+ cu: null,
+ depletion_fraction: 0.55,
+ end_kc: 0.85,
+ energy: null,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: null,
+ fl: null,
+ folate: null,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: null,
+ lipid: null,
+ max_height: null,
+ max_rooting_depth: 2,
+ mg: null,
+ mid_kc: 0.85,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: null,
+ ph: null,
+ protein: null,
+ refuse: null,
+ reviewed: true,
+ riboflavin: null,
+ se: null,
+ thiamin: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ vite: null,
+ vitk: null,
+ zn: null,
+ compliance_file_url: null,
+ crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 135,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: null,
+ crop_common_name: 'Alfalfa for fodder',
+ crop_genus: 'Medicago',
+ crop_group: 'Other crops',
+ crop_id: 142,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ crop_specie: 'sativa ',
+ crop_subgroup: 'Grasses and other fodder crops',
+ crop_translation_key: 'ALFALFA_FOR_FODDER',
+ cu: null,
+ depletion_fraction: 0.55,
+ end_kc: 0.85,
+ energy: null,
+ farm_id: null,
+ fe: null,
+ fl: null,
+ folate: null,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: null,
+ lipid: null,
+ max_height: null,
+ max_rooting_depth: 2,
+ mg: null,
+ mid_kc: 0.85,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: null,
+ ph: null,
+ protein: null,
+ refuse: null,
+ reviewed: true,
+ riboflavin: null,
+ se: null,
+ thiamin: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ vite: null,
+ vitk: null,
+ zn: null,
+ },
+ crop_variety: {
+ ca: null,
+ compliance_file_url: null,
+ crop_id: 142,
+ crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ cu: null,
+ energy: null,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: null,
+ folate: null,
+ genetically_engineered: null,
+ k: null,
+ lifecycle: 'ANNUAL',
+ lipid: null,
+ mg: null,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ organic: null,
+ ph: null,
+ protein: null,
+ riboflavin: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: null,
+ treated: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ zn: null,
+ },
+ },
+ {
+ ca: 60,
+ crop_common_name: 'Salsify',
+ crop_genus: 'Tragopogon',
+ crop_group: 'Vegetables and melons',
+ crop_id: 167,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'porrifolius ',
+ crop_subgroup: 'Root, bulb, or tuberous vegetables',
+ crop_translation_key: 'SALSIFY',
+ cu: 0.09,
+ depletion_fraction: 0.308333,
+ end_kc: 0.866667,
+ energy: 82,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.7,
+ fl: null,
+ folate: 26,
+ initial_kc: 0.725,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 380,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.525,
+ mg: 23,
+ mid_kc: 1.01667,
+ mn: 0.27,
+ na: 20,
+ niacin: 0.5,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 13,
+ ph: 75,
+ protein: 3.3,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.22,
+ se: null,
+ thiamin: 0.08,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.28,
+ vitc: 8,
+ vite: null,
+ vitk: null,
+ zn: 0.38,
+ compliance_file_url: null,
+ crop_variety_id: '19336a12-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 158154,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 158154,
+ estimated_revenue: 158154,
+ management_plan_id: 134,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 60,
+ crop_common_name: 'Salsify',
+ crop_genus: 'Tragopogon',
+ crop_group: 'Vegetables and melons',
+ crop_id: 167,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'porrifolius ',
+ crop_subgroup: 'Root, bulb, or tuberous vegetables',
+ crop_translation_key: 'SALSIFY',
+ cu: 0.089,
+ depletion_fraction: 0.308333,
+ end_kc: 0.866667,
+ energy: 82,
+ farm_id: null,
+ fe: 0.7,
+ fl: null,
+ folate: 26,
+ initial_kc: 0.725,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 380,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.525,
+ mg: 23,
+ mid_kc: 1.01667,
+ mn: 0.268,
+ na: 20,
+ niacin: 0.5,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 13,
+ ph: 75,
+ protein: 3.3,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.22,
+ se: null,
+ thiamin: 0.08,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.277,
+ vitc: 8,
+ vite: null,
+ vitk: null,
+ zn: 0.38,
+ },
+ crop_variety: {
+ ca: 60,
+ compliance_file_url: null,
+ crop_id: 167,
+ crop_variety_id: '19336a12-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ cu: 0.09,
+ energy: 82,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.7,
+ folate: 26,
+ genetically_engineered: null,
+ k: 380,
+ lifecycle: 'ANNUAL',
+ lipid: 0.2,
+ mg: 23,
+ mn: 0.27,
+ na: 20,
+ niacin: 0.5,
+ nutrient_credits: null,
+ organic: null,
+ ph: 75,
+ protein: 3.3,
+ riboflavin: 0.22,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.08,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.28,
+ vitc: 8,
+ zn: 0.38,
+ },
+ },
+ {
+ ca: 14,
+ crop_common_name: 'Black pepper',
+ crop_genus: 'Piper',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 82,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ crop_specie: 'nigrum ',
+ crop_subgroup: 'Permanent spice crops',
+ crop_translation_key: 'BLACK_PEPPER',
+ cu: 0.09,
+ depletion_fraction: 0.4,
+ end_kc: 0.99,
+ energy: 27,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.46,
+ fl: null,
+ folate: 29,
+ initial_kc: 0.75,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 256,
+ lipid: 0.45,
+ max_height: null,
+ max_rooting_depth: 0.99,
+ mg: 17,
+ mid_kc: 1.04,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.24,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 18,
+ ph: 32,
+ protein: 1.66,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.05,
+ se: null,
+ thiamin: 0.08,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.36,
+ vitc: 82.7,
+ vite: null,
+ vitk: null,
+ zn: 0.25,
+ compliance_file_url: null,
+ crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2020-05-14T07:00:00.000Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 144,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2020-04-14T07:00:00.000Z',
+ crop: {
+ ca: 14,
+ crop_common_name: 'Black pepper',
+ crop_genus: 'Piper',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 82,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ crop_specie: 'nigrum ',
+ crop_subgroup: 'Permanent spice crops',
+ crop_translation_key: 'BLACK_PEPPER',
+ cu: 0.094,
+ depletion_fraction: 0.4,
+ end_kc: 0.99,
+ energy: 27,
+ farm_id: null,
+ fe: 0.46,
+ fl: null,
+ folate: 29,
+ initial_kc: 0.75,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 256,
+ lipid: 0.45,
+ max_height: null,
+ max_rooting_depth: 0.99,
+ mg: 17,
+ mid_kc: 1.04,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.242,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 18,
+ ph: 32,
+ protein: 1.66,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.054,
+ se: null,
+ thiamin: 0.081,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.357,
+ vitc: 82.7,
+ vite: null,
+ vitk: null,
+ zn: 0.25,
+ },
+ crop_variety: {
+ ca: 14,
+ compliance_file_url: null,
+ crop_id: 82,
+ crop_variety_id: '19336a15-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/black_pepper.webp',
+ cu: 0.09,
+ energy: 27,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.46,
+ folate: 29,
+ genetically_engineered: null,
+ k: 256,
+ lifecycle: 'ANNUAL',
+ lipid: 0.45,
+ mg: 17,
+ mn: 0.1,
+ na: 13,
+ niacin: 1.24,
+ nutrient_credits: null,
+ organic: null,
+ ph: 32,
+ protein: 1.66,
+ riboflavin: 0.05,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.08,
+ treated: null,
+ vita_rae: 17,
+ vitb12: 0,
+ vitb6: 0.36,
+ vitc: 82.7,
+ zn: 0.25,
+ },
+ },
+ {
+ ca: 13,
+ crop_common_name: 'Apricot',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 31,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ crop_specie: 'armeniaca ',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APRICOT',
+ cu: 0.08,
+ depletion_fraction: 0.5,
+ end_kc: 0.6518,
+ energy: 48,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.39,
+ fl: null,
+ folate: 9,
+ initial_kc: 0.55,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 259,
+ lipid: 0.39,
+ max_height: 3,
+ max_rooting_depth: 1.5,
+ mg: 10,
+ mid_kc: 0.9,
+ mn: 0.08,
+ na: 1,
+ niacin: 0.6,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 7,
+ ph: 23,
+ protein: 1.4,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.04,
+ se: null,
+ thiamin: 0.03,
+ vita_rae: 96,
+ vitb12: 0,
+ vitb6: 0.05,
+ vitc: 10,
+ vite: null,
+ vitk: null,
+ zn: 0.2,
+ compliance_file_url: null,
+ crop_variety_id: '19336a27-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 139,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 13,
+ crop_common_name: 'Apricot',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 31,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ crop_specie: 'armeniaca ',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APRICOT',
+ cu: 0.078,
+ depletion_fraction: 0.5,
+ end_kc: 0.6518,
+ energy: 48,
+ farm_id: null,
+ fe: 0.39,
+ fl: null,
+ folate: 9,
+ initial_kc: 0.55,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 259,
+ lipid: 0.39,
+ max_height: 3,
+ max_rooting_depth: 1.5,
+ mg: 10,
+ mid_kc: 0.9,
+ mn: 0.077,
+ na: 1,
+ niacin: 0.6,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 7,
+ ph: 23,
+ protein: 1.4,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.04,
+ se: null,
+ thiamin: 0.03,
+ vita_rae: 96,
+ vitb12: 0,
+ vitb6: 0.054,
+ vitc: 10,
+ vite: null,
+ vitk: null,
+ zn: 0.2,
+ },
+ crop_variety: {
+ ca: 13,
+ compliance_file_url: null,
+ crop_id: 31,
+ crop_variety_id: '19336a27-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ cu: 0.08,
+ energy: 48,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.39,
+ folate: 9,
+ genetically_engineered: null,
+ k: 259,
+ lifecycle: 'ANNUAL',
+ lipid: 0.39,
+ mg: 10,
+ mn: 0.08,
+ na: 1,
+ niacin: 0.6,
+ nutrient_credits: null,
+ organic: null,
+ ph: 23,
+ protein: 1.4,
+ riboflavin: 0.04,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.03,
+ treated: null,
+ vita_rae: 96,
+ vitb12: 0,
+ vitb6: 0.05,
+ vitc: 10,
+ zn: 0.2,
+ },
+ },
+ {
+ ca: 6,
+ crop_common_name: 'Apple',
+ crop_genus: 'Malus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 25,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
+ crop_specie: 'sylvestris ',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APPLE',
+ cu: 0.03,
+ depletion_fraction: 0.5,
+ end_kc: 0.3,
+ energy: 52,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.12,
+ fl: null,
+ folate: 3,
+ initial_kc: 0.5,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 107,
+ lipid: 0.17,
+ max_height: 0.8,
+ max_rooting_depth: 0.45,
+ mg: 5,
+ mid_kc: 0.3,
+ mn: 0.04,
+ na: 1,
+ niacin: 0.09,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 10,
+ ph: 11,
+ protein: 0.26,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.03,
+ se: null,
+ thiamin: 0.02,
+ vita_rae: 3,
+ vitb12: 0,
+ vitb6: 0.04,
+ vitc: 4.6,
+ vite: null,
+ vitk: null,
+ zn: 0.04,
+ compliance_file_url: null,
+ crop_variety_id: '19336a11-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 138,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 6,
+ crop_common_name: 'Apple',
+ crop_genus: 'Malus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 25,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
+ crop_specie: 'sylvestris ',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APPLE',
+ cu: 0.027,
+ depletion_fraction: 0.5,
+ end_kc: 0.3,
+ energy: 52,
+ farm_id: null,
+ fe: 0.12,
+ fl: null,
+ folate: 3,
+ initial_kc: 0.5,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 107,
+ lipid: 0.17,
+ max_height: 0.8,
+ max_rooting_depth: 0.45,
+ mg: 5,
+ mid_kc: 0.3,
+ mn: 0.035,
+ na: 1,
+ niacin: 0.091,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 10,
+ ph: 11,
+ protein: 0.26,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.026,
+ se: null,
+ thiamin: 0.017,
+ vita_rae: 3,
+ vitb12: 0,
+ vitb6: 0.041,
+ vitc: 4.6,
+ vite: null,
+ vitk: null,
+ zn: 0.04,
+ },
+ crop_variety: {
+ ca: 6,
+ compliance_file_url: null,
+ crop_id: 25,
+ crop_variety_id: '19336a11-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apple.webp',
+ cu: 0.03,
+ energy: 52,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 0.12,
+ folate: 3,
+ genetically_engineered: null,
+ k: 107,
+ lifecycle: 'ANNUAL',
+ lipid: 0.17,
+ mg: 5,
+ mn: 0.04,
+ na: 1,
+ niacin: 0.09,
+ nutrient_credits: null,
+ organic: null,
+ ph: 11,
+ protein: 0.26,
+ riboflavin: 0.03,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.02,
+ treated: null,
+ vita_rae: 3,
+ vitb12: 0,
+ vitb6: 0.04,
+ vitc: 4.6,
+ zn: 0.04,
+ },
+ },
+ {
+ ca: 646,
+ crop_common_name: 'Anise seeds',
+ crop_genus: 'Pimpinella',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 81,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
+ crop_specie: 'anisum ',
+ crop_subgroup: 'Temporary spice crops',
+ crop_translation_key: 'ANISE_SEEDS',
+ cu: 0.91,
+ depletion_fraction: 0.4,
+ end_kc: 1.1,
+ energy: 337,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 36.96,
+ fl: null,
+ folate: 10,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 1441,
+ lipid: 15.9,
+ max_height: null,
+ max_rooting_depth: 0.6,
+ mg: 170,
+ mid_kc: 1.15,
+ mn: 2.3,
+ na: 16,
+ niacin: 3.06,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 440,
+ protein: 17.6,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.29,
+ se: null,
+ thiamin: 0.34,
+ vita_rae: 16,
+ vitb12: 0,
+ vitb6: 0.65,
+ vitc: 21,
+ vite: null,
+ vitk: null,
+ zn: 5.3,
+ compliance_file_url: null,
+ crop_variety_id: '19336a21-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 137,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 646,
+ crop_common_name: 'Anise seeds',
+ crop_genus: 'Pimpinella',
+ crop_group: 'Beverage and spice crops',
+ crop_id: 81,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
+ crop_specie: 'anisum ',
+ crop_subgroup: 'Temporary spice crops',
+ crop_translation_key: 'ANISE_SEEDS',
+ cu: 0.91,
+ depletion_fraction: 0.4,
+ end_kc: 1.1,
+ energy: 337,
+ farm_id: null,
+ fe: 36.96,
+ fl: null,
+ folate: 10,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 1441,
+ lipid: 15.9,
+ max_height: null,
+ max_rooting_depth: 0.6,
+ mg: 170,
+ mid_kc: 1.15,
+ mn: 2.3,
+ na: 16,
+ niacin: 3.06,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 440,
+ protein: 17.6,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.29,
+ se: null,
+ thiamin: 0.34,
+ vita_rae: 16,
+ vitb12: 0,
+ vitb6: 0.65,
+ vitc: 21,
+ vite: null,
+ vitk: null,
+ zn: 5.3,
+ },
+ crop_variety: {
+ ca: 646,
+ compliance_file_url: null,
+ crop_id: 81,
+ crop_variety_id: '19336a21-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/anise_seeds.webp',
+ cu: 0.91,
+ energy: 337,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 36.96,
+ folate: 10,
+ genetically_engineered: null,
+ k: 1441,
+ lifecycle: 'ANNUAL',
+ lipid: 15.9,
+ mg: 170,
+ mn: 2.3,
+ na: 16,
+ niacin: 3.06,
+ nutrient_credits: null,
+ organic: null,
+ ph: 440,
+ protein: 17.6,
+ riboflavin: 0.29,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.34,
+ treated: null,
+ vita_rae: 16,
+ vitb12: 0,
+ vitb6: 0.65,
+ vitc: 21,
+ zn: 5.3,
+ },
+ },
+ {
+ ca: null,
+ crop_common_name: 'Alfalfa for fodder',
+ crop_genus: 'Medicago',
+ crop_group: 'Other crops',
+ crop_id: 142,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ crop_specie: 'sativa ',
+ crop_subgroup: 'Grasses and other fodder crops',
+ crop_translation_key: 'ALFALFA_FOR_FODDER',
+ cu: null,
+ depletion_fraction: 0.55,
+ end_kc: 0.85,
+ energy: null,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: null,
+ fl: null,
+ folate: null,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: null,
+ lipid: null,
+ max_height: null,
+ max_rooting_depth: 2,
+ mg: null,
+ mid_kc: 0.85,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: null,
+ ph: null,
+ protein: null,
+ refuse: null,
+ reviewed: true,
+ riboflavin: null,
+ se: null,
+ thiamin: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ vite: null,
+ vitk: null,
+ zn: null,
+ compliance_file_url: null,
+ crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 136,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-13T07:00:00.000Z',
+ crop: {
+ ca: null,
+ crop_common_name: 'Alfalfa for fodder',
+ crop_genus: 'Medicago',
+ crop_group: 'Other crops',
+ crop_id: 142,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ crop_specie: 'sativa ',
+ crop_subgroup: 'Grasses and other fodder crops',
+ crop_translation_key: 'ALFALFA_FOR_FODDER',
+ cu: null,
+ depletion_fraction: 0.55,
+ end_kc: 0.85,
+ energy: null,
+ farm_id: null,
+ fe: null,
+ fl: null,
+ folate: null,
+ initial_kc: 0.6,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: null,
+ lipid: null,
+ max_height: null,
+ max_rooting_depth: 2,
+ mg: null,
+ mid_kc: 0.85,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: null,
+ ph: null,
+ protein: null,
+ refuse: null,
+ reviewed: true,
+ riboflavin: null,
+ se: null,
+ thiamin: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ vite: null,
+ vitk: null,
+ zn: null,
+ },
+ crop_variety: {
+ ca: null,
+ compliance_file_url: null,
+ crop_id: 142,
+ crop_variety_id: '19336a3b-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ cu: null,
+ energy: null,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: null,
+ folate: null,
+ genetically_engineered: null,
+ k: null,
+ lifecycle: 'ANNUAL',
+ lipid: null,
+ mg: null,
+ mn: null,
+ na: null,
+ niacin: null,
+ nutrient_credits: 200,
+ organic: null,
+ ph: null,
+ protein: null,
+ riboflavin: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: null,
+ treated: null,
+ vita_rae: null,
+ vitb12: null,
+ vitb6: null,
+ vitc: null,
+ zn: null,
+ },
+ },
+ {
+ ca: 6,
+ crop_common_name: 'Arrowroot',
+ crop_genus: 'Maranta',
+ crop_group: 'Potatoes and yams',
+ crop_id: 147,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'arundinacea ',
+ crop_subgroup: 'High starch Root/tuber crops',
+ crop_translation_key: 'ARROWROOT',
+ cu: 0.12,
+ depletion_fraction: 0.36,
+ end_kc: 0.602667,
+ energy: 65,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 2.22,
+ fl: null,
+ folate: 338,
+ initial_kc: 0.433333,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 454,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.583333,
+ mg: 25,
+ mid_kc: 1.03433,
+ mn: 0.17,
+ na: 26,
+ niacin: 1.69,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 15,
+ ph: 98,
+ protein: 4.24,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.06,
+ se: null,
+ thiamin: 0.14,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.27,
+ vitc: 1.9,
+ vite: null,
+ vitk: null,
+ zn: 0.63,
+ compliance_file_url: null,
+ crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ genetically_engineered: null,
+ lifecycle: 'ANNUAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ treated: null,
+ location: {
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ name: 'Field one',
+ notes: '',
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
+ type: 'field',
+ total_area: 158154,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26822337992714,
+ lng: -123.2591160736328,
+ },
+ {
+ lat: 49.2656190259034,
+ lng: -123.25606908419188,
+ },
+ {
+ lat: 49.267131248202105,
+ lng: -123.25177754976805,
+ },
+ {
+ lat: 49.27068758833716,
+ lng: -123.25430955507811,
+ },
+ ],
+ perimeter: 1600,
+ perimeter_unit: 'km',
+ station_id: null,
+ organic_status: 'Transitional',
+ transition_date: '2021-04-14T07:00:00.000Z',
+ },
+ area_used: 1582,
+ bed_config: null,
+ harvest_date: '2021-05-14T17:10:00.144Z',
+ estimated_production: 1582,
+ estimated_revenue: 1582,
+ management_plan_id: 140,
+ is_by_bed: false,
+ location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
+ seed_date: '2021-04-14T17:10:00.145Z',
+ crop: {
+ ca: 6,
+ crop_common_name: 'Arrowroot',
+ crop_genus: 'Maranta',
+ crop_group: 'Potatoes and yams',
+ crop_id: 147,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ crop_specie: 'arundinacea ',
+ crop_subgroup: 'High starch Root/tuber crops',
+ crop_translation_key: 'ARROWROOT',
+ cu: 0.121,
+ depletion_fraction: 0.36,
+ end_kc: 0.602667,
+ energy: 65,
+ farm_id: null,
+ fe: 2.22,
+ fl: null,
+ folate: 338,
+ initial_kc: 0.433333,
+ is_avg_depth: true,
+ is_avg_kc: true,
+ is_avg_nutrient: false,
+ k: 454,
+ lipid: 0.2,
+ max_height: null,
+ max_rooting_depth: 0.583333,
+ mg: 25,
+ mid_kc: 1.03433,
+ mn: 0.174,
+ na: 26,
+ niacin: 1.693,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 15,
+ ph: 98,
+ protein: 4.24,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.059,
+ se: null,
+ thiamin: 0.143,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.266,
+ vitc: 1.9,
+ vite: null,
+ vitk: null,
+ zn: 0.63,
+ },
+ crop_variety: {
+ ca: 6,
+ compliance_file_url: null,
+ crop_id: 147,
+ crop_variety_id: '19336a40-b308-11eb-8c6d-1d647fbafa40',
+ crop_variety_name: '',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/default.webp',
+ cu: 0.12,
+ energy: 65,
+ farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
+ fe: 2.22,
+ folate: 338,
+ genetically_engineered: null,
+ k: 454,
+ lifecycle: 'ANNUAL',
+ lipid: 0.2,
+ mg: 25,
+ mn: 0.17,
+ na: 26,
+ niacin: 1.69,
+ nutrient_credits: null,
+ organic: null,
+ ph: 98,
+ protein: 4.24,
+ riboflavin: 0.06,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: null,
+ thiamin: 0.14,
+ treated: null,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.27,
+ vitc: 1.9,
+ zn: 0.63,
+ },
+ },
+];
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ activeCrops: crops,
+ pastCrops: crops,
+ plannedCrops: crops.slice(2, 5),
+ isAdmin: true,
+ match: {
+ url: '/field/3da7abb4-9d44-11eb-bbf7-1bc17302df43/crops',
+ params: { location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43' },
+ },
+ history: { location: { pathname: '/field/3da7abb4-9d44-11eb-bbf7-1bc17302df43/crops' } },
+};
diff --git a/packages/webapp/src/stories/Pages/Document/AddDocument.stories.js b/packages/webapp/src/stories/Pages/Document/AddDocument.stories.js
deleted file mode 100644
index 146ecbe621..0000000000
--- a/packages/webapp/src/stories/Pages/Document/AddDocument.stories.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import React from 'react';
-import PureDocumentDetailView from '../../../components/Documents/Add';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import { AddLink } from '../../../components/Typography';
-
-export default {
- title: 'Page/Document/AddDocument',
- component: PureDocumentDetailView,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- handleSubmit: () => {},
- onGoBack: () => {},
- onCancel: () => {},
- deleteImage: () => {},
- useHookFormPersist: () => ({
- persistedData: {
- uploadedFiles: [
- {
- url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- thumbnail_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- },
- ],
- },
- }),
- imageComponent: (props) => ,
- documentUploader: (props) => {props.linkText} ,
- isEdit: true,
-};
-
-export const uploadingImage = Template.bind({});
-uploadingImage.args = {
- handleSubmit: () => {},
- onGoBack: () => {},
- onCancel: () => {},
- deleteImage: () => {},
- useHookFormPersist: () => ({
- persistedData: {
- uploadedFiles: [
- {
- url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- thumbnail_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- },
- ],
- },
- }),
- imageComponent: (props) => ,
- documentUploader: (props) => {props.linkText} ,
- isEdit: false,
-};
-
-Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/Document/AddDocument.stories.jsx b/packages/webapp/src/stories/Pages/Document/AddDocument.stories.jsx
new file mode 100644
index 0000000000..c857585a07
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Document/AddDocument.stories.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import PureDocumentDetailView from '../../../components/Documents/Add';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import { AddLink } from '../../../components/Typography';
+
+export default {
+ title: 'Page/Document/AddDocument',
+ component: PureDocumentDetailView,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ handleSubmit: () => {},
+ onGoBack: () => {},
+ onCancel: () => {},
+ deleteImage: () => {},
+ useHookFormPersist: () => ({
+ persistedData: {
+ uploadedFiles: [
+ {
+ url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ thumbnail_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ },
+ ],
+ },
+ }),
+ imageComponent: (props) => ,
+ documentUploader: (props) => {props.linkText} ,
+ isEdit: true,
+};
+
+export const uploadingImage = Template.bind({});
+uploadingImage.args = {
+ handleSubmit: () => {},
+ onGoBack: () => {},
+ onCancel: () => {},
+ deleteImage: () => {},
+ useHookFormPersist: () => ({
+ persistedData: {
+ uploadedFiles: [
+ {
+ url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ thumbnail_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ },
+ ],
+ },
+ }),
+ imageComponent: (props) => ,
+ documentUploader: (props) => {props.linkText} ,
+ isEdit: false,
+};
+
+Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/Document/EditDocument.stories.js b/packages/webapp/src/stories/Pages/Document/EditDocument.stories.js
deleted file mode 100644
index 4dde811bdf..0000000000
--- a/packages/webapp/src/stories/Pages/Document/EditDocument.stories.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import PureDocumentDetailView from '../../../components/Documents/Add';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import { AddLink } from '../../../components/Typography';
-
-export default {
- title: 'Page/Document/EditDocument',
- component: PureDocumentDetailView,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-
-Primary.args = {
- handleSubmit: () => {},
- onGoBack: () => {},
- deleteImage: () => {},
- useHookFormPersist: () => ({
- persistedData: {
- uploadedFiles: [
- {
- url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- thumbnail_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- },
- ],
- },
- }),
- imageComponent: (props) => ,
- documentUploader: (props) => {props.linkText} ,
- isEdit: true,
-};
-
-Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/Document/EditDocument.stories.jsx b/packages/webapp/src/stories/Pages/Document/EditDocument.stories.jsx
new file mode 100644
index 0000000000..919d118ea6
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Document/EditDocument.stories.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import PureDocumentDetailView from '../../../components/Documents/Add';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import { AddLink } from '../../../components/Typography';
+
+export default {
+ title: 'Page/Document/EditDocument',
+ component: PureDocumentDetailView,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ handleSubmit: () => {},
+ onGoBack: () => {},
+ deleteImage: () => {},
+ useHookFormPersist: () => ({
+ persistedData: {
+ uploadedFiles: [
+ {
+ url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ thumbnail_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ },
+ ],
+ },
+ }),
+ imageComponent: (props) => ,
+ documentUploader: (props) => {props.linkText} ,
+ isEdit: true,
+};
+
+Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/Document/MainDocument.stories.js b/packages/webapp/src/stories/Pages/Document/MainDocument.stories.js
deleted file mode 100644
index 904d0be8b8..0000000000
--- a/packages/webapp/src/stories/Pages/Document/MainDocument.stories.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import MainDocumentView from '../../../components/Documents/Main';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/Document/MainDocument',
- component: MainDocumentView,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-
-Primary.args = {
- onRetire: () => {},
- onUpdate: () => {},
- document: {
- name: 'Document Name',
- notes: `Lorem Ipsum dolorem`,
- valid_until: '2021-06-21',
- files: [
- {
- thumbnail_url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
- },
- ],
- },
- imageComponent: (props) => ,
- onGoBack: () => {},
-};
-
-Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/Document/MainDocument.stories.jsx b/packages/webapp/src/stories/Pages/Document/MainDocument.stories.jsx
new file mode 100644
index 0000000000..981662b50f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Document/MainDocument.stories.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import MainDocumentView from '../../../components/Documents/Main';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/Document/MainDocument',
+ component: MainDocumentView,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+
+Primary.args = {
+ onRetire: () => {},
+ onUpdate: () => {},
+ document: {
+ name: 'Document Name',
+ notes: `Lorem Ipsum dolorem`,
+ valid_until: '2021-06-21',
+ files: [
+ {
+ thumbnail_url: 'https://litefarm.nyc3.digitaloceanspaces.com/default_crop/v2/default.webp',
+ },
+ ],
+ },
+ imageComponent: (props) => ,
+ onGoBack: () => {},
+};
+
+Primary.parameters = { ...chromaticSmallScreen };
diff --git a/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.js b/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.js
deleted file mode 100644
index 555d1def97..0000000000
--- a/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import React from 'react';
-import EditCropVariety from '../../../components/EditCropVariety';
-import decorators from '../config/decorators';
-import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
-import { AddLink } from '../../../components/Typography';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Crop/EditCropVariety',
- decorators: decorators,
- component: EditCropVariety,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- crop: {
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 31,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APRICOT',
- },
- imageUploader: (
-
- {'Add image'}
-
- ),
- handleGoBack: () => {},
- isSeekingCert: false,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeekingCert = Template.bind({});
-SeekingCert.args = {
- crop: {
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 31,
- crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
- crop_subgroup: 'Pome fruits and stone fruits',
- crop_translation_key: 'APRICOT',
- },
- imageUploader: (
-
- {'Add image'}
-
- ),
- handleGoBack: () => {},
- isSeekingCert: true,
-};
-SeekingCert.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.jsx b/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.jsx
new file mode 100644
index 0000000000..68c302a8ec
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/EditCropVariety/EditCropVariety.stories.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import EditCropVariety from '../../../components/EditCropVariety';
+import decorators from '../config/Decorators';
+import ImagePickerWrapper from '../../../containers/ImagePickerWrapper';
+import { AddLink } from '../../../components/Typography';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Crop/EditCropVariety',
+ decorators: decorators,
+ component: EditCropVariety,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ crop: {
+ crop_common_name: 'Apricot',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 31,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APRICOT',
+ },
+ imageUploader: (
+
+ {'Add image'}
+
+ ),
+ handleGoBack: () => {},
+ isSeekingCert: false,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeekingCert = Template.bind({});
+SeekingCert.args = {
+ crop: {
+ crop_common_name: 'Apricot',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 31,
+ crop_photo_url: 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/apricot.webp',
+ crop_subgroup: 'Pome fruits and stone fruits',
+ crop_translation_key: 'APRICOT',
+ },
+ imageUploader: (
+
+ {'Add image'}
+
+ ),
+ handleGoBack: () => {},
+ isSeekingCert: true,
+};
+SeekingCert.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.js b/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.js
deleted file mode 100644
index 099e112e37..0000000000
--- a/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.js
+++ /dev/null
@@ -1,261 +0,0 @@
-import React from 'react';
-import PureFilterPage from '../../../components/FilterPage';
-import decorator from '../config/decorators';
-import Input from '../../../components/Form/Input';
-
-export default {
- title: 'Page/FilterPage',
- component: PureFilterPage,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- title: 'Crop Catalogue Filter',
- filters: [
- {
- subject: 'Status',
- filterKey: 'Status',
- options: [
- {
- value: 'active',
- default: false,
- label: 'Active',
- },
- {
- value: 'planned',
- default: false,
- label: 'Planned',
- },
- {
- value: 'complete',
- default: false,
- label: 'Complete',
- },
- {
- value: 'abandoned',
- default: false,
- label: 'Abandoned',
- },
- {
- value: 'needs_plan',
- default: false,
- label: 'Needs plan',
- },
- ],
- },
- {
- subject: 'Location',
- filterKey: 'Location',
- options: [
- {
- value: 'Buffer Zone 1',
- default: false,
- label: 'Buffer Zone 1',
- },
- {
- value: 'Buffer Zone 2',
- default: false,
- label: 'Buffer Zone 2',
- },
- {
- value: 'Field 1',
- default: false,
- label: 'Field 1',
- },
- {
- value: 'Field 2',
- default: false,
- label: 'Field 2',
- },
- {
- value: 'Field 3',
- default: false,
- label: 'Field 3',
- },
- {
- value: 'Field 4',
- default: false,
- label: 'Field 4',
- },
- {
- value: 'Field 5',
- default: false,
- label: 'Field 5',
- },
- {
- value: 'Greenhouse 1',
- default: false,
- label: 'Greenhouse 1',
- },
- {
- value: 'Greenhouse 2',
- default: false,
- label: 'Greenhouse 2',
- },
- {
- value: 'Veggie Garden',
- default: false,
- label: 'Veggie Garden',
- },
- ],
- },
- {
- subject: 'Suppliers',
- filterKey: 'Suppliers',
- options: [
- {
- value: 'Supplier 1',
- default: false,
- label: 'Supplier 1',
- },
- {
- value: 'Supplier 2',
- default: false,
- label: 'Supplier 2',
- },
- {
- value: 'Supplier 3',
- default: false,
- label: 'Supplier 3',
- },
- ],
- },
- ],
- filterRef: { current: {} },
-};
-
-export const NoSuppliers = Template.bind({});
-NoSuppliers.args = {
- title: 'Crop Catalogue Filter',
- filters: [
- {
- subject: 'Status',
- filterKey: 'Status',
- options: [
- {
- value: 'active',
- label: 'Active',
- },
- {
- value: 'planned',
- label: 'Planned',
- },
- {
- value: 'complete',
- label: 'Complete',
- },
- {
- value: 'abandoned',
- label: 'Abandoned',
- },
- {
- value: 'needs_plan',
- label: 'Needs plan',
- },
- ],
- },
- {
- subject: 'Location',
- filterKey: 'Location',
- options: [
- {
- value: 'Buffer Zone 1',
- label: 'Buffer Zone 1',
- },
- {
- value: 'Buffer Zone 2',
- label: 'Buffer Zone 2',
- },
- {
- value: 'Field 1',
- label: 'Field 1',
- },
- {
- value: 'Field 2',
- label: 'Field 2',
- },
- {
- value: 'Field 3',
- label: 'Field 3',
- },
- {
- value: 'Field 4',
- label: 'Field 4',
- },
- {
- value: 'Field 5',
- label: 'Field 5',
- },
- {
- value: 'Greenhouse 1',
- label: 'Greenhouse 1',
- },
- {
- value: 'Greenhouse 2',
- label: 'Greenhouse 2',
- },
- {
- value: 'Veggie Garden',
- label: 'Veggie Garden',
- },
- ],
- },
- {
- subject: 'Suppliers',
- filterKey: 'Suppliers',
- options: [],
- },
- ],
- filterRef: { current: {} },
-};
-
-export const DocumentsFilter = Template.bind({});
-DocumentsFilter.args = {
- title: 'Documents Filter',
- filters: [
- {
- subject: 'Type',
- filterKey: 'Type',
- options: [
- {
- value: 'cleaning_product',
- default: false,
- label: 'Cleaning product',
- },
- {
- value: 'crop_compliance',
- default: false,
- label: 'Crop compliance',
- },
- {
- value: 'fertilizing_product',
- default: false,
- label: 'Fertilizing product',
- },
- {
- value: 'pest_control_product',
- default: false,
- label: 'Pest control product',
- },
- {
- value: 'soil_amendment',
- default: false,
- label: 'Soil amendment',
- },
- {
- value: 'other',
- default: false,
- label: 'Other',
- },
- ],
- },
- ],
- filterRef: { current: {} },
- children: (
-
-
-
- ),
-};
diff --git a/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.jsx b/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.jsx
new file mode 100644
index 0000000000..2878e5ccf6
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/FilterPage/FilterPage.stories.jsx
@@ -0,0 +1,261 @@
+import React from 'react';
+import PureFilterPage from '../../../components/FilterPage';
+import decorator from '../config/Decorators';
+import Input from '../../../components/Form/Input';
+
+export default {
+ title: 'Page/FilterPage',
+ component: PureFilterPage,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ title: 'Crop Catalogue Filter',
+ filters: [
+ {
+ subject: 'Status',
+ filterKey: 'Status',
+ options: [
+ {
+ value: 'active',
+ default: false,
+ label: 'Active',
+ },
+ {
+ value: 'planned',
+ default: false,
+ label: 'Planned',
+ },
+ {
+ value: 'complete',
+ default: false,
+ label: 'Complete',
+ },
+ {
+ value: 'abandoned',
+ default: false,
+ label: 'Abandoned',
+ },
+ {
+ value: 'needs_plan',
+ default: false,
+ label: 'Needs plan',
+ },
+ ],
+ },
+ {
+ subject: 'Location',
+ filterKey: 'Location',
+ options: [
+ {
+ value: 'Buffer Zone 1',
+ default: false,
+ label: 'Buffer Zone 1',
+ },
+ {
+ value: 'Buffer Zone 2',
+ default: false,
+ label: 'Buffer Zone 2',
+ },
+ {
+ value: 'Field 1',
+ default: false,
+ label: 'Field 1',
+ },
+ {
+ value: 'Field 2',
+ default: false,
+ label: 'Field 2',
+ },
+ {
+ value: 'Field 3',
+ default: false,
+ label: 'Field 3',
+ },
+ {
+ value: 'Field 4',
+ default: false,
+ label: 'Field 4',
+ },
+ {
+ value: 'Field 5',
+ default: false,
+ label: 'Field 5',
+ },
+ {
+ value: 'Greenhouse 1',
+ default: false,
+ label: 'Greenhouse 1',
+ },
+ {
+ value: 'Greenhouse 2',
+ default: false,
+ label: 'Greenhouse 2',
+ },
+ {
+ value: 'Veggie Garden',
+ default: false,
+ label: 'Veggie Garden',
+ },
+ ],
+ },
+ {
+ subject: 'Suppliers',
+ filterKey: 'Suppliers',
+ options: [
+ {
+ value: 'Supplier 1',
+ default: false,
+ label: 'Supplier 1',
+ },
+ {
+ value: 'Supplier 2',
+ default: false,
+ label: 'Supplier 2',
+ },
+ {
+ value: 'Supplier 3',
+ default: false,
+ label: 'Supplier 3',
+ },
+ ],
+ },
+ ],
+ filterRef: { current: {} },
+};
+
+export const NoSuppliers = Template.bind({});
+NoSuppliers.args = {
+ title: 'Crop Catalogue Filter',
+ filters: [
+ {
+ subject: 'Status',
+ filterKey: 'Status',
+ options: [
+ {
+ value: 'active',
+ label: 'Active',
+ },
+ {
+ value: 'planned',
+ label: 'Planned',
+ },
+ {
+ value: 'complete',
+ label: 'Complete',
+ },
+ {
+ value: 'abandoned',
+ label: 'Abandoned',
+ },
+ {
+ value: 'needs_plan',
+ label: 'Needs plan',
+ },
+ ],
+ },
+ {
+ subject: 'Location',
+ filterKey: 'Location',
+ options: [
+ {
+ value: 'Buffer Zone 1',
+ label: 'Buffer Zone 1',
+ },
+ {
+ value: 'Buffer Zone 2',
+ label: 'Buffer Zone 2',
+ },
+ {
+ value: 'Field 1',
+ label: 'Field 1',
+ },
+ {
+ value: 'Field 2',
+ label: 'Field 2',
+ },
+ {
+ value: 'Field 3',
+ label: 'Field 3',
+ },
+ {
+ value: 'Field 4',
+ label: 'Field 4',
+ },
+ {
+ value: 'Field 5',
+ label: 'Field 5',
+ },
+ {
+ value: 'Greenhouse 1',
+ label: 'Greenhouse 1',
+ },
+ {
+ value: 'Greenhouse 2',
+ label: 'Greenhouse 2',
+ },
+ {
+ value: 'Veggie Garden',
+ label: 'Veggie Garden',
+ },
+ ],
+ },
+ {
+ subject: 'Suppliers',
+ filterKey: 'Suppliers',
+ options: [],
+ },
+ ],
+ filterRef: { current: {} },
+};
+
+export const DocumentsFilter = Template.bind({});
+DocumentsFilter.args = {
+ title: 'Documents Filter',
+ filters: [
+ {
+ subject: 'Type',
+ filterKey: 'Type',
+ options: [
+ {
+ value: 'cleaning_product',
+ default: false,
+ label: 'Cleaning product',
+ },
+ {
+ value: 'crop_compliance',
+ default: false,
+ label: 'Crop compliance',
+ },
+ {
+ value: 'fertilizing_product',
+ default: false,
+ label: 'Fertilizing product',
+ },
+ {
+ value: 'pest_control_product',
+ default: false,
+ label: 'Pest control product',
+ },
+ {
+ value: 'soil_amendment',
+ default: false,
+ label: 'Soil amendment',
+ },
+ {
+ value: 'other',
+ default: false,
+ label: 'Other',
+ },
+ ],
+ },
+ ],
+ filterRef: { current: {} },
+ children: (
+
+
+
+ ),
+};
diff --git a/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.js b/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.js
deleted file mode 100644
index b4d879983c..0000000000
--- a/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import FullMonthCalendarView from '../../../components/MonthCalendar';
-import { componentDecorators } from '../config/decorators';
-
-export default {
- title: 'Components/FullMonthCalendar',
- component: FullMonthCalendarView,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- date: '07-30-2021',
- stage: 'harvest_date'
-};
diff --git a/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.jsx b/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.jsx
new file mode 100644
index 0000000000..70349209c3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/FullYearCalendar/FullMonthCalendar.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import FullMonthCalendarView from '../../../components/MonthCalendar';
+import { componentDecorators } from '../config/Decorators';
+
+export default {
+ title: 'Components/FullMonthCalendar',
+ component: FullMonthCalendarView,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ date: '07-30-2021',
+ stage: 'harvest_date'
+};
diff --git a/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.js b/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.js
deleted file mode 100644
index 2b10319401..0000000000
--- a/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import FullYearCalendarView from '../../../components/FullYearCalendar';
-import { componentDecorators } from '../config/decorators';
-
-export default {
- title: 'Components/FullYearCalendar',
- component: FullYearCalendarView,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- seed_date: '06-01-2021',
- germination_date: '06-30-2021',
- harvest_date: '04-30-2022',
- transplant_date: '07-30-2021',
-};
diff --git a/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.jsx b/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.jsx
new file mode 100644
index 0000000000..cfef9fc145
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/FullYearCalendar/FullYearCalendar.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import FullYearCalendarView from '../../../components/FullYearCalendar';
+import { componentDecorators } from '../config/Decorators';
+
+export default {
+ title: 'Components/FullYearCalendar',
+ component: FullYearCalendarView,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ seed_date: '06-01-2021',
+ germination_date: '06-30-2021',
+ harvest_date: '04-30-2022',
+ transplant_date: '07-30-2021',
+};
diff --git a/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.js b/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.js
deleted file mode 100644
index 3e0659e6a4..0000000000
--- a/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PureAddHarvestUse from '../../../components/Logs/PureAddHarvestUse';
-
-export default {
- title: 'Form/AddHarvestUse',
- decorators: decorators,
- component: PureAddHarvestUse,
-};
-
-const Template = (args) => ;
-
-export const Add = Template.bind({});
-Add.args = {
- title: 'Add harvest use',
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- title: 'Edit harvest use',
- defaultHarvestUseName: 'Harvest use name1',
-};
diff --git a/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.jsx b/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.jsx
new file mode 100644
index 0000000000..00b5fb7364
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/HarvestLog/AddHarvestUse.stories.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PureAddHarvestUse from '../../../components/Logs/PureAddHarvestUse';
+
+export default {
+ title: 'Form/AddHarvestUse',
+ decorators: decorators,
+ component: PureAddHarvestUse,
+};
+
+const Template = (args) => ;
+
+export const Add = Template.bind({});
+Add.args = {
+ title: 'Add harvest use',
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ title: 'Edit harvest use',
+ defaultHarvestUseName: 'Harvest use name1',
+};
diff --git a/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.js b/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.js
deleted file mode 100644
index 0c4473c21e..0000000000
--- a/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PureHarvestLog from '../../../components/Logs/HarvestLog';
-
-export default {
- title: 'Form/HarvestLog',
- decorators: decorators,
- component: PureHarvestLog,
-};
-
-const Template = (args) => ;
-
-export const HelpMain = Template.bind({});
-HelpMain.args = {
- isEdit: {},
- dispatch: () => {},
- defaultData: {},
-};
diff --git a/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.jsx b/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.jsx
new file mode 100644
index 0000000000..8cbb6705ad
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/HarvestLog/HarvestLog.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PureHarvestLog from '../../../components/Logs/HarvestLog';
+
+export default {
+ title: 'Form/HarvestLog',
+ decorators: decorators,
+ component: PureHarvestLog,
+};
+
+const Template = (args) => ;
+
+export const HelpMain = Template.bind({});
+HelpMain.args = {
+ isEdit: {},
+ dispatch: () => {},
+ defaultData: {},
+};
diff --git a/packages/webapp/src/stories/Pages/Help/PureHelp.stories.js b/packages/webapp/src/stories/Pages/Help/PureHelp.stories.js
deleted file mode 100644
index d668769f79..0000000000
--- a/packages/webapp/src/stories/Pages/Help/PureHelp.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { authenticatedDecorators } from '../config/decorators';
-import PureHelpRequestPage from '../../../components/Help';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Help/PureHelp',
- decorators: authenticatedDecorators,
- component: PureHelpRequestPage,
-};
-
-const Template = (args) => ;
-
-export const HelpMain = Template.bind({});
-HelpMain.args = {};
-HelpMain.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Help/PureHelp.stories.jsx b/packages/webapp/src/stories/Pages/Help/PureHelp.stories.jsx
new file mode 100644
index 0000000000..9ee0233f00
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Help/PureHelp.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { authenticatedDecorators } from '../config/Decorators';
+import PureHelpRequestPage from '../../../components/Help';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Help/PureHelp',
+ decorators: authenticatedDecorators,
+ component: PureHelpRequestPage,
+};
+
+const Template = (args) => ;
+
+export const HelpMain = Template.bind({});
+HelpMain.args = {};
+HelpMain.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Home/Home.stories.js b/packages/webapp/src/stories/Pages/Home/Home.stories.js
deleted file mode 100644
index f2a6c66a6a..0000000000
--- a/packages/webapp/src/stories/Pages/Home/Home.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import { authenticatedDecorators } from '../config/decorators';
-import React from 'react';
-import Home from '../../../containers/Home';
-
-export default {
- title: 'Form/Home/HomeWrapper',
- decorators: authenticatedDecorators,
- component: Home,
-};
-
-const Template = (args) => ;
-
-export const Default = Template.bind({});
-Default.args = {};
-Default.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/Pages/Home/Home.stories.jsx b/packages/webapp/src/stories/Pages/Home/Home.stories.jsx
new file mode 100644
index 0000000000..3be4e5b731
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Home/Home.stories.jsx
@@ -0,0 +1,17 @@
+import { authenticatedDecorators } from '../config/Decorators';
+import React from 'react';
+import Home from '../../../containers/Home';
+
+export default {
+ title: 'Form/Home/HomeWrapper',
+ decorators: authenticatedDecorators,
+ component: Home,
+};
+
+const Template = (args) => ;
+
+export const Default = Template.bind({});
+Default.args = {};
+Default.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/Pages/Home/PureHome.stories.js b/packages/webapp/src/stories/Pages/Home/PureHome.stories.js
deleted file mode 100644
index ad39966db9..0000000000
--- a/packages/webapp/src/stories/Pages/Home/PureHome.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import { authenticatedDecorators } from '../config/decorators';
-import { Rain } from '../../WeatherBoard/PureWeather.stories';
-import PureHome from '../../../components/Home';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Home/PureHome',
- decorators: authenticatedDecorators,
- component: PureHome,
-};
-
-const Template = (args) => ;
-
-export const HomeRain = Template.bind({});
-HomeRain.args = {
- greeting: 'Good morning,',
- first_name: ' User Name',
- children: ,
- imgUrl:
- 'https://res.cloudinary.com/dfxanglyc/image/upload/v1552774058/portfolio/1024px-Nail___Gear.svg.png',
-};
-HomeRain.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Home/PureHome.stories.jsx b/packages/webapp/src/stories/Pages/Home/PureHome.stories.jsx
new file mode 100644
index 0000000000..2c14cd7c56
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Home/PureHome.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { authenticatedDecorators } from '../config/Decorators';
+import { Rain } from '../../WeatherBoard/PureWeather.stories';
+import PureHome from '../../../components/Home';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Home/PureHome',
+ decorators: authenticatedDecorators,
+ component: PureHome,
+};
+
+const Template = (args) => ;
+
+export const HomeRain = Template.bind({});
+HomeRain.args = {
+ greeting: 'Good morning,',
+ first_name: ' User Name',
+ children: ,
+ imgUrl:
+ 'https://res.cloudinary.com/dfxanglyc/image/upload/v1552774058/portfolio/1024px-Nail___Gear.svg.png',
+};
+HomeRain.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.js b/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.js
deleted file mode 100644
index b46116b8df..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import AddFarm from '../../../../containers/AddFarm';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/2-AddFarm',
- decorators: decorators,
- component: AddFarm,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.jsx b/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.jsx
new file mode 100644
index 0000000000..1fc878ee88
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/AddFarm/AddFarm.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import AddFarm from '../../../../containers/AddFarm';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/2-AddFarm',
+ decorators: decorators,
+ component: AddFarm,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.js b/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.js
deleted file mode 100644
index a7cea0777e..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import { PureCertifierSelectionScreen } from '../../../../components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/PureCertifierSelectionScreen',
- decorators: decorators,
- component: PureCertifierSelectionScreen,
-};
-
-const certifiers = [
- {
- certifier_id: 5,
- certification_type: 1,
- certifier_name: 'Bio-Dynamic Agricultural Society of British Columbia',
- certifier_acronym: 'BDASBC',
- certifier_country_id: 5,
- country_id: 37,
- farm_id: 'ea8eda4e-bdad-11eb-9e63-318a4efb8273',
- farm_name: 'new organic',
- address: '49.267847499999995, -123.1745952',
- units: {
- currency: 'CAD',
- measurement: 'metric',
- },
- grid_points: {
- lat: 49.267847499999995,
- lng: -123.1745952,
- },
- deleted: false,
- farm_phone_number: null,
- created_by_user_id: '104942873090979111002',
- updated_by_user_id: '104942873090979111002',
- created_at: '2021-05-25T23:07:02.713Z',
- updated_at: '2021-05-25T23:07:06.436Z',
- sandbox_farm: false,
- owner_operated: true,
- },
- {
- certifier_id: 4,
- certification_type: 1,
- certifier_name: 'British Columbia Association for Regenerative Agriculture',
- certifier_acronym: 'BCARA',
- certifier_country_id: 4,
- country_id: 37,
- farm_id: 'ea8eda4e-bdad-11eb-9e63-318a4efb8273',
- farm_name: 'new organic',
- address: '49.267847499999995, -123.1745952',
- units: {
- currency: 'CAD',
- measurement: 'metric',
- },
- grid_points: {
- lat: 49.267847499999995,
- lng: -123.1745952,
- },
- deleted: false,
- farm_phone_number: null,
- created_by_user_id: '104942873090979111002',
- updated_by_user_id: '104942873090979111002',
- created_at: '2021-05-25T23:07:02.713Z',
- updated_at: '2021-05-25T23:07:06.436Z',
- sandbox_farm: false,
- owner_operated: true,
- },
-];
-const certifications = [
- {
- certification_id: 1,
- certification_type: 'Organic',
- certification_translation_key: 'ORGANIC',
- },
- {
- certification_id: 2,
- certification_type: 'Participatory Guarantee System',
- certification_translation_key: 'PGS',
- },
-];
-
-const Template = (args) => ;
-
-export const NotSearchable = Template.bind({});
-NotSearchable.args = {
- persistedFormData: {},
- certifications: certifications,
- certifiers: certifiers.slice(0, 1),
-};
-NotSearchable.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Searchable = Template.bind({});
-Searchable.args = {
- persistedFormData: {},
- certifications: certifications,
- certifiers,
-};
-Searchable.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.jsx b/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.jsx
new file mode 100644
index 0000000000..382a2af254
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/CertiferSelection/CertiferSelection.stories.jsx
@@ -0,0 +1,103 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import {
+ PureCertifierSelectionScreen,
+} from '../../../../components/OrganicCertifierSurvey/CertifierSelection/PureCertifierSelectionScreen';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/PureCertifierSelectionScreen',
+ decorators: decorators,
+ component: PureCertifierSelectionScreen,
+};
+
+const certifiers = [
+ {
+ certifier_id: 5,
+ certification_type: 1,
+ certifier_name: 'Bio-Dynamic Agricultural Society of British Columbia',
+ certifier_acronym: 'BDASBC',
+ certifier_country_id: 5,
+ country_id: 37,
+ farm_id: 'ea8eda4e-bdad-11eb-9e63-318a4efb8273',
+ farm_name: 'new organic',
+ address: '49.267847499999995, -123.1745952',
+ units: {
+ currency: 'CAD',
+ measurement: 'metric',
+ },
+ grid_points: {
+ lat: 49.267847499999995,
+ lng: -123.1745952,
+ },
+ deleted: false,
+ farm_phone_number: null,
+ created_by_user_id: '104942873090979111002',
+ updated_by_user_id: '104942873090979111002',
+ created_at: '2021-05-25T23:07:02.713Z',
+ updated_at: '2021-05-25T23:07:06.436Z',
+ sandbox_farm: false,
+ owner_operated: true,
+ },
+ {
+ certifier_id: 4,
+ certification_type: 1,
+ certifier_name: 'British Columbia Association for Regenerative Agriculture',
+ certifier_acronym: 'BCARA',
+ certifier_country_id: 4,
+ country_id: 37,
+ farm_id: 'ea8eda4e-bdad-11eb-9e63-318a4efb8273',
+ farm_name: 'new organic',
+ address: '49.267847499999995, -123.1745952',
+ units: {
+ currency: 'CAD',
+ measurement: 'metric',
+ },
+ grid_points: {
+ lat: 49.267847499999995,
+ lng: -123.1745952,
+ },
+ deleted: false,
+ farm_phone_number: null,
+ created_by_user_id: '104942873090979111002',
+ updated_by_user_id: '104942873090979111002',
+ created_at: '2021-05-25T23:07:02.713Z',
+ updated_at: '2021-05-25T23:07:06.436Z',
+ sandbox_farm: false,
+ owner_operated: true,
+ },
+];
+const certifications = [
+ {
+ certification_id: 1,
+ certification_type: 'Organic',
+ certification_translation_key: 'ORGANIC',
+ },
+ {
+ certification_id: 2,
+ certification_type: 'Participatory Guarantee System',
+ certification_translation_key: 'PGS',
+ },
+];
+
+const Template = (args) => ;
+
+export const NotSearchable = Template.bind({});
+NotSearchable.args = {
+ persistedFormData: {},
+ certifications: certifications,
+ certifiers: certifiers.slice(0, 1),
+};
+NotSearchable.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Searchable = Template.bind({});
+Searchable.args = {
+ persistedFormData: {},
+ certifications: certifications,
+ certifiers,
+};
+Searchable.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.js b/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.js
deleted file mode 100644
index b93b325928..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { PureCertificationSelection } from '../../../../components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/PureCertificationSelection',
- decorators: decorators,
- component: PureCertificationSelection,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- persistedFormData: {
- certification_id: 2,
- },
- certifications: [
- {
- certification_id: 1,
- certification_type: 'Organic',
- certification_translation_key: 'ORGANIC',
- },
- {
- certification_id: 2,
- certification_type: 'Participatory Guarantee System',
- certification_translation_key: 'PGS',
- },
- ],
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.jsx b/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.jsx
new file mode 100644
index 0000000000..16dd12870b
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/CertificationSelection/CertificationSelection.stories.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import {
+ PureCertificationSelection,
+} from '../../../../components/OrganicCertifierSurvey/CertificationSelection/PureCertificationSelection';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/PureCertificationSelection',
+ decorators: decorators,
+ component: PureCertificationSelection,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ persistedFormData: {
+ certification_id: 2,
+ },
+ certifications: [
+ {
+ certification_id: 1,
+ certification_type: 'Organic',
+ certification_translation_key: 'ORGANIC',
+ },
+ {
+ certification_id: 2,
+ certification_type: 'Participatory Guarantee System',
+ certification_translation_key: 'PGS',
+ },
+ ],
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.js b/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.js
deleted file mode 100644
index a0f43f58a5..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-import { PureInterestedOrganic } from '../../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
-
-export default {
- title: 'Form/Intro/4-InterestedOrganic',
- decorators: decorators,
- component: PureInterestedOrganic,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- onGoBack: () => {},
- onSubmit: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.jsx b/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.jsx
new file mode 100644
index 0000000000..6363966fe1
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/InterestedOrganic/InterestedOrganic.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+import { PureInterestedOrganic } from '../../../../components/OrganicCertifierSurvey/InterestedOrganic/PureInterestedOrganic';
+
+export default {
+ title: 'Form/Intro/4-InterestedOrganic',
+ decorators: decorators,
+ component: PureInterestedOrganic,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ onGoBack: () => {},
+ onSubmit: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.js b/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.js
deleted file mode 100644
index 00da8fb6de..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import Layout from '../../../components/Layout';
-import Button from '../../../components/Form/Button';
-import Svg from '../../../components/Svg';
-import signup2 from '../../../assets/images/signUp/signUp2.svg';
-import decorators from '../config/decorators';
-
-export default {
- title: 'Layout/Intro',
- decorators: decorators,
- component: Layout,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- buttonGroup: ,
-};
-
-export const SVG = Template.bind({});
-SVG.args = {
- buttonGroup: ,
- children: ,
- isSVG: true,
-};
-
-export const TwoButton = Template.bind({});
-TwoButton.args = {
- buttonGroup: (
- <>
-
-
- >
- ),
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.jsx b/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.jsx
new file mode 100644
index 0000000000..e208afd9f7
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/IntroLayout.stories.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import Layout from '../../../components/Layout';
+import Button from '../../../components/Form/Button';
+import Svg from '../../../components/Svg';
+import signup2 from '../../../assets/images/signUp/signUp2.svg';
+import decorators from '../config/Decorators';
+
+export default {
+ title: 'Layout/Intro',
+ decorators: decorators,
+ component: Layout,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ buttonGroup: ,
+};
+
+export const SVG = Template.bind({});
+SVG.args = {
+ buttonGroup: ,
+ children: ,
+ isSVG: true,
+};
+
+export const TwoButton = Template.bind({});
+TwoButton.args = {
+ buttonGroup: (
+ <>
+
+
+ >
+ ),
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.js b/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.js
deleted file mode 100644
index 1276fe39c5..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import PureOutroSplash from '../../../../components/Outro';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/6-Outro',
- decorators: decorators,
- component: PureOutroSplash,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- redirectFinish: () => {},
- onGoBack: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.jsx b/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.jsx
new file mode 100644
index 0000000000..375807fef2
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/Outro/Outro.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import PureOutroSplash from '../../../../components/Outro';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/6-Outro',
+ decorators: decorators,
+ component: PureOutroSplash,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ redirectFinish: () => {},
+ onGoBack: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.js b/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.js
deleted file mode 100644
index 8ef3d6a1e6..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import { PureRequestCertifier } from '../../../../components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/RequestCertifier',
- decorators: decorators,
- component: PureRequestCertifier,
-};
-
-const Template = (args) => ;
-
-export const RequestedCertification = Template.bind({});
-RequestedCertification.args = {
- certificationName: 'Other',
- isRequestedCertification: true,
- hasSupportedCertifiers: true,
- requestedCertification: 'Certification',
- onGoBack: () => {},
-};
-RequestedCertification.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WithSupportedCertifier = Template.bind({});
-WithSupportedCertifier.args = {
- certificationName: 'Organic',
- isRequestedCertification: false,
- hasSupportedCertifiers: true,
- requestedCertification: 'Certification',
- onGoBack: () => {},
-};
-WithSupportedCertifier.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const NoSupportedCertifier = Template.bind({});
-NoSupportedCertifier.args = {
- certificationName: 'Organic',
- isRequestedCertification: false,
- hasSupportedCertifiers: true,
- requestedCertification: 'Certification',
- onGoBack: () => {},
-};
-NoSupportedCertifier.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.jsx b/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.jsx
new file mode 100644
index 0000000000..e359ff9613
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/RequestCertifier/RequestCertifier.stories.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import {
+ PureRequestCertifier,
+} from '../../../../components/OrganicCertifierSurvey/RequestCertifier/PureRequestCertifier';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/RequestCertifier',
+ decorators: decorators,
+ component: PureRequestCertifier,
+};
+
+const Template = (args) => ;
+
+export const RequestedCertification = Template.bind({});
+RequestedCertification.args = {
+ certificationName: 'Other',
+ isRequestedCertification: true,
+ hasSupportedCertifiers: true,
+ requestedCertification: 'Certification',
+ onGoBack: () => {},
+};
+RequestedCertification.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WithSupportedCertifier = Template.bind({});
+WithSupportedCertifier.args = {
+ certificationName: 'Organic',
+ isRequestedCertification: false,
+ hasSupportedCertifiers: true,
+ requestedCertification: 'Certification',
+ onGoBack: () => {},
+};
+WithSupportedCertifier.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const NoSupportedCertifier = Template.bind({});
+NoSupportedCertifier.args = {
+ certificationName: 'Organic',
+ isRequestedCertification: false,
+ hasSupportedCertifiers: true,
+ requestedCertification: 'Certification',
+ onGoBack: () => {},
+};
+NoSupportedCertifier.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.js b/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.js
deleted file mode 100644
index 653ce3a898..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import RoleSelection from '../../../../containers/RoleSelection';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/RoleSelection',
- decorators: decorators,
- component: RoleSelection,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- onGoBack: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.jsx b/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.jsx
new file mode 100644
index 0000000000..65d820e6b1
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/RoleSelection/Role.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import RoleSelection from '../../../../containers/RoleSelection';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/RoleSelection',
+ decorators: decorators,
+ component: RoleSelection,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ onGoBack: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.js b/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.js
deleted file mode 100644
index e685a9eba6..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { PureSetCertificationSummary } from '../../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/SetCertificationSummary',
- decorators: decorators,
- component: PureSetCertificationSummary,
-};
-
-const Template = (args) => ;
-
-export const RequestedCertifier = Template.bind({});
-RequestedCertifier.args = {
- certificationName: 'Participatory Guarantee System',
- certifierName: 'Certifier',
- isRequestedCertifier: true,
- onGoBack: () => {},
-};
-RequestedCertifier.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SupportedCertifier = Template.bind({});
-SupportedCertifier.args = {
- certificationName: 'Participatory Guarantee System',
- certifierName: 'Supported Certifier',
- isRequestedCertifier: false,
- onGoBack: () => {},
-};
-SupportedCertifier.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.jsx b/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.jsx
new file mode 100644
index 0000000000..509de07a9b
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/SetCertificationSummary/SetCertificationSummary.stories.jsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import {
+ PureSetCertificationSummary,
+} from '../../../../components/OrganicCertifierSurvey/SetCertificationSummary/PureSetCertificationSummary';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/SetCertificationSummary',
+ decorators: decorators,
+ component: PureSetCertificationSummary,
+};
+
+const Template = (args) => ;
+
+export const RequestedCertifier = Template.bind({});
+RequestedCertifier.args = {
+ certificationName: 'Participatory Guarantee System',
+ certifierName: 'Certifier',
+ isRequestedCertifier: true,
+ onGoBack: () => {},
+};
+RequestedCertifier.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SupportedCertifier = Template.bind({});
+SupportedCertifier.args = {
+ certificationName: 'Participatory Guarantee System',
+ certifierName: 'Supported Certifier',
+ isRequestedCertifier: false,
+ onGoBack: () => {},
+};
+SupportedCertifier.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.js b/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.js
deleted file mode 100644
index e2b90f4b6f..0000000000
--- a/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import WelcomeScreen from '../../../../components/WelcomeScreen';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Intro/1-WelcomeScreen',
- decorators: decorators,
- component: WelcomeScreen,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.jsx b/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.jsx
new file mode 100644
index 0000000000..fe6da8de56
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Intro/WelcomeScreen/WelcomeScreen.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import WelcomeScreen from '../../../../components/WelcomeScreen';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Intro/1-WelcomeScreen',
+ decorators: decorators,
+ component: WelcomeScreen,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.js b/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.js
deleted file mode 100644
index f77839134b..0000000000
--- a/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import ExpiredTokenScreen from '../../../../components/ExpiredTokenScreen';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Page/ExpiredToken',
- decorators: decorators,
- component: ExpiredTokenScreen,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- text: 'This link has expired. Please ask for a new invite link.',
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const ResetPassword = Template.bind({});
-ResetPassword.args = {
- text: 'This link has expired.',
- linkText: 'Send new password link.',
-};
-ResetPassword.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.jsx b/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.jsx
new file mode 100644
index 0000000000..bacbe61573
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Invitation/ExpiredTokenScreen/ExpiredTokenScreen.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import ExpiredTokenScreen from '../../../../components/ExpiredTokenScreen';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Page/ExpiredToken',
+ decorators: decorators,
+ component: ExpiredTokenScreen,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ text: 'This link has expired. Please ask for a new invite link.',
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const ResetPassword = Template.bind({});
+ResetPassword.args = {
+ text: 'This link has expired.',
+ linkText: 'Send new password link.',
+};
+ResetPassword.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.js b/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.js
deleted file mode 100644
index 5c61cd93da..0000000000
--- a/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureInviteSignup from '../../../../components/InviteSignup';
-import Button from '../../../../components/Form/Button';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Page/PureInviteSignUpScreen',
- decorators: decorators,
- component: PureInviteSignup,
-};
-
-const Template = (args) => ;
-
-export const WithoutError = Template.bind({});
-WithoutError.args = {
- googleButton: Proceed ,
- showError: false,
- selectedKey: 0,
- email: 'example@litefarm.org',
-};
-WithoutError.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SelectGoogle = Template.bind({});
-SelectGoogle.args = {
- googleButton: Proceed ,
- showError: false,
- selectedKey: 1,
- email: 'example@litefarm.org',
-};
-SelectGoogle.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WithError = Template.bind({});
-WithError.args = {
- googleButton: Proceed ,
- showError: true,
- selectedKey: 1,
- email: 'example@litefarm.org',
-};
-SelectGoogle.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WithErrorAndIsNotChrome = Template.bind({});
-WithErrorAndIsNotChrome.args = {
- googleButton: Proceed ,
- showError: true,
- selectedKey: 1,
- email: 'example@litefarm.org',
- isChrome: false,
-};
-WithErrorAndIsNotChrome.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const isNotChrome = Template.bind({});
-isNotChrome.args = {
- googleButton: Proceed ,
- selectedKey: 1,
- email: 'example@litefarm.org',
- isChrome: false,
-};
-isNotChrome.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.jsx b/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.jsx
new file mode 100644
index 0000000000..fa8ac5f1b4
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Invitation/InviteSignUp/PureInviteSignUp.stories.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureInviteSignup from '../../../../components/InviteSignup';
+import Button from '../../../../components/Form/Button';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Page/PureInviteSignUpScreen',
+ decorators: decorators,
+ component: PureInviteSignup,
+};
+
+const Template = (args) => ;
+
+export const WithoutError = Template.bind({});
+WithoutError.args = {
+ googleButton: Proceed ,
+ showError: false,
+ selectedKey: 0,
+ email: 'example@litefarm.org',
+};
+WithoutError.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SelectGoogle = Template.bind({});
+SelectGoogle.args = {
+ googleButton: Proceed ,
+ showError: false,
+ selectedKey: 1,
+ email: 'example@litefarm.org',
+};
+SelectGoogle.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WithError = Template.bind({});
+WithError.args = {
+ googleButton: Proceed ,
+ showError: true,
+ selectedKey: 1,
+ email: 'example@litefarm.org',
+};
+SelectGoogle.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WithErrorAndIsNotChrome = Template.bind({});
+WithErrorAndIsNotChrome.args = {
+ googleButton: Proceed ,
+ showError: true,
+ selectedKey: 1,
+ email: 'example@litefarm.org',
+ isChrome: false,
+};
+WithErrorAndIsNotChrome.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const isNotChrome = Template.bind({});
+isNotChrome.args = {
+ googleButton: Proceed ,
+ selectedKey: 1,
+ email: 'example@litefarm.org',
+ isChrome: false,
+};
+isNotChrome.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.js b/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.js
deleted file mode 100644
index c883b73253..0000000000
--- a/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import { authenticatedDecorators } from '../../config/decorators';
-import PureInvitedUserCreateAccountPage from '../../../../components/InvitedUserCreateAccount';
-
-export default {
- title: 'Form/PureInvitedUserCreateAccountPage',
- decorators: authenticatedDecorators,
- component: PureInvitedUserCreateAccountPage,
-};
-
-const Template = (args) => ;
-
-export const notSSO = Template.bind({});
-notSSO.args = {
- onSubmit: (data) => console.log(data),
- email: 'example@gmail.com',
- name: 'liteFarm',
- title: 'Create your account',
- buttonText: 'Create New Account',
- isNotSSO: true,
-};
-
-export const SSO = Template.bind({});
-SSO.args = {
- onSubmit: (data) => console.log(data),
- email: 'example@gmail.com',
- name: 'liteFarm',
- title: 'Your information',
- buttonText: 'Save',
-};
-
-export const notSSOWithTooltipOpen = Template.bind({});
-notSSOWithTooltipOpen.args = {
- onSubmit: (data) => console.log(data),
- email: 'example@gmail.com',
- name: 'liteFarm',
- title: 'Create your account',
- buttonText: 'Create New Account',
- isNotSSO: true,
- autoOpen: true,
-};
diff --git a/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.jsx b/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.jsx
new file mode 100644
index 0000000000..05e9381753
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Invitation/InvitedUserCreateAccount/InvitedUserCreateAccount.stories.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { authenticatedDecorators } from '../../config/Decorators';
+import PureInvitedUserCreateAccountPage from '../../../../components/InvitedUserCreateAccount';
+
+export default {
+ title: 'Form/PureInvitedUserCreateAccountPage',
+ decorators: authenticatedDecorators,
+ component: PureInvitedUserCreateAccountPage,
+};
+
+const Template = (args) => ;
+
+export const notSSO = Template.bind({});
+notSSO.args = {
+ onSubmit: (data) => console.log(data),
+ email: 'example@gmail.com',
+ name: 'liteFarm',
+ title: 'Create your account',
+ buttonText: 'Create New Account',
+ isNotSSO: true,
+};
+
+export const SSO = Template.bind({});
+SSO.args = {
+ onSubmit: (data) => console.log(data),
+ email: 'example@gmail.com',
+ name: 'liteFarm',
+ title: 'Your information',
+ buttonText: 'Save',
+};
+
+export const notSSOWithTooltipOpen = Template.bind({});
+notSSOWithTooltipOpen.args = {
+ onSubmit: (data) => console.log(data),
+ email: 'example@gmail.com',
+ name: 'liteFarm',
+ title: 'Create your account',
+ buttonText: 'Create New Account',
+ isNotSSO: true,
+ autoOpen: true,
+};
diff --git a/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.js b/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.js
deleted file mode 100644
index 8da4c23bad..0000000000
--- a/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import JoinFarmSuccessScreen from '../../../../components/JoinFarmSuccessScreen';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Page/JoinFarmSuccessScreen',
- decorators: decorators,
- component: JoinFarmSuccessScreen,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- farm_name: 'Data Farm',
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Show_spot_light = Template.bind({});
-Show_spot_light.args = {
- farm_name: 'Data Farm',
- showSpotLight: true,
-};
-Show_spot_light.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.jsx b/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.jsx
new file mode 100644
index 0000000000..363c277ec4
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Invitation/JoinFarmSuccessScreen/ExpiredTokenScreen.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import JoinFarmSuccessScreen from '../../../../components/JoinFarmSuccessScreen';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Page/JoinFarmSuccessScreen',
+ decorators: decorators,
+ component: JoinFarmSuccessScreen,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ farm_name: 'Data Farm',
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Show_spot_light = Template.bind({});
+Show_spot_light.args = {
+ farm_name: 'Data Farm',
+ showSpotLight: true,
+};
+Show_spot_light.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.js b/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.js
deleted file mode 100644
index 4fbec9712c..0000000000
--- a/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PureInviteUser from '../../../components/InviteUser';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/InviteUser',
- decorators: decorators,
- component: PureInviteUser,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- roleOptions: [
- { value: 1, label: 'Farm Owner' },
- { value: 2, label: 'Farm Manager' },
- { value: 3, label: 'Farm Worker' },
- { value: 5, label: 'Extension Officer' },
- ],
- onInvite: (data) => console.log(data),
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.jsx b/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.jsx
new file mode 100644
index 0000000000..3bb9d441ce
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/InviteUser/InviteUserPage.stories.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PureInviteUser from '../../../components/InviteUser';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/InviteUser',
+ decorators: decorators,
+ component: PureInviteUser,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ roleOptions: [
+ { value: 1, label: 'Farm Owner' },
+ { value: 2, label: 'Farm Manager' },
+ { value: 3, label: 'Farm Worker' },
+ { value: 5, label: 'Extension Officer' },
+ ],
+ onInvite: (data) => console.log(data),
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.js
deleted file mode 100644
index 09b6ed6b0c..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react';
-import AreaDetails from '../../../../components/LocationDetailLayout/AreaDetails';
-import decorator from '../../config/decorators';
-import { useForm } from 'react-hook-form';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/AreaDetails',
- decorators: decorator,
- component: AreaDetails,
-};
-
-const Template = (args) => {
- const {
- register,
- watch,
- setValue,
- getValues,
- setError,
- control,
- handleSubmit,
-
- formState: { errors },
- } = useForm({
- mode: 'onChange',
- });
- return (
-
- );
-};
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- name: 'Field',
- title: 'Add field',
- submitForm: (data) => {},
- onError: (data) => {},
- disabled: false,
- register: (data) => {},
- handleSubmit: (data) => {},
- showPerimeter: true,
- setValue: (data) => {},
- getValues: (data) => {},
- setError: (data) => {},
- control: (data) => {},
- history: (data) => {},
- children: (data) => {},
- errors: (data) => {},
- areaType: (data) => {},
- system: 'metric',
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.jsx
new file mode 100644
index 0000000000..811ae927f3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/AreaDetails.stories.jsx
@@ -0,0 +1,65 @@
+import React from 'react';
+import AreaDetails from '../../../../components/LocationDetailLayout/AreaDetails/AreaDetails';
+import decorator from '../../config/Decorators';
+import { useForm } from 'react-hook-form';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/AreaDetails',
+ decorators: decorator,
+ component: AreaDetails,
+};
+
+const Template = (args) => {
+ const {
+ register,
+ watch,
+ setValue,
+ getValues,
+ setError,
+ control,
+ handleSubmit,
+
+ formState: { errors },
+ } = useForm({
+ mode: 'onChange',
+ });
+ return (
+
+ );
+};
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ name: 'Field',
+ title: 'Add field',
+ submitForm: (data) => {},
+ onError: (data) => {},
+ disabled: false,
+ register: (data) => {},
+ handleSubmit: (data) => {},
+ showPerimeter: true,
+ setValue: (data) => {},
+ getValues: (data) => {},
+ setError: (data) => {},
+ control: (data) => {},
+ history: (data) => {},
+ children: (data) => {},
+ errors: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.js
deleted file mode 100644
index d1a41f8586..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import Barn from '../../../../../components/LocationDetailLayout/AreaDetails/Barn';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/Barn',
- decorators: decorator,
- component: Barn,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/barn/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WorkerView = Template.bind({});
-WorkerView.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/barn/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: false,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-WorkerView.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.jsx
new file mode 100644
index 0000000000..eb40857858
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Barn/Barn.stories.jsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import Barn from '../../../../../components/LocationDetailLayout/AreaDetails/Barn';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/Barn',
+ decorators: decorator,
+ component: Barn,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/barn/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WorkerView = Template.bind({});
+WorkerView.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/barn/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: false,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+WorkerView.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.js
deleted file mode 100644
index ee012a6e16..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import CeremonialArea from '../../../../../components/LocationDetailLayout/AreaDetails/CeremonialArea';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/CeremonialArea',
- decorators: decorator,
- component: CeremonialArea,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/ceremonial_area/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.jsx
new file mode 100644
index 0000000000..683d87d6ac
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/CeremonialArea/CeremonialArea.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import CeremonialArea from '../../../../../components/LocationDetailLayout/AreaDetails/CeremonialArea';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/CeremonialArea',
+ decorators: decorator,
+ component: CeremonialArea,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/ceremonial_area/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.js
deleted file mode 100644
index f169f38fe7..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import FarmSiteBoundary from '../../../../../components/LocationDetailLayout/AreaDetails/FarmSiteBoundary';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/FarmSiteBoundary',
- decorators: decorator,
- component: FarmSiteBoundary,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/farm_site_boundary/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.jsx
new file mode 100644
index 0000000000..373b3232db
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/FarmSiteBoundary/FarmSiteBoundary.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import FarmSiteBoundary from '../../../../../components/LocationDetailLayout/AreaDetails/FarmSiteBoundary';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/FarmSiteBoundary',
+ decorators: decorator,
+ component: FarmSiteBoundary,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/farm_site_boundary/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.js
deleted file mode 100644
index 849ec7f088..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import Field from '../../../../../components/LocationDetailLayout/AreaDetails/Field';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/Field',
- decorators: decorator,
- component: Field,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/field/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.jsx
new file mode 100644
index 0000000000..3cb75b2324
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Field/Field.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Field from '../../../../../components/LocationDetailLayout/AreaDetails/Field';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/Field',
+ decorators: decorator,
+ component: Field,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/field/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.js
deleted file mode 100644
index 3680da5f26..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import Garden from '../../../../../components/LocationDetailLayout/AreaDetails/Garden';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/Garden',
- decorators: decorator,
- component: Garden,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/garden/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.jsx
new file mode 100644
index 0000000000..0fd3b7087f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Garden/Garden.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Garden from '../../../../../components/LocationDetailLayout/AreaDetails/Garden';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/Garden',
+ decorators: decorator,
+ component: Garden,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/garden/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.js
deleted file mode 100644
index 90963407d0..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import Greenhouse from '../../../../../components/LocationDetailLayout/AreaDetails/Greenhouse';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/Greenhouse',
- decorators: decorator,
- component: Greenhouse,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/greenhouse/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.jsx
new file mode 100644
index 0000000000..40c33826dd
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Greenhouse/Greenhouse.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Greenhouse from '../../../../../components/LocationDetailLayout/AreaDetails/Greenhouse';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/Greenhouse',
+ decorators: decorator,
+ component: Greenhouse,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/greenhouse/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.js
deleted file mode 100644
index f5fe7140b4..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import NaturalArea from '../../../../../components/LocationDetailLayout/AreaDetails/NaturalArea';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/NaturalArea',
- decorators: decorator,
- component: NaturalArea,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/natural_area/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.jsx
new file mode 100644
index 0000000000..04c1e0a32b
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/NaturalArea/NaturalArea.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import NaturalArea from '../../../../../components/LocationDetailLayout/AreaDetails/NaturalArea';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/NaturalArea',
+ decorators: decorator,
+ component: NaturalArea,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/natural_area/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.js
deleted file mode 100644
index b37818e2db..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import Residence from '../../../../../components/LocationDetailLayout/AreaDetails/Residence';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/Residence',
- decorators: decorator,
- component: Residence,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/residence/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.jsx
new file mode 100644
index 0000000000..7e864a3c5f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/Residence/Residence.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import Residence from '../../../../../components/LocationDetailLayout/AreaDetails/Residence';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/Residence',
+ decorators: decorator,
+ component: Residence,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/residence/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.js
deleted file mode 100644
index 596db37a31..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import React from 'react';
-import SurfaceWater from '../../../../../components/LocationDetailLayout/AreaDetails/SurfaceWater';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Area/SurfaceWater',
- decorators: decorator,
- component: SurfaceWater,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- areaType: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/surface_water/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.jsx
new file mode 100644
index 0000000000..01df1bda26
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/AreaDetails/SurfaceWater/SurfaceWater.stories.jsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import SurfaceWater from '../../../../../components/LocationDetailLayout/AreaDetails/SurfaceWater';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Area/SurfaceWater',
+ decorators: decorator,
+ component: SurfaceWater,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ areaType: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/surface_water/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.js
deleted file mode 100644
index 061c126213..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import BufferZone from '../../../../../components/LocationDetailLayout/LineDetails/BufferZone';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Line/BufferZone',
- decorators: decorator,
- component: BufferZone,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, width: 1, length: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/buffer_zone/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.jsx
new file mode 100644
index 0000000000..371de306a7
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/BufferZone/BufferZone.stories.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import BufferZone from '../../../../../components/LocationDetailLayout/LineDetails/BufferZone';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Line/BufferZone',
+ decorators: decorator,
+ component: BufferZone,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, width: 1, length: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/buffer_zone/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.js
deleted file mode 100644
index 17c0c09f01..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from 'react';
-import Fence from '../../../../../components/LocationDetailLayout/LineDetails/Fence';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Line/Fence',
- decorators: decorator,
- component: Fence,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, width: 1, length: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/fence/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.jsx
new file mode 100644
index 0000000000..b7b6202597
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Fence/Fence.stories.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import Fence from '../../../../../components/LocationDetailLayout/LineDetails/Fence';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Line/Fence',
+ decorators: decorator,
+ component: Fence,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, width: 1, length: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/fence/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.js
deleted file mode 100644
index 5892ec2686..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import LineDetails from '../../../../components/LocationDetailLayout/LineDetails';
-import decorator from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Location/Line/LineDetails',
- decorators: decorator,
- component: LineDetails,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- name: 'Fence',
- title: 'Add fence',
- submitForm: (data) => {},
- children: (data) => {},
- setValue: (data) => {},
- handleSubmit: (data) => {},
- history: (data) => {},
- onError: (data) => {},
- register: (data) => {},
- disabled: false,
- errors: (data) => {},
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.jsx
new file mode 100644
index 0000000000..3a75f59102
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/LineDetails.stories.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import LineDetails from '../../../../components/LocationDetailLayout/LineDetails/LineDetails';
+import decorator from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Line/LineDetails',
+ decorators: decorator,
+ component: LineDetails,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ name: 'Fence',
+ title: 'Add fence',
+ submitForm: (data) => {},
+ children: (data) => {},
+ setValue: (data) => {},
+ handleSubmit: (data) => {},
+ history: (data) => {},
+ onError: (data) => {},
+ register: (data) => {},
+ disabled: false,
+ errors: (data) => {},
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.js
deleted file mode 100644
index 85e8cc40f6..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import Watercourse from '../../../../../components/LocationDetailLayout/LineDetails/Watercourse';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Line/Watercourse',
- decorators: decorator,
- component: Watercourse,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- history: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, width: 1, length: 2 },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/watercourse/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.jsx
new file mode 100644
index 0000000000..f8f417171e
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/LineDetails/Watercourse/Watercourse.stories.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import Watercourse from '../../../../../components/LocationDetailLayout/LineDetails/Watercourse';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Line/Watercourse',
+ decorators: decorator,
+ component: Watercourse,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ history: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, width: 1, length: 2 },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/watercourse/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.js
deleted file mode 100644
index a2aeef41bf..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from 'react';
-import Gate from '../../../../../components/LocationDetailLayout/PointDetails/Gate';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Point/Gate',
- decorators: decorator,
- component: Gate,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- useHookFormPersist: () => ({
- persistedData: { point: {}, type: 'type' },
- }),
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/gate/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.jsx
new file mode 100644
index 0000000000..98b948d2e3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/Gate/Gate.stories.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import Gate from '../../../../../components/LocationDetailLayout/PointDetails/Gate';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Point/Gate',
+ decorators: decorator,
+ component: Gate,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ useHookFormPersist: () => ({
+ persistedData: { point: {}, type: 'type' },
+ }),
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/gate/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.js
deleted file mode 100644
index 2f7fbb46f4..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import PointDetails from '../../../../components/LocationDetailLayout/PointDetails';
-import decorator from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Location/Point/PointDetails',
- decorators: decorator,
- component: PointDetails,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- name: 'Gate',
- title: 'Add gate',
- submitForm: (data) => {},
- children: (data) => {},
- setValue: (data) => {},
- handleSubmit: (data) => {},
- history: (data) => {},
- onError: (data) => {},
- register: (data) => {},
- disabled: false,
- errors: (data) => {},
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.jsx
new file mode 100644
index 0000000000..76c2fc7d03
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/PointDetails.stories.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import PointDetails from '../../../../components/LocationDetailLayout/PointDetails/PointDetails';
+import decorator from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Point/PointDetails',
+ decorators: decorator,
+ component: PointDetails,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ name: 'Gate',
+ title: 'Add gate',
+ submitForm: (data) => {},
+ children: (data) => {},
+ setValue: (data) => {},
+ handleSubmit: (data) => {},
+ history: (data) => {},
+ onError: (data) => {},
+ register: (data) => {},
+ disabled: false,
+ errors: (data) => {},
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.js b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.js
deleted file mode 100644
index 40a8081aff..0000000000
--- a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import WaterValve from '../../../../../components/LocationDetailLayout/PointDetails/WaterValve';
-import decorator from '../../../config/decorators';
-import { chromaticSmallScreen } from '../../../config/chromatic';
-
-export default {
- title: 'Form/Location/Point/WaterValve',
- decorators: decorator,
- component: WaterValve,
-};
-
-const Template = (args) => ;
-
-export const Post = Template.bind({});
-Post.args = {
- isCreateLocationPage: true,
- useHookFormPersist: () => ({
- persistedData: { point: {}, type: 'type' },
- }),
- system: 'imperial',
-};
-Post.parameters = {
- ...chromaticSmallScreen,
-};
-export const View = Template.bind({});
-View.args = {
- isViewLocationPage: true,
- history: { location: { pathname: '/water_valve/location_id/details' } },
- match: { params: { location_id: 'location_id' } },
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-View.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Edit = Template.bind({});
-Edit.args = {
- isEditLocationPage: true,
- submitForm: (data) => {},
- system: 'metric',
- isAdmin: true,
- useHookFormPersist: () => ({
- persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
- }),
-};
-Edit.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.jsx b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.jsx
new file mode 100644
index 0000000000..52ce94b629
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/LocationDetails/PointDetails/WaterValve/WaterValve.stories.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import WaterValve from '../../../../../components/LocationDetailLayout/PointDetails/WaterValve';
+import decorator from '../../../config/Decorators';
+import { chromaticSmallScreen } from '../../../config/chromatic';
+
+export default {
+ title: 'Form/Location/Point/WaterValve',
+ decorators: decorator,
+ component: WaterValve,
+};
+
+const Template = (args) => ;
+
+export const Post = Template.bind({});
+Post.args = {
+ isCreateLocationPage: true,
+ useHookFormPersist: () => ({
+ persistedData: { point: {}, type: 'type' },
+ }),
+ system: 'imperial',
+};
+Post.parameters = {
+ ...chromaticSmallScreen,
+};
+export const View = Template.bind({});
+View.args = {
+ isViewLocationPage: true,
+ history: { location: { pathname: '/water_valve/location_id/details' } },
+ match: { params: { location_id: 'location_id' } },
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+View.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Edit = Template.bind({});
+Edit.args = {
+ isEditLocationPage: true,
+ submitForm: (data) => {},
+ system: 'metric',
+ isAdmin: true,
+ useHookFormPersist: () => ({
+ persistedData: { grid_points: {}, total_area: 1, perimeter: 2 },
+ }),
+};
+Edit.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.js
deleted file mode 100644
index 8ff813d9e8..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import React from 'react';
-import PureBedPlan from '../../../components/Crop/BedPlan/PureBedPlan';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/BedPlan',
- component: PureBedPlan,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- history: {},
- system: 'metric',
- crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: {},
- },
- },
- },
- isFinalPage: true,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Final = Template.bind({});
-Final.args = {
- history: {},
- system: 'metric',
- crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: {
- bed_method: {
- number_of_beds: 10,
- number_of_rows_in_bed: 10,
- bed_length: 10,
- plant_spacing: 10,
- },
- },
- },
- },
- },
- isFinalPage: true,
-};
-Final.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Historical = Template.bind({});
-Historical.args = {
- history: {},
- system: 'metric',
- crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- initial: {
- bed_method: {
- number_of_beds: 10,
- number_of_rows_in_bed: 10,
- bed_length: 10,
- plant_spacing: 10,
- },
- },
- },
- },
- },
- isFinalPage: false,
-};
-Historical.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.jsx
new file mode 100644
index 0000000000..ff16846614
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/BedPlanting.stories.jsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import PureBedPlan from '../../../components/Crop/BedPlan/PureBedPlan';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/BedPlan',
+ component: PureBedPlan,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ history: {},
+ system: 'metric',
+ crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: {},
+ },
+ },
+ },
+ isFinalPage: true,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Final = Template.bind({});
+Final.args = {
+ history: {},
+ system: 'metric',
+ crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: {
+ bed_method: {
+ number_of_beds: 10,
+ number_of_rows_in_bed: 10,
+ bed_length: 10,
+ plant_spacing: 10,
+ },
+ },
+ },
+ },
+ },
+ isFinalPage: true,
+};
+Final.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Historical = Template.bind({});
+Historical.args = {
+ history: {},
+ system: 'metric',
+ crop_variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ initial: {
+ bed_method: {
+ number_of_beds: 10,
+ number_of_rows_in_bed: 10,
+ bed_length: 10,
+ plant_spacing: 10,
+ },
+ },
+ },
+ },
+ },
+ isFinalPage: false,
+};
+Historical.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.js
deleted file mode 100644
index 5aa4c6ff10..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.js
+++ /dev/null
@@ -1,99 +0,0 @@
-import React from 'react';
-import PureBroadcastPlan from '../../../components/Crop/BroadcastPlan';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/BroadcastPlan',
- component: PureBroadcastPlan,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- initial: {
- broadcast_method: {},
- },
- },
- },
- },
- system: 'metric',
- locationSize: 2000,
- yieldPerArea: 30,
- isFinalPage: true,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Final = Template.bind({});
-Final.args = {
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: {
- broadcast_method: {
- percentage_planted: 10,
- seeding_rate: 2,
- },
- },
- },
- },
- },
- system: 'metric',
- locationSize: 2000,
- yieldPerArea: 30,
- isFinalPage: true,
-};
-Final.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalInitial = Template.bind({});
-HistoricalInitial.args = {
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: true,
- },
- },
- system: 'metric',
- locationSize: 2000,
- yieldPerArea: 30,
- isFinalPage: false,
-};
-
-HistoricalInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalFinal = Template.bind({});
-HistoricalFinal.args = {
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: false,
- },
- },
- system: 'metric',
- locationSize: 2000,
- yieldPerArea: 30,
- isFinalPage: true,
-};
-
-HistoricalFinal.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.jsx
new file mode 100644
index 0000000000..a0ca30bb6f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/BroadcastPlanting.stories.jsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import PureBroadcastPlan from '../../../components/Crop/BroadcastPlan';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/BroadcastPlan',
+ component: PureBroadcastPlan,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ initial: {
+ broadcast_method: {},
+ },
+ },
+ },
+ },
+ system: 'metric',
+ locationSize: 2000,
+ yieldPerArea: 30,
+ isFinalPage: true,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Final = Template.bind({});
+Final.args = {
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: {
+ broadcast_method: {
+ percentage_planted: 10,
+ seeding_rate: 2,
+ },
+ },
+ },
+ },
+ },
+ system: 'metric',
+ locationSize: 2000,
+ yieldPerArea: 30,
+ isFinalPage: true,
+};
+Final.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalInitial = Template.bind({});
+HistoricalInitial.args = {
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: true,
+ },
+ },
+ system: 'metric',
+ locationSize: 2000,
+ yieldPerArea: 30,
+ isFinalPage: false,
+};
+
+HistoricalInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalFinal = Template.bind({});
+HistoricalFinal.args = {
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: false,
+ },
+ },
+ system: 'metric',
+ locationSize: 2000,
+ yieldPerArea: 30,
+ isFinalPage: true,
+};
+
+HistoricalFinal.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.js
deleted file mode 100644
index 4654ca8360..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import { PureCompleteManagementPlan } from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/PureCompleteManagementPlan',
- decorators: decorators,
- component: PureCompleteManagementPlan,
-};
-
-const Template = (args) => ;
-
-export const Complete = Template.bind({});
-Complete.args = {
- crop_variety: {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Blueberry 1',
- supplier: 'supplier',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
- },
- onSubmit: (data) => console.log(data),
- start_date: '2021-08-01',
-};
-Complete.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Abandon = Template.bind({});
-Abandon.args = {
- crop_variety: {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Blueberry 1',
- supplier: 'supplier',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
- },
- isAbandonPage: true,
- onSubmit: (data) => console.log(data),
- reasonOptions: [
- { label: 'reason1', value: 'reason1' },
- { label: 'reason1', value: 'reason2' },
- ],
-};
-Abandon.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.jsx
new file mode 100644
index 0000000000..93fe119c08
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/CompleteManagementPlan.stories.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import {
+ PureCompleteManagementPlan,
+} from '../../../components/Crop/CompleteManamgenentPlan/PureCompleteManagementPlan';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/PureCompleteManagementPlan',
+ decorators: decorators,
+ component: PureCompleteManagementPlan,
+};
+
+const Template = (args) => ;
+
+export const Complete = Template.bind({});
+Complete.args = {
+ crop_variety: {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Blueberry 1',
+ supplier: 'supplier',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+ },
+ onSubmit: (data) => console.log(data),
+ start_date: '2021-08-01',
+};
+Complete.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Abandon = Template.bind({});
+Abandon.args = {
+ crop_variety: {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Blueberry 1',
+ supplier: 'supplier',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+ },
+ isAbandonPage: true,
+ onSubmit: (data) => console.log(data),
+ reasonOptions: [
+ { label: 'reason1', value: 'reason1' },
+ { label: 'reason1', value: 'reason2' },
+ ],
+};
+Abandon.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.js
deleted file mode 100644
index dad4583835..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import React from 'react';
-import PureCropManagement from '../../../components/Crop/management';
-import decorator from '../config/decorators';
-import { Abandoned, Active, Completed, Planned } from '../../Card/ManagementPlanCard.stories';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Crop/Management',
- component: PureCropManagement,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-const managementPlanCardContents = [Active.args, Planned.args, Abandoned.args, Completed.args];
-
-const getManagementPlanCardContents = (numberOfCards) =>
- Array.from({ length: numberOfCards }, (_, index) => {
- return managementPlanCardContents[index % 4];
- });
-
-export const Management = Template.bind({});
-Management.args = {
- history: {
- location: { pathname: '/crop/variety_id/management' },
- },
- match: {
- params: {
- variety_id: 'variety_id',
- },
- },
- variety: {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Nantes',
- supplier: 'Buckerfields',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
- },
-};
-Management.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const ManagementWithOneCard = Template.bind({});
-ManagementWithOneCard.args = {
- history: {
- location: { pathname: '/crop/variety_id/management' },
- },
- match: {
- params: {
- variety_id: 'variety_id',
- },
- },
- variety: {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Nantes',
- supplier: 'Buckerfields',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
- },
- managementPlanCardContents: [managementPlanCardContents[0]],
-};
-ManagementWithOneCard.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const ManagementWithManyCards = Template.bind({});
-ManagementWithManyCards.args = {
- history: {
- location: { pathname: '/crop/variety_id/management' },
- },
- match: {
- params: {
- variety_id: 'variety_id',
- },
- },
- variety: {
- crop_translation_key: 'Blueberry',
- crop_variety_name: 'Nantes',
- supplier: 'Buckerfields',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
- },
- managementPlanCardContents: getManagementPlanCardContents(100),
-};
-ManagementWithManyCards.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.jsx
new file mode 100644
index 0000000000..275d9b0375
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/CropManagement.stories.jsx
@@ -0,0 +1,88 @@
+import React from 'react';
+import PureCropManagement from '../../../components/Crop/Management';
+import decorator from '../config/Decorators';
+import { Abandoned, Active, Completed, Planned } from '../../Card/ManagementPlanCard.stories';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Crop/Management',
+ component: PureCropManagement,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+const managementPlanCardContents = [Active.args, Planned.args, Abandoned.args, Completed.args];
+
+const getManagementPlanCardContents = (numberOfCards) =>
+ Array.from({ length: numberOfCards }, (_, index) => {
+ return managementPlanCardContents[index % 4];
+ });
+
+export const Management = Template.bind({});
+Management.args = {
+ history: {
+ location: { pathname: '/crop/variety_id/management' },
+ },
+ match: {
+ params: {
+ variety_id: 'variety_id',
+ },
+ },
+ variety: {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Nantes',
+ supplier: 'Buckerfields',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+ },
+};
+Management.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const ManagementWithOneCard = Template.bind({});
+ManagementWithOneCard.args = {
+ history: {
+ location: { pathname: '/crop/variety_id/management' },
+ },
+ match: {
+ params: {
+ variety_id: 'variety_id',
+ },
+ },
+ variety: {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Nantes',
+ supplier: 'Buckerfields',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+ },
+ managementPlanCardContents: [managementPlanCardContents[0]],
+};
+ManagementWithOneCard.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const ManagementWithManyCards = Template.bind({});
+ManagementWithManyCards.args = {
+ history: {
+ location: { pathname: '/crop/variety_id/management' },
+ },
+ match: {
+ params: {
+ variety_id: 'variety_id',
+ },
+ },
+ variety: {
+ crop_translation_key: 'Blueberry',
+ crop_variety_name: 'Nantes',
+ supplier: 'Buckerfields',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/blueberry.webp',
+ },
+ managementPlanCardContents: getManagementPlanCardContents(100),
+};
+ManagementWithManyCards.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.js
deleted file mode 100644
index 8cab068dee..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.js
+++ /dev/null
@@ -1,102 +0,0 @@
-import React from 'react';
-import PureManagementTasks from '../../../components/Crop/ManagementDetail/ManagementPlanTasks';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/ManagementTasks',
- decorators: decorators,
- component: PureManagementTasks,
-};
-
-const Template = (args) => ;
-
-export const IsAdmin = Template.bind({});
-IsAdmin.args = {
- onBack: () => {},
- onCompleted: () => {},
- variety: {
- crop_translation_key: 'Crop',
- crop_variety_name: 'Variety',
- crop_variety_photo_url: '',
- supplier: 'Supplier',
- },
- plan: {
- name: 'name',
- notes: 'notes',
- },
- isAdmin: true,
- match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
- history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
-};
-IsAdmin.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const IsNotAdmin = Template.bind({});
-IsNotAdmin.args = {
- onBack: () => {},
- onCompleted: () => {},
- variety: {
- crop_translation_key: 'Crop',
- crop_variety_name: 'Variety',
- crop_variety_photo_url: '',
- supplier: 'Supplier',
- },
- plan: {
- name: 'name',
- notes: 'notes',
- },
- isAdmin: false,
- match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
- history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
-};
-IsNotAdmin.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Completed = Template.bind({});
-Completed.args = {
- onBack: () => {},
- onCompleted: () => {},
- variety: {
- crop_translation_key: 'Crop',
- crop_variety_name: 'Variety',
- crop_variety_photo_url: '',
- supplier: 'Supplier',
- },
- plan: {
- name: 'name',
- notes: 'notes',
- complete_date: '2020-01-01',
- },
- isAdmin: true,
- match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
- history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
-};
-Completed.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Abandoned = Template.bind({});
-Abandoned.args = {
- onBack: () => {},
- onCompleted: () => {},
- variety: {
- crop_translation_key: 'Crop',
- crop_variety_name: 'Variety',
- crop_variety_photo_url: '',
- supplier: 'Supplier',
- },
- plan: {
- name: 'name',
- notes: 'notes',
- abandon_date: '2020-01-01',
- },
- isAdmin: true,
- match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
- history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
-};
-Abandoned.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.jsx
new file mode 100644
index 0000000000..fe7f526eb0
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanDetail.stories.jsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import PureManagementTasks from '../../../components/Crop/ManagementDetail/ManagementPlanTasks';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/ManagementTasks',
+ decorators: decorators,
+ component: PureManagementTasks,
+};
+
+const Template = (args) => ;
+
+export const IsAdmin = Template.bind({});
+IsAdmin.args = {
+ onBack: () => {},
+ onCompleted: () => {},
+ variety: {
+ crop_translation_key: 'Crop',
+ crop_variety_name: 'Variety',
+ crop_variety_photo_url: '',
+ supplier: 'Supplier',
+ },
+ plan: {
+ name: 'name',
+ notes: 'notes',
+ },
+ isAdmin: true,
+ match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
+ history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
+};
+IsAdmin.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const IsNotAdmin = Template.bind({});
+IsNotAdmin.args = {
+ onBack: () => {},
+ onCompleted: () => {},
+ variety: {
+ crop_translation_key: 'Crop',
+ crop_variety_name: 'Variety',
+ crop_variety_photo_url: '',
+ supplier: 'Supplier',
+ },
+ plan: {
+ name: 'name',
+ notes: 'notes',
+ },
+ isAdmin: false,
+ match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
+ history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
+};
+IsNotAdmin.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Completed = Template.bind({});
+Completed.args = {
+ onBack: () => {},
+ onCompleted: () => {},
+ variety: {
+ crop_translation_key: 'Crop',
+ crop_variety_name: 'Variety',
+ crop_variety_photo_url: '',
+ supplier: 'Supplier',
+ },
+ plan: {
+ name: 'name',
+ notes: 'notes',
+ complete_date: '2020-01-01',
+ },
+ isAdmin: true,
+ match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
+ history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
+};
+Completed.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Abandoned = Template.bind({});
+Abandoned.args = {
+ onBack: () => {},
+ onCompleted: () => {},
+ variety: {
+ crop_translation_key: 'Crop',
+ crop_variety_name: 'Variety',
+ crop_variety_photo_url: '',
+ supplier: 'Supplier',
+ },
+ plan: {
+ name: 'name',
+ notes: 'notes',
+ abandon_date: '2020-01-01',
+ },
+ isAdmin: true,
+ match: { params: { variety_id: 'variety_id', management_plan_id: 'management_plan_id' } },
+ history: { location: { pathname: '/crop/variety_id/management_plan/management_plan_id/tasks' } },
+};
+Abandoned.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.js
deleted file mode 100644
index 34a258950d..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import ManagementPlanName from '../../../components/Crop/ManagementPlanName';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/ManagementPlanName',
- decorators: decorators,
- component: ManagementPlanName,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- persistedFormData: {
- crop_management_plan: { planting_management_plans: { final: {}, initial: {} } },
- },
- managementPlanCount: 10,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.jsx
new file mode 100644
index 0000000000..13f20eac5a
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/ManagementPlanName.stories.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import ManagementPlanName from '../../../components/Crop/ManagementPlanName';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/ManagementPlanName',
+ decorators: decorators,
+ component: ManagementPlanName,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ persistedFormData: {
+ crop_management_plan: { planting_management_plans: { final: {}, initial: {} } },
+ },
+ managementPlanCount: 10,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.js
deleted file mode 100644
index 5eb284035a..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import PureNextHarvest from '../../../components/Crop/PlantingDate/NextHarvest';
-import decorators from '../config/decorators';
-
-export default {
- title: 'Form/ManagementPlan/NextHarvest',
- component: PureNextHarvest,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const Management = Template.bind({});
-Management.args = {
- useHookFormPersist: () => {},
- persistedFormData: { crop_management_plan: {} },
- system: 'metric',
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.jsx
new file mode 100644
index 0000000000..9bf757cbd6
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/NextHarvest.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import PureNextHarvest from '../../../components/Crop/PlantingDate/NextHarvest';
+import decorators from '../config/Decorators';
+
+export default {
+ title: 'Form/ManagementPlan/NextHarvest',
+ component: PureNextHarvest,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const Management = Template.bind({});
+Management.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: { crop_management_plan: {} },
+ system: 'metric',
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.js
deleted file mode 100644
index eb3affb559..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import React from 'react';
-import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
-import decorators from '../config/decorators';
-
-export default {
- title: 'Form/ManagementPlan/PlanGuidance',
- component: PurePlanGuidance,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const HistoricalBeds = Template.bind({});
-HistoricalBeds.args = {
- system: 'metric',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- initial: { bed_method: { bed_spacing: 10 } },
- },
- },
- },
- isFinalPage: false,
- isBed: true,
-};
-
-export const FinalRows = Template.bind({});
-FinalRows.args = {
- system: 'metric',
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: { row_method: { row_spacing: 10 } },
- },
- },
- },
- isFinalPage: true,
- isBed: false,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.jsx
new file mode 100644
index 0000000000..f971c0bfc6
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/PlanGuidance.stories.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import PurePlanGuidance from '../../../components/Crop/BedPlan/PurePlanGuidance';
+import decorators from '../config/Decorators';
+
+export default {
+ title: 'Form/ManagementPlan/PlanGuidance',
+ component: PurePlanGuidance,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const HistoricalBeds = Template.bind({});
+HistoricalBeds.args = {
+ system: 'metric',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ initial: { bed_method: { bed_spacing: 10 } },
+ },
+ },
+ },
+ isFinalPage: false,
+ isBed: true,
+};
+
+export const FinalRows = Template.bind({});
+FinalRows.args = {
+ system: 'metric',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: { row_method: { row_spacing: 10 } },
+ },
+ },
+ },
+ isFinalPage: true,
+ isBed: false,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.js
deleted file mode 100644
index ca248740b4..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.js
+++ /dev/null
@@ -1,173 +0,0 @@
-import React from 'react';
-import PurePlantInContainer from '../../../components/Crop/PlantInContainer';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/PurePlantInContainer',
- decorators: decorators,
- component: PurePlantInContainer,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: { already_in_ground: false, planting_management_plans: { final: {} } },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: true,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const FinalContainer = Template.bind({});
-FinalContainer.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- planting_management_plans: {
- final: {
- container_method: {
- planting_depth: 0.99,
- number_of_containers: 10,
- plants_per_container: 10,
- in_ground: false,
- },
- },
- },
- },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: true,
-};
-FinalContainer.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const FinalInGround = Template.bind({});
-FinalInGround.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- planting_management_plans: {
- final: { container_method: { plant_spacing: 1, total_plants: 3, in_ground: true } },
- },
- },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: true,
-};
-FinalInGround.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InitialContainer = Template.bind({});
-InitialContainer.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- planting_management_plans: {
- initial: {
- container_method: {
- planting_depth: 0.99,
- number_of_containers: 10,
- plants_per_container: 10,
- in_ground: false,
- },
- },
- },
- },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: false,
-};
-InitialContainer.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalInitial = Template.bind({});
-HistoricalInitial.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- container_method: {
- plant_spacing: 1,
- total_plants: 3,
- in_ground: true,
- },
- },
- },
- },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: false,
-};
-HistoricalInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalFinal = Template.bind({});
-HistoricalFinal.args = {
- useHookFormPersist: () => ({}),
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- container_method: {
- plant_spacing: 1,
- total_plants: 3,
- in_ground: true,
- },
- },
- },
- },
- },
- system: 'metric',
- crop_variety: {
- average_seed_weight: 10,
- yield_per_plant: 10,
- crop_variety_id: 'crop_variety_id',
- },
- isFinalPage: true,
-};
-HistoricalFinal.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.jsx
new file mode 100644
index 0000000000..35e536fde3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/PlantInContainer.stories.jsx
@@ -0,0 +1,173 @@
+import React from 'react';
+import PurePlantInContainer from '../../../components/Crop/PlantInContainer';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/PurePlantInContainer',
+ decorators: decorators,
+ component: PurePlantInContainer,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: { already_in_ground: false, planting_management_plans: { final: {} } },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: true,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const FinalContainer = Template.bind({});
+FinalContainer.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ planting_management_plans: {
+ final: {
+ container_method: {
+ planting_depth: 0.99,
+ number_of_containers: 10,
+ plants_per_container: 10,
+ in_ground: false,
+ },
+ },
+ },
+ },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: true,
+};
+FinalContainer.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const FinalInGround = Template.bind({});
+FinalInGround.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ planting_management_plans: {
+ final: { container_method: { plant_spacing: 1, total_plants: 3, in_ground: true } },
+ },
+ },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: true,
+};
+FinalInGround.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InitialContainer = Template.bind({});
+InitialContainer.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ planting_management_plans: {
+ initial: {
+ container_method: {
+ planting_depth: 0.99,
+ number_of_containers: 10,
+ plants_per_container: 10,
+ in_ground: false,
+ },
+ },
+ },
+ },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: false,
+};
+InitialContainer.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalInitial = Template.bind({});
+HistoricalInitial.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ container_method: {
+ plant_spacing: 1,
+ total_plants: 3,
+ in_ground: true,
+ },
+ },
+ },
+ },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: false,
+};
+HistoricalInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalFinal = Template.bind({});
+HistoricalFinal.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ container_method: {
+ plant_spacing: 1,
+ total_plants: 3,
+ in_ground: true,
+ },
+ },
+ },
+ },
+ },
+ system: 'metric',
+ crop_variety: {
+ average_seed_weight: 10,
+ yield_per_plant: 10,
+ crop_variety_id: 'crop_variety_id',
+ },
+ isFinalPage: true,
+};
+HistoricalFinal.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.js
deleted file mode 100644
index 23f7382370..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import PurePlantedAlready from '../../../components/Crop/PlantedAlready';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/PlantedAlready',
- component: PurePlantedAlready,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const Seedling = Template.bind({});
-
-Seedling.args = {
- persistedFormData: {
- crop_management_plan: {
- seed_date: '2021-07-21',
- already_in_ground: false,
- is_seed: false,
- },
- },
- useHookFormPersist: () => {},
- system: 'metric',
- cropVariety: {
- needs_transplant: true,
- can_be_cover_crop: true,
- crop_variety_id: 'crop_variety_id',
- },
-};
-Seedling.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const WildCrop = Template.bind({});
-WildCrop.args = {
- persistedFormData: {
- crop_management_plan: {
- seed_date: '2021-07-20',
- already_in_ground: true,
- is_wild: true,
- },
- },
- useHookFormPersist: () => {},
- system: 'imperial',
- cropVariety: {
- needs_transplant: false,
- can_be_cover_crop: false,
- crop_variety_id: 'crop_variety_id',
- },
-};
-WildCrop.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.jsx
new file mode 100644
index 0000000000..0e8a93777b
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/PlantedAlready.stories.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import PurePlantedAlready from '../../../components/Crop/PlantedAlready';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/PlantedAlready',
+ component: PurePlantedAlready,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const Seedling = Template.bind({});
+
+Seedling.args = {
+ persistedFormData: {
+ crop_management_plan: {
+ seed_date: '2021-07-21',
+ already_in_ground: false,
+ is_seed: false,
+ },
+ },
+ useHookFormPersist: () => ({}),
+ system: 'metric',
+ cropVariety: {
+ needs_transplant: true,
+ can_be_cover_crop: true,
+ crop_variety_id: 'crop_variety_id',
+ },
+};
+Seedling.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const WildCrop = Template.bind({});
+WildCrop.args = {
+ persistedFormData: {
+ crop_management_plan: {
+ seed_date: '2021-07-20',
+ already_in_ground: true,
+ is_wild: true,
+ },
+ },
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ cropVariety: {
+ needs_transplant: false,
+ can_be_cover_crop: false,
+ crop_variety_id: 'crop_variety_id',
+ },
+};
+WildCrop.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.js
deleted file mode 100644
index 571af9ea07..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.js
+++ /dev/null
@@ -1,462 +0,0 @@
-import React from 'react';
-import PurePlantingOrHarvestDate from '../../../components/Crop/PlantingDate/PurePlantingOrHarvestDate';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/PlantingDate',
- decorators: decorators,
- component: PurePlantingOrHarvestDate,
-};
-
-const Template = (args) => ;
-
-const defaultDates = {
- seed_date: '2021-07-20',
- plant_date: '2021-07-21',
- germination_date: '2021-07-22',
- transplant_date: '2021-07-23',
- termination_date: '2021-07-24',
- harvest_date: '2021-07-25',
- germination_days: 2,
- transplant_days: 3,
- termination_days: 4,
- harvest_days: 5,
-};
-
-export const SeedForHarvestTransplant = Template.bind({});
-SeedForHarvestTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: true,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedForHarvestTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedCoverCropTransplant = Template.bind({});
-SeedCoverCropTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: true,
- for_cover: true,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedCoverCropTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedForHarvestNoTransplant = Template.bind({});
-SeedForHarvestNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: true,
- for_cover: false,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedForHarvestNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedCoverCropNoTransplant = Template.bind({});
-SeedCoverCropNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: true,
- for_cover: true,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedCoverCropNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingForHarvestTransplant = Template.bind({});
-SeedlingForHarvestTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedlingForHarvestTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingCoverCropTransplant = Template.bind({});
-SeedlingCoverCropTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: true,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedlingCoverCropTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingForHarvestNoTransplant = Template.bind({});
-SeedlingForHarvestNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedlingForHarvestNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingCoverCropNoTransplant = Template.bind({});
-SeedlingCoverCropNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: true,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-SeedlingCoverCropNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestTransplant = Template.bind({});
-InGroundNotWildHarvestTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: false,
- is_seed: undefined,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundNotWildHarvestTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropTransplant = Template.bind({});
-InGroundNotWildCoverCropTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: false,
- is_seed: undefined,
- for_cover: true,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundNotWildCoverCropTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestNoTransplant = Template.bind({});
-InGroundNotWildHarvestNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: false,
- is_seed: true,
- for_cover: false,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundNotWildHarvestNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropNoTransplant = Template.bind({});
-InGroundNotWildCoverCropNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: false,
- is_seed: undefined,
- for_cover: true,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundNotWildCoverCropNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundWildForHarvestTransplant = Template.bind({});
-InGroundWildForHarvestTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: true,
- is_seed: undefined,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundWildForHarvestTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundWildCoverCropTransplant = Template.bind({});
-InGroundWildCoverCropTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: true,
- is_seed: undefined,
- for_cover: true,
- needs_transplant: true,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundWildCoverCropTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundWildCoverCropNoTransplant = Template.bind({});
-InGroundWildCoverCropNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: true,
- is_seed: undefined,
- for_cover: true,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundWildCoverCropNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundWildForHarvestNoTransplant = Template.bind({});
-InGroundWildForHarvestNoTransplant.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_wild: true,
- is_seed: undefined,
- for_cover: false,
- needs_transplant: false,
- ...defaultDates,
- },
- },
- crop_variety: {},
-};
-InGroundWildForHarvestNoTransplant.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingWithoutSeedingDate = Template.bind({});
-SeedlingWithoutSeedingDate.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- seed_date: undefined,
- },
- },
- crop_variety: {},
-};
-SeedlingWithoutSeedingDate.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingWithSeedingDateAndDefaultVarietyValues = Template.bind({});
-SeedlingWithSeedingDateAndDefaultVarietyValues.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- seed_date: '2021-07-20',
- },
- },
- crop_variety: {
- germination_days: 2,
- transplant_days: 3,
- termination_days: 4,
- harvest_days: 5,
- },
-};
-SeedlingWithSeedingDateAndDefaultVarietyValues.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingWithoutSeedingDateAndDefaultVarietyValues = Template.bind({});
-SeedlingWithoutSeedingDateAndDefaultVarietyValues.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- },
- },
- crop_variety: {
- germination_days: 2,
- transplant_days: 3,
- termination_days: 4,
- harvest_days: 5,
- },
-};
-SeedlingWithoutSeedingDateAndDefaultVarietyValues.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const TransplantDatePriorThanPlantingDateError = Template.bind({});
-TransplantDatePriorThanPlantingDateError.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- seed_date: '2021-07-20',
- plant_date: '2021-07-25',
- transplant_date: '2021-07-24',
- },
- },
- crop_variety: {},
-};
-TransplantDatePriorThanPlantingDateError.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HarvestDatePriorThanTransplantDateError = Template.bind({});
-HarvestDatePriorThanTransplantDateError.args = {
- useHookFormPersist: () => ({}),
- system: 'imperial',
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_wild: undefined,
- is_seed: false,
- for_cover: false,
- needs_transplant: true,
- ...defaultDates,
- seed_date: '2021-07-20',
- plant_date: '2021-07-21',
- transplant_days: 3,
- harvest_days: 2,
- },
- },
- crop_variety: {},
-};
-HarvestDatePriorThanTransplantDateError.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.jsx
new file mode 100644
index 0000000000..95910e96f0
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingDate.stories.jsx
@@ -0,0 +1,462 @@
+import React from 'react';
+import PurePlantingOrHarvestDate from '../../../components/Crop/PlantingDate/PurePlantingOrHarvestDate';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/PlantingDate',
+ decorators: decorators,
+ component: PurePlantingOrHarvestDate,
+};
+
+const Template = (args) => ;
+
+const defaultDates = {
+ seed_date: '2021-07-20',
+ plant_date: '2021-07-21',
+ germination_date: '2021-07-22',
+ transplant_date: '2021-07-23',
+ termination_date: '2021-07-24',
+ harvest_date: '2021-07-25',
+ germination_days: 2,
+ transplant_days: 3,
+ termination_days: 4,
+ harvest_days: 5,
+};
+
+export const SeedForHarvestTransplant = Template.bind({});
+SeedForHarvestTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: true,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedForHarvestTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedCoverCropTransplant = Template.bind({});
+SeedCoverCropTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: true,
+ for_cover: true,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedCoverCropTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedForHarvestNoTransplant = Template.bind({});
+SeedForHarvestNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: true,
+ for_cover: false,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedForHarvestNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedCoverCropNoTransplant = Template.bind({});
+SeedCoverCropNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: true,
+ for_cover: true,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedCoverCropNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingForHarvestTransplant = Template.bind({});
+SeedlingForHarvestTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedlingForHarvestTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingCoverCropTransplant = Template.bind({});
+SeedlingCoverCropTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: true,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedlingCoverCropTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingForHarvestNoTransplant = Template.bind({});
+SeedlingForHarvestNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedlingForHarvestNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingCoverCropNoTransplant = Template.bind({});
+SeedlingCoverCropNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: true,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+SeedlingCoverCropNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestTransplant = Template.bind({});
+InGroundNotWildHarvestTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: false,
+ is_seed: undefined,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundNotWildHarvestTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropTransplant = Template.bind({});
+InGroundNotWildCoverCropTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: false,
+ is_seed: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundNotWildCoverCropTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestNoTransplant = Template.bind({});
+InGroundNotWildHarvestNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: false,
+ is_seed: true,
+ for_cover: false,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundNotWildHarvestNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropNoTransplant = Template.bind({});
+InGroundNotWildCoverCropNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: false,
+ is_seed: undefined,
+ for_cover: true,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundNotWildCoverCropNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundWildForHarvestTransplant = Template.bind({});
+InGroundWildForHarvestTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: true,
+ is_seed: undefined,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundWildForHarvestTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundWildCoverCropTransplant = Template.bind({});
+InGroundWildCoverCropTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: true,
+ is_seed: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundWildCoverCropTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundWildCoverCropNoTransplant = Template.bind({});
+InGroundWildCoverCropNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: true,
+ is_seed: undefined,
+ for_cover: true,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundWildCoverCropNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundWildForHarvestNoTransplant = Template.bind({});
+InGroundWildForHarvestNoTransplant.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_wild: true,
+ is_seed: undefined,
+ for_cover: false,
+ needs_transplant: false,
+ ...defaultDates,
+ },
+ },
+ crop_variety: {},
+};
+InGroundWildForHarvestNoTransplant.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingWithoutSeedingDate = Template.bind({});
+SeedlingWithoutSeedingDate.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ seed_date: undefined,
+ },
+ },
+ crop_variety: {},
+};
+SeedlingWithoutSeedingDate.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingWithSeedingDateAndDefaultVarietyValues = Template.bind({});
+SeedlingWithSeedingDateAndDefaultVarietyValues.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ seed_date: '2021-07-20',
+ },
+ },
+ crop_variety: {
+ germination_days: 2,
+ transplant_days: 3,
+ termination_days: 4,
+ harvest_days: 5,
+ },
+};
+SeedlingWithSeedingDateAndDefaultVarietyValues.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingWithoutSeedingDateAndDefaultVarietyValues = Template.bind({});
+SeedlingWithoutSeedingDateAndDefaultVarietyValues.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ },
+ },
+ crop_variety: {
+ germination_days: 2,
+ transplant_days: 3,
+ termination_days: 4,
+ harvest_days: 5,
+ },
+};
+SeedlingWithoutSeedingDateAndDefaultVarietyValues.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const TransplantDatePriorThanPlantingDateError = Template.bind({});
+TransplantDatePriorThanPlantingDateError.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ seed_date: '2021-07-20',
+ plant_date: '2021-07-25',
+ transplant_date: '2021-07-24',
+ },
+ },
+ crop_variety: {},
+};
+TransplantDatePriorThanPlantingDateError.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HarvestDatePriorThanTransplantDateError = Template.bind({});
+HarvestDatePriorThanTransplantDateError.args = {
+ useHookFormPersist: () => ({}),
+ system: 'imperial',
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_wild: undefined,
+ is_seed: false,
+ for_cover: false,
+ needs_transplant: true,
+ ...defaultDates,
+ seed_date: '2021-07-20',
+ plant_date: '2021-07-21',
+ transplant_days: 3,
+ harvest_days: 2,
+ },
+ },
+ crop_variety: {},
+};
+HarvestDatePriorThanTransplantDateError.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.js
deleted file mode 100644
index 53f62ce89d..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.js
+++ /dev/null
@@ -1,583 +0,0 @@
-import React from 'react';
-import PureManagementPlanPlantingMethod from '../../../components/Crop/PlantingMethod/PureManagementPlanPlantingMethod';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/PlantingMethod',
- decorators: decorators,
- component: PureManagementPlanPlantingMethod,
-};
-
-const Template = (args) => ;
-
-export const SeedForHarvestTransplantFinal = Template.bind({});
-SeedForHarvestTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: true,
- is_wild: undefined,
- for_cover: false,
- needs_transplant: true,
- },
- },
- system: 'metric',
-};
-SeedForHarvestTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedCovercropTransplantInitial = Template.bind({});
-SeedCovercropTransplantInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: true,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- planting_method: 'BROADCAST_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedCovercropTransplantInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedCovercropTransplantFinal = Template.bind({});
-SeedCovercropTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: true,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'ROW_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedCovercropTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedForHarvestNoTransplantFinal = Template.bind({});
-SeedForHarvestNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: true,
- is_wild: undefined,
- for_cover: false,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- planting_method: 'BED_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedForHarvestNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedCoverCropNoTransplantFinal = Template.bind({});
-SeedCoverCropNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: true,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedCoverCropNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingForHarvestTransplantInitial = Template.bind({});
-SeedlingForHarvestTransplantInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: false,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingForHarvestTransplantInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingForHarvestTransplantFinal = Template.bind({});
-SeedlingForHarvestTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: false,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingForHarvestTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingCoverCropTransplantInitial = Template.bind({});
-SeedlingCoverCropTransplantInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingCoverCropTransplantInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingCoverCropTransplantFinal = Template.bind({});
-SeedlingCoverCropTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingCoverCropTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingForHarvestNoTransplantFinal = Template.bind({});
-SeedlingForHarvestNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: false,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingForHarvestNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SeedlingCoverCropNoTransplantFinal = Template.bind({});
-SeedlingCoverCropNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: false,
- is_seed: false,
- is_wild: undefined,
- for_cover: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-SeedlingCoverCropNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestTransplantInitial = Template.bind({});
-InGroundNotWildHarvestTransplantInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: false,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- is_planting_method_known: false,
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildHarvestTransplantInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestTransplantMethodKnownInitial = Template.bind({});
-InGroundNotWildHarvestTransplantMethodKnownInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: false,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- is_planting_method_known: true,
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildHarvestTransplantMethodKnownInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestTransplantFinal = Template.bind({});
-InGroundNotWildHarvestTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: false,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildHarvestTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropTransplantInitial = Template.bind({});
-InGroundNotWildCoverCropTransplantInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- is_planting_method_known: false,
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildCoverCropTransplantInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropTransplantMethodKnownInitial = Template.bind({});
-InGroundNotWildCoverCropTransplantMethodKnownInitial.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: false,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- initial: {
- is_planting_method_known: true,
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildCoverCropTransplantMethodKnownInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropTransplantFinal = Template.bind({});
-InGroundNotWildCoverCropTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: true,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildCoverCropTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestNoTransplantFinal = Template.bind({});
-InGroundNotWildHarvestNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: false,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- is_planting_method_known: false,
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildHarvestNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildHarvestNoTransplantMethodKnownFinal = Template.bind({});
-InGroundNotWildHarvestNoTransplantMethodKnownFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: false,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- is_planting_method_known: true,
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildHarvestNoTransplantMethodKnownFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropNoTransplantFinal = Template.bind({});
-InGroundNotWildCoverCropNoTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- is_planting_method_known: false,
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildCoverCropNoTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundNotWildCoverCropNoTransplantMethodKnownFinal = Template.bind({});
-InGroundNotWildCoverCropNoTransplantMethodKnownFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: false,
- for_cover: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {
- is_planting_method_known: true,
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundNotWildCoverCropNoTransplantMethodKnownFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InGroundWildTransplantFinal = Template.bind({});
-InGroundWildTransplantFinal.args = {
- useHookFormPersist: () => ({}),
- onGoBack: () => {},
- onCancel: () => {},
- isFinalPlantingMethod: true,
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- is_seed: undefined,
- is_wild: true,
- for_cover: undefined,
- needs_transplant: true,
- planting_management_plans: {
- final: {
- planting_method: 'CONTAINER_METHOD',
- },
- },
- },
- },
- system: 'metric',
-};
-InGroundWildTransplantFinal.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.jsx
new file mode 100644
index 0000000000..77d7844dfe
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/PlantingMethod.stories.jsx
@@ -0,0 +1,583 @@
+import React from 'react';
+import PureManagementPlanPlantingMethod from '../../../components/Crop/PlantingMethod/PureManagementPlanPlantingMethod';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/PlantingMethod',
+ decorators: decorators,
+ component: PureManagementPlanPlantingMethod,
+};
+
+const Template = (args) => ;
+
+export const SeedForHarvestTransplantFinal = Template.bind({});
+SeedForHarvestTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: true,
+ is_wild: undefined,
+ for_cover: false,
+ needs_transplant: true,
+ },
+ },
+ system: 'metric',
+};
+SeedForHarvestTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedCovercropTransplantInitial = Template.bind({});
+SeedCovercropTransplantInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: true,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ planting_method: 'BROADCAST_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedCovercropTransplantInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedCovercropTransplantFinal = Template.bind({});
+SeedCovercropTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: true,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'ROW_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedCovercropTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedForHarvestNoTransplantFinal = Template.bind({});
+SeedForHarvestNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: true,
+ is_wild: undefined,
+ for_cover: false,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ planting_method: 'BED_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedForHarvestNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedCoverCropNoTransplantFinal = Template.bind({});
+SeedCoverCropNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: true,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedCoverCropNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingForHarvestTransplantInitial = Template.bind({});
+SeedlingForHarvestTransplantInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: false,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingForHarvestTransplantInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingForHarvestTransplantFinal = Template.bind({});
+SeedlingForHarvestTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: false,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingForHarvestTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingCoverCropTransplantInitial = Template.bind({});
+SeedlingCoverCropTransplantInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingCoverCropTransplantInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingCoverCropTransplantFinal = Template.bind({});
+SeedlingCoverCropTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingCoverCropTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingForHarvestNoTransplantFinal = Template.bind({});
+SeedlingForHarvestNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: false,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingForHarvestNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SeedlingCoverCropNoTransplantFinal = Template.bind({});
+SeedlingCoverCropNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: false,
+ is_seed: false,
+ is_wild: undefined,
+ for_cover: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+SeedlingCoverCropNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestTransplantInitial = Template.bind({});
+InGroundNotWildHarvestTransplantInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: false,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ is_planting_method_known: false,
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildHarvestTransplantInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestTransplantMethodKnownInitial = Template.bind({});
+InGroundNotWildHarvestTransplantMethodKnownInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: false,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ is_planting_method_known: true,
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildHarvestTransplantMethodKnownInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestTransplantFinal = Template.bind({});
+InGroundNotWildHarvestTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: false,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildHarvestTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropTransplantInitial = Template.bind({});
+InGroundNotWildCoverCropTransplantInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ is_planting_method_known: false,
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildCoverCropTransplantInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropTransplantMethodKnownInitial = Template.bind({});
+InGroundNotWildCoverCropTransplantMethodKnownInitial.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: false,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ initial: {
+ is_planting_method_known: true,
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildCoverCropTransplantMethodKnownInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropTransplantFinal = Template.bind({});
+InGroundNotWildCoverCropTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildCoverCropTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestNoTransplantFinal = Template.bind({});
+InGroundNotWildHarvestNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: false,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ is_planting_method_known: false,
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildHarvestNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildHarvestNoTransplantMethodKnownFinal = Template.bind({});
+InGroundNotWildHarvestNoTransplantMethodKnownFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: false,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ is_planting_method_known: true,
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildHarvestNoTransplantMethodKnownFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropNoTransplantFinal = Template.bind({});
+InGroundNotWildCoverCropNoTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ is_planting_method_known: false,
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildCoverCropNoTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundNotWildCoverCropNoTransplantMethodKnownFinal = Template.bind({});
+InGroundNotWildCoverCropNoTransplantMethodKnownFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: false,
+ for_cover: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {
+ is_planting_method_known: true,
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundNotWildCoverCropNoTransplantMethodKnownFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InGroundWildTransplantFinal = Template.bind({});
+InGroundWildTransplantFinal.args = {
+ useHookFormPersist: () => ({}),
+ onGoBack: () => {},
+ onCancel: () => {},
+ isFinalPlantingMethod: true,
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ is_seed: undefined,
+ is_wild: true,
+ for_cover: undefined,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {
+ planting_method: 'CONTAINER_METHOD',
+ },
+ },
+ },
+ },
+ system: 'metric',
+};
+InGroundWildTransplantFinal.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.js
deleted file mode 100644
index 32af505183..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.js
+++ /dev/null
@@ -1,124 +0,0 @@
-import React from 'react';
-import PureRowMethod from '../../../components/Crop/RowMethod';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ManagementPlan/RowMethod',
- decorators: decorators,
- component: PureRowMethod,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- history: {},
- system: 'metric',
- variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: {},
- },
- },
- },
- isFinalPage: true,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalInitial = Template.bind({});
-HistoricalInitial.args = {
- history: {},
- system: 'metric',
- variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: true,
- planting_management_plans: {
- final: {},
- },
- },
- },
- isFinalPage: false,
-};
-HistoricalInitial.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HistoricalFinal = Template.bind({});
-HistoricalFinal.args = {
- history: {},
- system: 'metric',
- variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- already_in_ground: true,
- needs_transplant: false,
- planting_management_plans: {
- final: {},
- },
- },
- },
- isFinalPage: true,
-};
-HistoricalFinal.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const FinalSameLength = Template.bind({});
-FinalSameLength.args = {
- history: {},
- system: 'metric',
- variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- final: {
- row_method: {
- same_length: true,
- number_of_rows: 10,
- row_length: 10,
- plant_spacing: 10,
- },
- },
- },
- },
- },
- isFinalPage: true,
-};
-FinalSameLength.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InitialDifferentLength = Template.bind({});
-InitialDifferentLength.args = {
- history: {},
- system: 'metric',
- variety: { average_seed_weight: 10, yield_per_plant: 10 },
- useHookFormPersist: () => {},
- persistedFormData: {
- crop_management_plan: {
- planting_management_plans: {
- initial: {
- row_method: {
- same_length: false,
- total_rows_length: 10,
- plant_spacing: 10,
- },
- },
- },
- },
- },
- isFinalPage: false,
-};
-InitialDifferentLength.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.jsx
new file mode 100644
index 0000000000..3394c42288
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/RowMethod.stories.jsx
@@ -0,0 +1,124 @@
+import React from 'react';
+import PureRowMethod from '../../../components/Crop/RowMethod';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ManagementPlan/RowMethod',
+ decorators: decorators,
+ component: PureRowMethod,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ history: {},
+ system: 'metric',
+ variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: {},
+ },
+ },
+ },
+ isFinalPage: true,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalInitial = Template.bind({});
+HistoricalInitial.args = {
+ history: {},
+ system: 'metric',
+ variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: true,
+ planting_management_plans: {
+ final: {},
+ },
+ },
+ },
+ isFinalPage: false,
+};
+HistoricalInitial.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HistoricalFinal = Template.bind({});
+HistoricalFinal.args = {
+ history: {},
+ system: 'metric',
+ variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ already_in_ground: true,
+ needs_transplant: false,
+ planting_management_plans: {
+ final: {},
+ },
+ },
+ },
+ isFinalPage: true,
+};
+HistoricalFinal.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const FinalSameLength = Template.bind({});
+FinalSameLength.args = {
+ history: {},
+ system: 'metric',
+ variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ final: {
+ row_method: {
+ same_length: true,
+ number_of_rows: 10,
+ row_length: 10,
+ plant_spacing: 10,
+ },
+ },
+ },
+ },
+ },
+ isFinalPage: true,
+};
+FinalSameLength.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InitialDifferentLength = Template.bind({});
+InitialDifferentLength.args = {
+ history: {},
+ system: 'metric',
+ variety: { average_seed_weight: 10, yield_per_plant: 10 },
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ crop_management_plan: {
+ planting_management_plans: {
+ initial: {
+ row_method: {
+ same_length: false,
+ total_rows_length: 10,
+ plant_spacing: 10,
+ },
+ },
+ },
+ },
+ },
+ isFinalPage: false,
+};
+InitialDifferentLength.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.js b/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.js
deleted file mode 100644
index 5adaf74d1b..0000000000
--- a/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import React from 'react';
-import PureTransplant from '../../../components/Crop/Transplant';
-import decorators from '../config/decorators';
-
-export default {
- title: 'Form/ManagementPlan/Transplant',
- component: PureTransplant,
- decorators: decorators,
-};
-
-const Template = (args) => ;
-
-export const CanNotBeCoverCrop = Template.bind({});
-CanNotBeCoverCrop.args = {
- persistedFormData: {
- crop_management_plan: { needs_transplant: true },
- },
- useHookFormPersist: () => {},
- onSubmit: (data) => {
- console.log(data);
- },
- onGoBack: () => {},
- onCancel: () => {},
- can_be_cover_crop: false,
-};
-
-export const CoverCrop = Template.bind({});
-CoverCrop.args = {
- persistedFormData: {
- crop_management_plan: { needs_transplant: false, for_cover: false },
- },
- can_be_cover_crop: true,
- useHookFormPersist: () => {},
- onSubmit: (data) => {
- console.log(data);
- },
- onGoBack: () => {},
- onCancel: () => {},
-};
diff --git a/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.jsx b/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.jsx
new file mode 100644
index 0000000000..971915ac7c
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ManagementPlan/Transplant.stories.jsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import PureTransplant from '../../../components/Crop/Transplant';
+import decorators from '../config/Decorators';
+
+export default {
+ title: 'Form/ManagementPlan/Transplant',
+ component: PureTransplant,
+ decorators: decorators,
+};
+
+const Template = (args) => ;
+
+export const CanNotBeCoverCrop = Template.bind({});
+CanNotBeCoverCrop.args = {
+ persistedFormData: {
+ crop_management_plan: { needs_transplant: true },
+ },
+ useHookFormPersist: () => ({}),
+ onSubmit: (data) => {
+ console.log(data);
+ },
+ onGoBack: () => {},
+ onCancel: () => {},
+ can_be_cover_crop: false,
+};
+
+export const CoverCrop = Template.bind({});
+CoverCrop.args = {
+ persistedFormData: {
+ crop_management_plan: { needs_transplant: false, for_cover: false },
+ },
+ can_be_cover_crop: true,
+ useHookFormPersist: () => ({}),
+ onSubmit: (data) => {
+ console.log(data);
+ },
+ onGoBack: () => {},
+ onCancel: () => {},
+};
diff --git a/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.js b/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.js
deleted file mode 100644
index d64b3fd123..0000000000
--- a/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import CustomCompass from '../../../../components/Map/CustomCompass/';
-
-export default {
- title: 'Components/Map/CustomCompass',
- component: CustomCompass,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
diff --git a/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.jsx b/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.jsx
new file mode 100644
index 0000000000..634c7e7672
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/CustomCompass/CustomCompass.stories.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import CustomCompass from '../../../../components/Map/CustomCompass/';
+
+export default {
+ title: 'Components/Map/CustomCompass',
+ component: CustomCompass,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
diff --git a/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.js b/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.js
deleted file mode 100644
index 12aa108fe8..0000000000
--- a/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import CustomZoom from '../../../../components/Map/CustomZoom/';
-
-export default {
- title: 'Components/Map/CustomZoom',
- component: CustomZoom,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
diff --git a/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.jsx b/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.jsx
new file mode 100644
index 0000000000..3b81fc6366
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/CustomZoom/CustomZoom.stories.jsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import CustomZoom from '../../../../components/Map/CustomZoom/';
+
+export default {
+ title: 'Components/Map/CustomZoom',
+ component: CustomZoom,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
diff --git a/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.js b/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.js
deleted file mode 100644
index 4019a9aa68..0000000000
--- a/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureMapFooter from '../../../../components/Map/Footer/';
-import { locationEnum } from '../../../../containers/Map/constants';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/Drawer',
- component: PureMapFooter,
- decorators: decorators,
-};
-const availableFilterSettings = {
- area: [
- locationEnum.barn,
- locationEnum.ceremonial_area,
- locationEnum.farm_site_boundary,
- locationEnum.field,
- locationEnum.garden,
- locationEnum.greenhouse,
- locationEnum.surface_water,
- locationEnum.natural_area,
- locationEnum.residence,
- ],
- line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
- point: [locationEnum.gate, locationEnum.water_valve],
-};
-const Template = (args) => (
-
-);
-
-export const Filter = Template.bind({});
-Filter.args = {
- isAdmin: true,
- showSpotlight: false,
- showMapFilter: true,
- drawerDefaultHeight: window.innerHeight - 156,
- /*
- * Map should show barns when barn:true
- * */
- filterSettings: { barn: true },
-};
-Filter.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Add = Template.bind({});
-Add.args = {
- isAdmin: true,
- showSpotlight: false,
- showAddDrawer: true,
- drawerDefaultHeight: window.innerHeight - 156,
-};
-Filter.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.jsx b/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.jsx
new file mode 100644
index 0000000000..3ccf1678b3
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/Drawer/Drawer.stories.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureMapFooter from '../../../../components/Map/Footer/';
+import { locationEnum } from '../../../../containers/Map/constants';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/Drawer',
+ component: PureMapFooter,
+ decorators: decorators,
+};
+const availableFilterSettings = {
+ area: [
+ locationEnum.barn,
+ locationEnum.ceremonial_area,
+ locationEnum.farm_site_boundary,
+ locationEnum.field,
+ locationEnum.garden,
+ locationEnum.greenhouse,
+ locationEnum.surface_water,
+ locationEnum.natural_area,
+ locationEnum.residence,
+ ],
+ line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
+ point: [locationEnum.gate, locationEnum.water_valve],
+};
+const Template = (args) => (
+
+);
+
+export const Filter = Template.bind({});
+Filter.args = {
+ isAdmin: true,
+ showSpotlight: false,
+ showMapFilter: true,
+ drawerDefaultHeight: window.innerHeight - 156,
+ /*
+ * Map should show barns when barn:true
+ * */
+ filterSettings: { barn: true },
+};
+Filter.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Add = Template.bind({});
+Add.args = {
+ isAdmin: true,
+ showSpotlight: false,
+ showAddDrawer: true,
+ drawerDefaultHeight: window.innerHeight - 156,
+};
+Filter.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.js b/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.js
deleted file mode 100644
index 24fa6fd304..0000000000
--- a/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import React from 'react';
-import { componentDecoratorsGreyBackground } from '../../config/decorators';
-import MapDrawerMenuItem from '../../../../components/MapDrawer/MapDrawerMenuItem';
-import { ReactComponent as MapBackground } from '../../../../assets/images/farmMapFilter/MapBackground.svg';
-
-export default {
- title: 'Components/Map/MapDrawerMenuItem',
- component: MapDrawerMenuItem,
- decorators: componentDecoratorsGreyBackground,
-};
-
-const Template = (args) => (
-
-
-
-);
-
-export const FilterInactive = Template.bind({});
-FilterInactive.args = {
- name: 'Map background',
- isFilterMenuItem: true,
-};
-
-export const FilterActive = Template.bind({});
-FilterActive.args = {
- name: 'Map background',
- isFiltered: true,
- isFilterMenuItem: true,
-};
-
-export const Add = Template.bind({});
-Add.args = {
- name: 'Map background',
-};
diff --git a/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.jsx b/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.jsx
new file mode 100644
index 0000000000..f6b12db2b1
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/DrawerMenuItem/DrawerMenuItem.stories.jsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { componentDecoratorsGreyBackground } from '../../config/Decorators';
+import MapDrawerMenuItem from '../../../../components/MapDrawer/MapDrawerMenuItem';
+import { ReactComponent as MapBackground } from '../../../../assets/images/farmMapFilter/MapBackground.svg';
+
+export default {
+ title: 'Components/Map/MapDrawerMenuItem',
+ component: MapDrawerMenuItem,
+ decorators: componentDecoratorsGreyBackground,
+};
+
+const Template = (args) => (
+
+
+
+);
+
+export const FilterInactive = Template.bind({});
+FilterInactive.args = {
+ name: 'Map background',
+ isFilterMenuItem: true,
+};
+
+export const FilterActive = Template.bind({});
+FilterActive.args = {
+ name: 'Map background',
+ isFiltered: true,
+ isFilterMenuItem: true,
+};
+
+export const Add = Template.bind({});
+Add.args = {
+ name: 'Map background',
+};
diff --git a/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.js b/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.js
deleted file mode 100644
index 410d0bdf9e..0000000000
--- a/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import DrawingManager from '../../../../components/Map/DrawingManager/';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/DrawingManager',
- component: DrawingManager,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const DrawingArea = Template.bind({});
-DrawingArea.args = {
- drawingState: 'field',
- isDrawing: true,
-};
-DrawingArea.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const DrewArea = Template.bind({});
-DrewArea.args = {
- drawingState: 'field',
- isDrawing: false,
-};
-DrewArea.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const DrawingPoint = Template.bind({});
-DrawingPoint.args = {
- drawingState: 'gate',
- isDrawing: true,
-};
-DrawingPoint.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const DrewPoint = Template.bind({});
-DrewPoint.args = {
- drawingState: 'gate',
- isDrawing: false,
-};
-DrewPoint.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.jsx b/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.jsx
new file mode 100644
index 0000000000..9bb53c349f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/DrawingManager/DrawingManager.stories.jsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import DrawingManager from '../../../../components/Map/DrawingManager/';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/DrawingManager',
+ component: DrawingManager,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const DrawingArea = Template.bind({});
+DrawingArea.args = {
+ drawingState: 'field',
+ isDrawing: true,
+};
+DrawingArea.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const DrewArea = Template.bind({});
+DrewArea.args = {
+ drawingState: 'field',
+ isDrawing: false,
+};
+DrewArea.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const DrawingPoint = Template.bind({});
+DrawingPoint.args = {
+ drawingState: 'gate',
+ isDrawing: true,
+};
+DrawingPoint.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const DrewPoint = Template.bind({});
+DrewPoint.args = {
+ drawingState: 'gate',
+ isDrawing: false,
+};
+DrewPoint.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.js b/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.js
deleted file mode 100644
index cd87c610be..0000000000
--- a/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import PureMapFooter from '../../../../components/Map/Footer/';
-import { locationEnum } from '../../../../containers/Map/constants';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/MapFooter',
- component: PureMapFooter,
- decorators: componentDecoratorsWithoutPadding,
-};
-const availableFilterSettings = {
- area: [
- locationEnum.barn,
- locationEnum.ceremonial_area,
- locationEnum.farm_site_boundary,
- locationEnum.field,
- locationEnum.garden,
- locationEnum.greenhouse,
- locationEnum.surface_water,
- locationEnum.natural_area,
- locationEnum.residence,
- ],
- line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
- point: [locationEnum.gate, locationEnum.water_valve],
-};
-const Template = (args) => ;
-
-export const Admin = Template.bind({});
-Admin.args = {
- isAdmin: true,
- showSpotlight: false,
- availableFilterSettings,
-};
-Admin.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Worker = Template.bind({});
-Worker.args = {
- isAdmin: false,
- showSpotlight: false,
- availableFilterSettings,
-};
-Worker.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.jsx b/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.jsx
new file mode 100644
index 0000000000..891b2ab4f1
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/Footer/MapFooter.stories.jsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import PureMapFooter from '../../../../components/Map/Footer/';
+import { locationEnum } from '../../../../containers/Map/constants';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/MapFooter',
+ component: PureMapFooter,
+ decorators: componentDecoratorsWithoutPadding,
+};
+const availableFilterSettings = {
+ area: [
+ locationEnum.barn,
+ locationEnum.ceremonial_area,
+ locationEnum.farm_site_boundary,
+ locationEnum.field,
+ locationEnum.garden,
+ locationEnum.greenhouse,
+ locationEnum.surface_water,
+ locationEnum.natural_area,
+ locationEnum.residence,
+ ],
+ line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
+ point: [locationEnum.gate, locationEnum.water_valve],
+};
+const Template = (args) => ;
+
+export const Admin = Template.bind({});
+Admin.args = {
+ isAdmin: true,
+ showSpotlight: false,
+ availableFilterSettings,
+};
+Admin.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Worker = Template.bind({});
+Worker.args = {
+ isAdmin: false,
+ showSpotlight: false,
+ availableFilterSettings,
+};
+Worker.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.js b/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.js
deleted file mode 100644
index 16165f0979..0000000000
--- a/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import PureMapHeader from '../../../../components/Map/Header/';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/MapHeader',
- component: PureMapHeader,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- farmName: 'Happy Valley',
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.jsx b/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.jsx
new file mode 100644
index 0000000000..41153a5b2f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/Header/MapHeader.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import PureMapHeader from '../../../../components/Map/Header/';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/MapHeader',
+ component: PureMapHeader,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ farmName: 'Happy Valley',
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.js b/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.js
deleted file mode 100644
index c70a14cd36..0000000000
--- a/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import PureLineBox from '../../../../components/Map/LineMapBoxes/index';
-import { decoratorsWithStore } from '../../config/decorators';
-
-export default {
- title: 'Components/LineBox',
- component: PureLineBox,
- decorators: decoratorsWithStore,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- locationData: { width: 8 },
- system: 'imperial',
- updateWidth: () => {},
-};
diff --git a/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.jsx b/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.jsx
new file mode 100644
index 0000000000..7d3e318f49
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/LineBox/LineBox.stories.jsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import PureLineBox from '../../../../components/Map/LineMapBoxes/index';
+import { decoratorsWithStore } from '../../config/Decorators';
+
+export default {
+ title: 'Components/LineBox',
+ component: PureLineBox,
+ decorators: decoratorsWithStore,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ locationData: { width: 8 },
+ system: 'imperial',
+ updateWidth: () => {},
+};
diff --git a/packages/webapp/src/stories/Pages/Map/Map.stories.js b/packages/webapp/src/stories/Pages/Map/Map.stories.js
deleted file mode 100644
index c03d558291..0000000000
--- a/packages/webapp/src/stories/Pages/Map/Map.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-// import PureMap from '../../../components/Map/';
-import Map from '../../../containers/Map/';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/Map',
- decorators: decorators,
- component: Map,
-};
-
-const Template = (args) => ;
-
-export const AdminMap = Template.bind({});
-AdminMap.args = {
- history: { location: {} },
-};
-AdminMap.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/Map.stories.jsx b/packages/webapp/src/stories/Pages/Map/Map.stories.jsx
new file mode 100644
index 0000000000..e4b90a26c8
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/Map.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+// import PureMap from '../../../components/Map/';
+import Map from '../../../containers/Map/';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/Map',
+ decorators: decorators,
+ component: Map,
+};
+
+const Template = (args) => ;
+
+export const AdminMap = Template.bind({});
+AdminMap.args = {
+ history: { location: {} },
+};
+AdminMap.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.js b/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.js
deleted file mode 100644
index d91ea159de..0000000000
--- a/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import PureSelectionHandler from '../../../../components/Map/SelectionHandler';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/LocationSelection',
- component: PureSelectionHandler,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const locations = [
- {
- asset: 'line',
- id: '80ca2d14-9636-11eb-93d7-acde48001122',
- name: 'Fence 1',
- type: 'fence',
- },
-];
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- locations: locations,
- history: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.jsx b/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.jsx
new file mode 100644
index 0000000000..c56d996cdf
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/SelectionHandler/SelectionHandler.stories.jsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import PureSelectionHandler from '../../../../components/Map/SelectionHandler';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/LocationSelection',
+ component: PureSelectionHandler,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const locations = [
+ {
+ asset: 'line',
+ id: '80ca2d14-9636-11eb-93d7-acde48001122',
+ name: 'Fence 1',
+ type: 'fence',
+ },
+];
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ locations: locations,
+ history: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.js b/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.js
deleted file mode 100644
index 454d751a02..0000000000
--- a/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureMapFooter from '../../../../components/Map/Footer/';
-import { locationEnum } from '../../../../containers/Map/constants';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/SpotLight',
- component: PureMapFooter,
- decorators: decorators,
-};
-const availableFilterSettings = {
- area: [
- locationEnum.barn,
- locationEnum.ceremonial_area,
- locationEnum.farm_site_boundary,
- locationEnum.field,
- locationEnum.garden,
- locationEnum.greenhouse,
- locationEnum.surface_water,
- locationEnum.natural_area,
- locationEnum.residence,
- ],
- line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
- point: [locationEnum.gate, locationEnum.water_valve],
-};
-const Template = (args) => (
-
-);
-
-export const SpotLight = Template.bind({});
-SpotLight.args = {
- isAdmin: true,
- showSpotlight: true,
- availableFilterSettings,
-};
-SpotLight.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.jsx b/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.jsx
new file mode 100644
index 0000000000..6dcdb8d421
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/SpotLight/Drawer.stories.jsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureMapFooter from '../../../../components/Map/Footer/';
+import { locationEnum } from '../../../../containers/Map/constants';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/SpotLight',
+ component: PureMapFooter,
+ decorators: decorators,
+};
+const availableFilterSettings = {
+ area: [
+ locationEnum.barn,
+ locationEnum.ceremonial_area,
+ locationEnum.farm_site_boundary,
+ locationEnum.field,
+ locationEnum.garden,
+ locationEnum.greenhouse,
+ locationEnum.surface_water,
+ locationEnum.natural_area,
+ locationEnum.residence,
+ ],
+ line: [locationEnum.buffer_zone, locationEnum.creek, locationEnum.fence],
+ point: [locationEnum.gate, locationEnum.water_valve],
+};
+const Template = (args) => (
+
+);
+
+export const SpotLight = Template.bind({});
+SpotLight.args = {
+ isAdmin: true,
+ showSpotlight: true,
+ availableFilterSettings,
+};
+SpotLight.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.js b/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.js
deleted file mode 100644
index 4ef28b7e31..0000000000
--- a/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import ProgressBar from '../../../../components/Map/ProgressBar';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/ProgressBar',
- component: ProgressBar,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- closeSuccessHeader: () => {},
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.jsx b/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.jsx
new file mode 100644
index 0000000000..2c8a15a259
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/SuccessHeader/ProgressBar.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import ProgressBar from '../../../../components/Map/ProgressBar';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/ProgressBar',
+ component: ProgressBar,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ closeSuccessHeader: () => {},
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.js b/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.js
deleted file mode 100644
index 80532c0b6a..0000000000
--- a/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import { PureSnackbarWithoutBorder } from '../../../../components/PureSnackbar/';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/SuccessHeader',
- component: PureSnackbarWithoutBorder,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- closeSuccessHeader: () => {},
- title: 'Farm site boundary successfully saved',
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.jsx b/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.jsx
new file mode 100644
index 0000000000..a249ffd6b8
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/SuccessHeader/SuccessHeader.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import { PureSnackbarWithoutBorder } from '../../../../components/PureSnackbar/';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/SuccessHeader',
+ component: PureSnackbarWithoutBorder,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ closeSuccessHeader: () => {},
+ title: 'Farm site boundary successfully saved',
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Map/Video/Video.stories.js b/packages/webapp/src/stories/Pages/Map/Video/Video.stories.js
deleted file mode 100644
index b510d5cf13..0000000000
--- a/packages/webapp/src/stories/Pages/Map/Video/Video.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { componentDecoratorsWithoutPadding } from '../../config/decorators';
-import PureVideo from '../../../../components/Map/Videos/index';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Components/Map/Videos',
- component: PureVideo,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Map/Video/Video.stories.jsx b/packages/webapp/src/stories/Pages/Map/Video/Video.stories.jsx
new file mode 100644
index 0000000000..3d105060b4
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Map/Video/Video.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { componentDecoratorsWithoutPadding } from '../../config/Decorators';
+import PureVideo from '../../../../components/Map/Videos/index';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Components/Map/Videos',
+ component: PureVideo,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.js b/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.js
deleted file mode 100644
index 62e4762ec2..0000000000
--- a/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import MapDrawer from '../../../components/MapDrawer/';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Page/MapDrawer',
- decorators: decorators,
- component: MapDrawer,
-};
-
-const Template = (args) => ;
-
-export const AdminMap = Template.bind({});
-AdminMap.args = {};
-AdminMap.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.jsx b/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.jsx
new file mode 100644
index 0000000000..faa550a4a4
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/MapFilter/MapFilter.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import MapDrawer from '../../../components/MapDrawer/';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Page/MapDrawer',
+ decorators: decorators,
+ component: MapDrawer,
+};
+
+const Template = (args) => ;
+
+export const AdminMap = Template.bind({});
+AdminMap.args = {};
+AdminMap.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.js b/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.js
deleted file mode 100644
index 915360dc5b..0000000000
--- a/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.js
+++ /dev/null
@@ -1,253 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PurePlantingLocation from '../../../components/Crop/PlantingLocation';
-import { chromaticSmallScreen } from '../config/chromatic';
-import produce from 'immer';
-
-export default {
- title: 'Form/ManagementPlan/PlantingLocation',
- decorators: decorators,
- component: PurePlantingLocation,
-};
-const cropLocations = [
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: 'eq',
- notes: '',
- location_id: '8b47b24e-f427-11eb-b310-9b4fc6232458',
- figure_id: '8b47b24f-f427-11eb-b310-9b4fc6232458',
- type: 'field',
- total_area: 5587,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26919164618451,
- lng: -123.18165204714356,
- },
- {
- lat: 49.268547584065274,
- lng: -123.18288586329041,
- },
- {
- lat: 49.268603589800726,
- lng: -123.1806328077179,
- },
- ],
- perimeter: 377,
- perimeter_unit: 'm',
- organic_status: 'Non-Organic',
- transition_date: '2021-08-03T07:00:00.000Z',
- station_id: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: 'w',
- notes: '',
- location_id: 'c361c80a-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'c361c80b-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'garden',
- total_area: 5309,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26919514649913,
- lng: -123.18276784609375,
- },
- {
- lat: 49.26819404639292,
- lng: -123.18202755640564,
- },
- {
- lat: 49.26790001313183,
- lng: -123.18312189768372,
- },
- ],
- perimeter: 356,
- perimeter_unit: 'm',
- organic_status: 'Non-Organic',
- station_id: null,
- transition_date: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: '4',
- notes: '',
- location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'ce8f9677-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'greenhouse',
- total_area: 9938,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26823605100145,
- lng: -123.18331501673279,
- },
- {
- lat: 49.26825705329233,
- lng: -123.18087957094727,
- },
- {
- lat: 49.26926515273966,
- lng: -123.18101904581604,
- },
- ],
- perimeter: 492,
- organic_status: 'Non-Organic',
- supplemental_lighting: null,
- co2_enrichment: null,
- greenhouse_heated: null,
- perimeter_unit: 'm',
- transition_date: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: '3',
- notes: '',
- location_id: 'd4ec5e8c-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'd4ec5e8d-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'buffer_zone',
- length: 224,
- width: 8,
- line_points: [
- {
- lat: 49.26831305935756,
- lng: -123.18393728922425,
- },
- {
- lat: 49.26787200987272,
- lng: -123.18092248629151,
- },
- ],
- width_unit: 'm',
- total_area: 1795,
- total_area_unit: 'ha',
- length_unit: 'm',
- },
-];
-
-const persistedFormData = {
- crop_management_plan: {
- transplant_date: '2021-08-18',
- harvest_days: 2,
- planting_management_plans: {
- final: {
- estimated_yield_unit: {
- value: 'kg',
- label: 'kg',
- },
- location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
- },
- initial: {
- estimated_yield_unit: {
- value: 'kg',
- label: 'kg',
- },
- pin_coordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
- },
- },
- needs_transplant: true,
- already_in_ground: true,
- for_cover: false,
- crop_age_unit: {
- label: 'weeks',
- value: 'week',
- },
- is_wild: true,
- harvest_date: '2021-08-20',
- },
-};
-
-const Template = (args) => ;
-
-export const FinalInGround = Template.bind({});
-FinalInGround.args = {
- cropLocations,
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData,
- isFinalLocationPage: true,
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-FinalInGround.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InitialInGround = Template.bind({});
-InitialInGround.args = {
- cropLocations,
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData,
- isFinalLocationPage: false,
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-InitialInGround.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const FinalSeedling = Template.bind({});
-FinalSeedling.args = {
- cropLocations,
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: produce(persistedFormData, (persistedFormData) => {
- persistedFormData.crop_management_plan.already_in_ground = false;
- }),
- isFinalLocationPage: true,
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-FinalSeedling.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InitialSeedling = Template.bind({});
-InitialSeedling.args = {
- cropLocations,
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: produce(persistedFormData, (persistedFormData) => {
- persistedFormData.crop_management_plan.already_in_ground = false;
- }),
- isFinalLocationPage: false,
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-InitialSeedling.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const InitialSeedlingWithDefaultFarmLocation = Template.bind({});
-InitialSeedlingWithDefaultFarmLocation.args = {
- cropLocations,
- variety_id: 'variety_id',
- useHookFormPersist: () => {},
- persistedFormData: produce(persistedFormData, (persistedFormData) => {
- persistedFormData.crop_management_plan.already_in_ground = false;
- persistedFormData.farm = {
- default_initial_location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
- };
- }),
- isFinalLocationPage: false,
- default_initial_location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-InitialSeedlingWithDefaultFarmLocation.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.jsx b/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.jsx
new file mode 100644
index 0000000000..8fdf9f67bb
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/PlantingLocation/PlantingLocation.stories.jsx
@@ -0,0 +1,253 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PurePlantingLocation from '../../../components/Crop/PlantingLocation';
+import { chromaticSmallScreen } from '../config/chromatic';
+import produce from 'immer';
+
+export default {
+ title: 'Form/ManagementPlan/PlantingLocation',
+ decorators: decorators,
+ component: PurePlantingLocation,
+};
+const cropLocations = [
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: 'eq',
+ notes: '',
+ location_id: '8b47b24e-f427-11eb-b310-9b4fc6232458',
+ figure_id: '8b47b24f-f427-11eb-b310-9b4fc6232458',
+ type: 'field',
+ total_area: 5587,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26919164618451,
+ lng: -123.18165204714356,
+ },
+ {
+ lat: 49.268547584065274,
+ lng: -123.18288586329041,
+ },
+ {
+ lat: 49.268603589800726,
+ lng: -123.1806328077179,
+ },
+ ],
+ perimeter: 377,
+ perimeter_unit: 'm',
+ organic_status: 'Non-Organic',
+ transition_date: '2021-08-03T07:00:00.000Z',
+ station_id: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: 'w',
+ notes: '',
+ location_id: 'c361c80a-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'c361c80b-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'garden',
+ total_area: 5309,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26919514649913,
+ lng: -123.18276784609375,
+ },
+ {
+ lat: 49.26819404639292,
+ lng: -123.18202755640564,
+ },
+ {
+ lat: 49.26790001313183,
+ lng: -123.18312189768372,
+ },
+ ],
+ perimeter: 356,
+ perimeter_unit: 'm',
+ organic_status: 'Non-Organic',
+ station_id: null,
+ transition_date: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: '4',
+ notes: '',
+ location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'ce8f9677-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'greenhouse',
+ total_area: 9938,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26823605100145,
+ lng: -123.18331501673279,
+ },
+ {
+ lat: 49.26825705329233,
+ lng: -123.18087957094727,
+ },
+ {
+ lat: 49.26926515273966,
+ lng: -123.18101904581604,
+ },
+ ],
+ perimeter: 492,
+ organic_status: 'Non-Organic',
+ supplemental_lighting: null,
+ co2_enrichment: null,
+ greenhouse_heated: null,
+ perimeter_unit: 'm',
+ transition_date: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: '3',
+ notes: '',
+ location_id: 'd4ec5e8c-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'd4ec5e8d-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'buffer_zone',
+ length: 224,
+ width: 8,
+ line_points: [
+ {
+ lat: 49.26831305935756,
+ lng: -123.18393728922425,
+ },
+ {
+ lat: 49.26787200987272,
+ lng: -123.18092248629151,
+ },
+ ],
+ width_unit: 'm',
+ total_area: 1795,
+ total_area_unit: 'ha',
+ length_unit: 'm',
+ },
+];
+
+const persistedFormData = {
+ crop_management_plan: {
+ transplant_date: '2021-08-18',
+ harvest_days: 2,
+ planting_management_plans: {
+ final: {
+ estimated_yield_unit: {
+ value: 'kg',
+ label: 'kg',
+ },
+ location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
+ },
+ initial: {
+ estimated_yield_unit: {
+ value: 'kg',
+ label: 'kg',
+ },
+ pin_coordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+ },
+ },
+ needs_transplant: true,
+ already_in_ground: true,
+ for_cover: false,
+ crop_age_unit: {
+ label: 'weeks',
+ value: 'week',
+ },
+ is_wild: true,
+ harvest_date: '2021-08-20',
+ },
+};
+
+const Template = (args) => ;
+
+export const FinalInGround = Template.bind({});
+FinalInGround.args = {
+ cropLocations,
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData,
+ isFinalLocationPage: true,
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+FinalInGround.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InitialInGround = Template.bind({});
+InitialInGround.args = {
+ cropLocations,
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData,
+ isFinalLocationPage: false,
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+InitialInGround.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const FinalSeedling = Template.bind({});
+FinalSeedling.args = {
+ cropLocations,
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: produce(persistedFormData, (persistedFormData) => {
+ persistedFormData.crop_management_plan.already_in_ground = false;
+ }),
+ isFinalLocationPage: true,
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+FinalSeedling.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InitialSeedling = Template.bind({});
+InitialSeedling.args = {
+ cropLocations,
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: produce(persistedFormData, (persistedFormData) => {
+ persistedFormData.crop_management_plan.already_in_ground = false;
+ }),
+ isFinalLocationPage: false,
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+InitialSeedling.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const InitialSeedlingWithDefaultFarmLocation = Template.bind({});
+InitialSeedlingWithDefaultFarmLocation.args = {
+ cropLocations,
+ variety_id: 'variety_id',
+ useHookFormPersist: () => ({}),
+ persistedFormData: produce(persistedFormData, (persistedFormData) => {
+ persistedFormData.crop_management_plan.already_in_ground = false;
+ persistedFormData.farm = {
+ default_initial_location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
+ };
+ }),
+ isFinalLocationPage: false,
+ default_initial_location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+InitialSeedlingWithDefaultFarmLocation.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Profile/Account.stories.js b/packages/webapp/src/stories/Pages/Profile/Account.stories.js
deleted file mode 100644
index 6f0201f6a7..0000000000
--- a/packages/webapp/src/stories/Pages/Profile/Account.stories.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-import PureAccount from '../../../components/Profile/Account';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Profile/Account',
- decorators: decorator,
- component: PureAccount,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- userFarm: {
- first_name: 'first',
- last_name: 'last',
- email: 'example@litefarm.org',
- phone_number: '123456789',
- user_address: 'litefarm',
- },
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Profile/Account.stories.jsx b/packages/webapp/src/stories/Pages/Profile/Account.stories.jsx
new file mode 100644
index 0000000000..a15221656a
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Profile/Account.stories.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import PureAccount from '../../../components/Profile/Account';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Profile/Account',
+ decorators: decorator,
+ component: PureAccount,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ userFarm: {
+ first_name: 'first',
+ last_name: 'last',
+ email: 'example@litefarm.org',
+ phone_number: '123456789',
+ user_address: 'litefarm',
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Profile/EditUser.stories.jsx b/packages/webapp/src/stories/Pages/Profile/EditUser.stories.jsx
new file mode 100644
index 0000000000..921f36ff43
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Profile/EditUser.stories.jsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import PureEditUser from '../../../components/Profile/EditUser';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Profile/EditUser',
+ decorators: decorator,
+ component: PureEditUser,
+};
+
+const userFarm = {
+ wage: { type: 'hourly', amount: 10 },
+ first_name: 'first_name',
+ last_name: 'last_name',
+ email: 'email@example.com',
+ role_id: 1,
+};
+const Template = (args) => ;
+
+export const Admin = Template.bind({});
+Admin.args = {
+ userFarm,
+ history: {},
+ isAdmin: true,
+
+};
+Admin.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Worker = Template.bind({});
+Worker.args = {
+ userFarm,
+ history: {},
+ isAdmin: false,
+
+};
+Worker.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Profile/Farm.stories.js b/packages/webapp/src/stories/Pages/Profile/Farm.stories.js
deleted file mode 100644
index 6efee47907..0000000000
--- a/packages/webapp/src/stories/Pages/Profile/Farm.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import PureFarm from '../../../components/Profile/Farm';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Profile/Farm',
- decorators: decorator,
- component: PureFarm,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- userFarm: {
- farm_name: 'liteFarm',
- last_name: 'last',
- farm_phone_number: '123456789',
- address: 'litefarm',
- units: {
- measurement: 'imperial',
- currency: 'CAD',
- },
- },
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Profile/Farm.stories.jsx b/packages/webapp/src/stories/Pages/Profile/Farm.stories.jsx
new file mode 100644
index 0000000000..26952fc7fa
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Profile/Farm.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import PureFarm from '../../../components/Profile/Farm';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Profile/Farm',
+ decorators: decorator,
+ component: PureFarm,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ userFarm: {
+ farm_name: 'liteFarm',
+ last_name: 'last',
+ farm_phone_number: '123456789',
+ address: 'litefarm',
+ units: {
+ measurement: 'imperial',
+ currency: 'CAD',
+ },
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Profile/People.stories.js b/packages/webapp/src/stories/Pages/Profile/People.stories.js
deleted file mode 100644
index d95ee32309..0000000000
--- a/packages/webapp/src/stories/Pages/Profile/People.stories.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React from 'react';
-import PurePeople from '../../../components/Profile/People';
-import decorator from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/Profile/People',
- decorators: decorator,
- component: PurePeople,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- users: [
- {
- first_name: 'first',
- last_name: 'last',
- role: 'Owner',
- status: 'Active',
- user_id: '123456778',
- email: 'example@litefarm.org',
- },
- ],
- history: {},
- isAdmin: true,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Profile/People.stories.jsx b/packages/webapp/src/stories/Pages/Profile/People.stories.jsx
new file mode 100644
index 0000000000..55bfdac396
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Profile/People.stories.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import PurePeople from '../../../components/Profile/People';
+import decorator from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/Profile/People',
+ decorators: decorator,
+ component: PurePeople,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ users: [
+ {
+ first_name: 'first',
+ last_name: 'last',
+ role: 'Owner',
+ status: 'Active',
+ user_id: '123456778',
+ email: 'example@litefarm.org',
+ },
+ ],
+ history: {},
+ isAdmin: true,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.js b/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.js
deleted file mode 100644
index e7855582d2..0000000000
--- a/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-
-import PureResetPasswordAccount from '../../../components/PasswordResetAccount';
-import { chromaticSmallScreen } from '../config/chromatic';
-
-export default {
- title: 'Form/ResetPassword/NewPasswordPage',
- decorators: decorators,
- component: PureResetPasswordAccount,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.jsx b/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.jsx
new file mode 100644
index 0000000000..80387dfdab
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ResetPassword/NewPasswordPage.stories.jsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+
+import PureResetPasswordAccount from '../../../components/PasswordResetAccount';
+import { chromaticSmallScreen } from '../config/chromatic';
+
+export default {
+ title: 'Form/ResetPassword/NewPasswordPage',
+ decorators: decorators,
+ component: PureResetPasswordAccount,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.js b/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.js
deleted file mode 100644
index c8c37b9d38..0000000000
--- a/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureCreateUserAccount from '../../../../components/CreateUserAccount';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Signup/CreateUserAccount',
- decorators: decorators,
- component: PureCreateUserAccount,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- email: 'litefarm@litefarm.org',
- onSignUp: (data) => console.log(data),
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.jsx b/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.jsx
new file mode 100644
index 0000000000..6b86ae8567
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Signup/CreateAccountPage/CreateAccountPage.stories.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureCreateUserAccount from '../../../../components/CreateUserAccount';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Signup/CreateUserAccount',
+ decorators: decorators,
+ component: PureCreateUserAccount,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ email: 'litefarm@litefarm.org',
+ onSignUp: (data) => console.log(data),
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.js b/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.js
deleted file mode 100644
index 61ee66dee4..0000000000
--- a/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import EnterPasswordPage from '../../../../components/Signup/EnterPasswordPage';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Signup/EnterPassword',
- decorators: decorators,
- component: EnterPasswordPage,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Not_Chrome = Template.bind({});
-Not_Chrome.args = { isChrome: false };
-Not_Chrome.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.jsx b/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.jsx
new file mode 100644
index 0000000000..1d2014db43
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Signup/EnterPasswordPage/EnterPasswordPage.stories.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import EnterPasswordPage from '../../../../components/Signup/EnterPasswordPage';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Signup/EnterPassword',
+ decorators: decorators,
+ component: EnterPasswordPage,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Not_Chrome = Template.bind({});
+Not_Chrome.args = { isChrome: false };
+Not_Chrome.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.js b/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.js
deleted file mode 100644
index fa924486ba..0000000000
--- a/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureCustomSignUp from '../../../../components/CustomSignUp';
-import GoogleLoginButton from '../../../../containers/GoogleLoginButton';
-import { chromaticSmallScreen } from '../../config/chromatic';
-
-export default {
- title: 'Form/Signup/SignUpPage',
- decorators: decorators,
- component: PureCustomSignUp,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = { GoogleLoginButton: };
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Not_Chrome = Template.bind({});
-Not_Chrome.args = { GoogleLoginButton: , isChrome: false };
-Not_Chrome.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const Invalid_token = Template.bind({});
-Invalid_token.args = {
- GoogleLoginButton: ,
- isChrome: false,
- errorMessage: 'This invitation has already been used, please log in to access this farm',
-};
-Invalid_token.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.jsx b/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.jsx
new file mode 100644
index 0000000000..9e9ac27480
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Signup/SignUpPage/SignUpPage.stories.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureCustomSignUp from '../../../../components/CustomSignUp';
+import GoogleLoginButton from '../../../../containers/GoogleLoginButton';
+import { chromaticSmallScreen } from '../../config/chromatic';
+
+export default {
+ title: 'Form/Signup/SignUpPage',
+ decorators: decorators,
+ component: PureCustomSignUp,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = { GoogleLoginButton: };
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Not_Chrome = Template.bind({});
+Not_Chrome.args = { GoogleLoginButton: , isChrome: false };
+Not_Chrome.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const Invalid_token = Template.bind({});
+Invalid_token.args = {
+ GoogleLoginButton: ,
+ isChrome: false,
+ errorMessage: 'This invitation has already been used, please log in to access this farm',
+};
+Invalid_token.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.js b/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.js
deleted file mode 100644
index 9f9e494d97..0000000000
--- a/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import PureAbandonTask from '../../../components/Task/AbandonTask';
-
-export default {
- title: 'Page/Task/AbandonedTask',
- decorators: decorators,
- component: PureAbandonTask,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- // useHookFormPersist: () => {},
- onSubmit: () => console.log('onSubmit called'),
- onGoBack: () => console.log('handleGoBack called'),
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.jsx b/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.jsx
new file mode 100644
index 0000000000..9a3afa3f7e
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/AbandonTask.stories.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import PureAbandonTask from '../../../components/Task/AbandonTask';
+
+export default {
+ title: 'Page/Task/AbandonedTask',
+ decorators: decorators,
+ component: PureAbandonTask,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ // useHookFormPersist: () => ({}),
+ onSubmit: () => console.log('onSubmit called'),
+ onGoBack: () => console.log('handleGoBack called'),
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.js b/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.js
deleted file mode 100644
index a0ac8be043..0000000000
--- a/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import { PureManageCustomTasks } from '../../../components/Task/PureTaskTypeSelection/PureManageCustomTasks';
-
-export default {
- title: 'Page/Task/PureManageCustomTasks',
- decorators: decorators,
- component: PureManageCustomTasks,
-};
-const customTasks = [
- {
- task_type_id: 93,
- task_name: 'custom 1',
- task_translation_key: 'custom 1',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- deleted: false,
- },
- {
- task_type_id: 94,
- task_name: 'custom 2',
- task_translation_key: 'custom 2',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- deleted: false,
- },
-];
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- useHookFormPersist: () => {},
- persistedFormData: {},
- customTasks,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.jsx b/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.jsx
new file mode 100644
index 0000000000..42daadbd5f
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/PureManageCustomTasks.stories.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import { PureManageCustomTasks } from '../../../components/Task/PureTaskTypeSelection/PureManageCustomTasks';
+
+export default {
+ title: 'Page/Task/PureManageCustomTasks',
+ decorators: decorators,
+ component: PureManageCustomTasks,
+};
+const customTasks = [
+ {
+ task_type_id: 93,
+ task_name: 'custom 1',
+ task_translation_key: 'custom 1',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ deleted: false,
+ },
+ {
+ task_type_id: 94,
+ task_name: 'custom 2',
+ task_translation_key: 'custom 2',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ deleted: false,
+ },
+];
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {},
+ customTasks,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.js b/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.js
deleted file mode 100644
index cc80922a6e..0000000000
--- a/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.js
+++ /dev/null
@@ -1,159 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import { PureTaskTypeSelection } from '../../../components/Task/PureTaskTypeSelection/PureTaskTypeSelection';
-
-export default {
- title: 'Page/Task/PureTaskTypeSelection',
- decorators: decorators,
- component: PureTaskTypeSelection,
-};
-const taskTypes = [
- {
- task_type_id: 1,
- task_name: 'Bed Preparation',
- task_translation_key: 'BED_PREPARATION_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 3,
- task_name: 'Sales',
- task_translation_key: 'SALE_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 7,
- task_name: 'Scouting',
- task_translation_key: 'SCOUTING_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 8,
- task_name: 'Harvesting',
- task_translation_key: 'HARVEST_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 10,
- task_name: 'Wash and Pack',
- task_translation_key: 'WASH_AND_PACK_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 11,
- task_name: 'Pest Control',
- task_translation_key: 'PEST_CONTROL_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 12,
- task_name: 'Other',
- task_translation_key: 'OTHER_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 68,
- task_name: 'Break',
- task_translation_key: 'BREAK_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 89,
- task_name: 'Soil Sample Results',
- task_translation_key: 'SOIL_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 90,
- task_name: 'Irrigation',
- task_translation_key: 'IRRIGATION_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 2,
- task_name: 'Transport',
- task_translation_key: 'TRANSPORT_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 9,
- task_name: 'Field Work',
- task_translation_key: 'FIELD_WORK_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 4,
- task_name: 'Social',
- task_translation_key: 'SOCIAL_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 91,
- task_name: 'Cleaning',
- task_translation_key: 'CLEANING_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 6,
- task_name: 'Soil Amendment',
- task_translation_key: 'SOIL_AMENDMENT_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 5,
- task_name: 'Planting',
- task_translation_key: 'PLANT_TASK',
- farm_id: null,
- deleted: false,
- },
- {
- task_type_id: 92,
- task_name: 'Transplant',
- task_translation_key: 'TRANSPLANT_TASK',
- farm_id: null,
- deleted: false,
- },
-];
-const customTasks = [
- {
- task_type_id: 93,
- task_name: 'custom 1',
- task_translation_key: 'custom 1',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- deleted: false,
- },
- {
- task_type_id: 94,
- task_name: 'custom 2',
- task_translation_key: 'custom 2',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- deleted: false,
- },
-];
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- useHookFormPersist: () => {},
- persistedFormData: {},
- taskTypes,
- customTasks,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.jsx b/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.jsx
new file mode 100644
index 0000000000..70dc552063
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/PureTaskTypeSelection.stories.jsx
@@ -0,0 +1,159 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import { PureTaskTypeSelection } from '../../../components/Task/PureTaskTypeSelection/PureTaskTypeSelection';
+
+export default {
+ title: 'Page/Task/PureTaskTypeSelection',
+ decorators: decorators,
+ component: PureTaskTypeSelection,
+};
+const taskTypes = [
+ {
+ task_type_id: 1,
+ task_name: 'Bed Preparation',
+ task_translation_key: 'BED_PREPARATION_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 3,
+ task_name: 'Sales',
+ task_translation_key: 'SALE_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 7,
+ task_name: 'Scouting',
+ task_translation_key: 'SCOUTING_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 8,
+ task_name: 'Harvesting',
+ task_translation_key: 'HARVEST_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 10,
+ task_name: 'Wash and Pack',
+ task_translation_key: 'WASH_AND_PACK_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 11,
+ task_name: 'Pest Control',
+ task_translation_key: 'PEST_CONTROL_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 12,
+ task_name: 'Other',
+ task_translation_key: 'OTHER_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 68,
+ task_name: 'Break',
+ task_translation_key: 'BREAK_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 89,
+ task_name: 'Soil Sample Results',
+ task_translation_key: 'SOIL_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 90,
+ task_name: 'Irrigation',
+ task_translation_key: 'IRRIGATION_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 2,
+ task_name: 'Transport',
+ task_translation_key: 'TRANSPORT_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 9,
+ task_name: 'Field Work',
+ task_translation_key: 'FIELD_WORK_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 4,
+ task_name: 'Social',
+ task_translation_key: 'SOCIAL_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 91,
+ task_name: 'Cleaning',
+ task_translation_key: 'CLEANING_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 6,
+ task_name: 'Soil Amendment',
+ task_translation_key: 'SOIL_AMENDMENT_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 5,
+ task_name: 'Planting',
+ task_translation_key: 'PLANT_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+ {
+ task_type_id: 92,
+ task_name: 'Transplant',
+ task_translation_key: 'TRANSPLANT_TASK',
+ farm_id: null,
+ deleted: false,
+ },
+];
+const customTasks = [
+ {
+ task_type_id: 93,
+ task_name: 'custom 1',
+ task_translation_key: 'custom 1',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ deleted: false,
+ },
+ {
+ task_type_id: 94,
+ task_name: 'custom 2',
+ task_translation_key: 'custom 2',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ deleted: false,
+ },
+];
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ useHookFormPersist: () => ({}),
+ persistedFormData: {},
+ taskTypes,
+ customTasks,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.js b/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.js
deleted file mode 100644
index d545d55395..0000000000
--- a/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import PureTaskAssignment from '../../../../components/Task/PureTaskAssignment';
-
-export default {
- title: 'Page/Task/AddTask',
- decorators: decorators,
- component: PureTaskAssignment,
-};
-const userFarmOptions = [
- { label: 'Apple', value: 'apple' },
- { label: 'Banana', value: 'banana' },
- { label: 'Strawberry', value: 'strawberry' },
- { label: 'Kiwi', value: 'kiwi' },
- { label: 'Mango', value: 'mango' },
- { label: 'Banana Apple', value: 'bananaapple' },
-];
-
-const moreThanEightUsers = [
- { label: 'Coconut', value: 'coconut' },
- { label: 'Blueberry', value: 'blueberry' },
- { label: 'Orange', value: 'orange' },
- { label: 'Raspberry', value: 'raspberry' },
- { label: 'Apple', value: 'apple' },
- { label: 'Banana', value: 'banana' },
- { label: 'Strawberry', value: 'strawberry' },
- { label: 'Kiwi', value: 'kiwi' },
- { label: 'Mango', value: 'mango' },
- { label: 'Banana Apple', value: 'bananaapple' },
-];
-
-const oneUser = [{ label: 'Apple', value: 'apple' }];
-
-const Template = (args) => ;
-
-export const TaskAssignment = Template.bind({});
-TaskAssignment.args = {
- useHookFormPersist: () => {},
- onSubmit: () => console.log('onSave called'),
- handleGoBack: () => console.log('handleGoBack called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- userFarmOptions: userFarmOptions,
-};
-
-export const TaskAssignmentFarmWorker = Template.bind({});
-TaskAssignmentFarmWorker.args = {
- useHookFormPersist: () => {},
- onSubmit: () => console.log('onSave called'),
- handleGoBack: () => console.log('handleGoBack called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- userFarmOptions: oneUser,
- isFarmWorker: true,
-};
-
-export const TaskAssignmentOneUser = Template.bind({});
-TaskAssignmentOneUser.args = {
- useHookFormPersist: () => {},
- onSubmit: () => console.log('onSave called'),
- handleGoBack: () => console.log('handleGoBack called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- userFarmOptions: oneUser,
-};
-
-export const TaskAssignmentMoreThanEightUsers = Template.bind({});
-TaskAssignmentMoreThanEightUsers.args = {
- onSubmit: () => console.log('onSave called'),
- handleGoBack: () => console.log('handleGoBack called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- userFarmOptions: moreThanEightUsers,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.jsx b/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.jsx
new file mode 100644
index 0000000000..e49e0fd53a
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/TaskAssignment/TaskAssignment.stories.jsx
@@ -0,0 +1,74 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import PureTaskAssignment from '../../../../components/Task/PureTaskAssignment';
+
+export default {
+ title: 'Page/Task/AddTask',
+ decorators: decorators,
+ component: PureTaskAssignment,
+};
+const userFarmOptions = [
+ { label: 'Apple', value: 'apple' },
+ { label: 'Banana', value: 'banana' },
+ { label: 'Strawberry', value: 'strawberry' },
+ { label: 'Kiwi', value: 'kiwi' },
+ { label: 'Mango', value: 'mango' },
+ { label: 'Banana Apple', value: 'bananaapple' },
+];
+
+const moreThanEightUsers = [
+ { label: 'Coconut', value: 'coconut' },
+ { label: 'Blueberry', value: 'blueberry' },
+ { label: 'Orange', value: 'orange' },
+ { label: 'Raspberry', value: 'raspberry' },
+ { label: 'Apple', value: 'apple' },
+ { label: 'Banana', value: 'banana' },
+ { label: 'Strawberry', value: 'strawberry' },
+ { label: 'Kiwi', value: 'kiwi' },
+ { label: 'Mango', value: 'mango' },
+ { label: 'Banana Apple', value: 'bananaapple' },
+];
+
+const oneUser = [{ label: 'Apple', value: 'apple' }];
+
+const Template = (args) => ;
+
+export const TaskAssignment = Template.bind({});
+TaskAssignment.args = {
+ useHookFormPersist: () => ({}),
+ onSubmit: () => console.log('onSave called'),
+ handleGoBack: () => console.log('handleGoBack called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ userFarmOptions: userFarmOptions,
+};
+
+export const TaskAssignmentFarmWorker = Template.bind({});
+TaskAssignmentFarmWorker.args = {
+ useHookFormPersist: () => ({}),
+ onSubmit: () => console.log('onSave called'),
+ handleGoBack: () => console.log('handleGoBack called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ userFarmOptions: oneUser,
+ isFarmWorker: true,
+};
+
+export const TaskAssignmentOneUser = Template.bind({});
+TaskAssignmentOneUser.args = {
+ useHookFormPersist: () => ({}),
+ onSubmit: () => console.log('onSave called'),
+ handleGoBack: () => console.log('handleGoBack called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ userFarmOptions: oneUser,
+};
+
+export const TaskAssignmentMoreThanEightUsers = Template.bind({});
+TaskAssignmentMoreThanEightUsers.args = {
+ onSubmit: () => console.log('onSave called'),
+ handleGoBack: () => console.log('handleGoBack called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ userFarmOptions: moreThanEightUsers,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.js b/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.js
deleted file mode 100644
index 33df456b91..0000000000
--- a/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.js
+++ /dev/null
@@ -1,2665 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import { chromaticSmallScreen } from '../config/chromatic';
-import PureTaskCrops from '../../../components/Task/PureTaskCrops';
-
-export default {
- title: 'Form/Task/PureTaskCrops',
- decorators: decorators,
- component: PureTaskCrops,
-};
-const managementPlansByLocationIds = {
- '57bb2bb8-59fc-4a6c-9814-63e8664a7461': [
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1165,
- notes: '4',
- name: 'Plan 4',
- start_date: null,
- complete_date: null,
- abandon_date: '2021-08-18T07:00:00.000Z',
- complete_notes: '',
- abandon_reason: null,
- rating: 3,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-30T07:00:00.000Z',
- harvest_date: '2021-09-01T07:00:00.000Z',
- is_seed: false,
- is_wild: null,
- needs_transplant: true,
- plant_date: '2021-08-29T07:00:00.000Z',
- seed_date: '2021-08-24T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-31T07:00:00.000Z',
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-30T07:00:00.000Z',
- harvest_date: '2021-09-01T07:00:00.000Z',
- is_seed: false,
- is_wild: null,
- management_plan_id: 1165,
- needs_transplant: true,
- plant_date: '2021-08-29T07:00:00.000Z',
- seed_date: '2021-08-24T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-31T07:00:00.000Z',
- },
- planting_management_plans: {
- initial: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: false,
- is_planting_method_known: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- management_plan_id: 1165,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: 'c9472347-9c24-4c65-93e8-076003deddcd',
- planting_method: 'CONTAINER_METHOD',
- container_method: {
- container_type: null,
- in_ground: true,
- number_of_containers: null,
- plant_spacing: 0.101599996749,
- plant_spacing_unit: 'in',
- planting_depth: 0.076199997562,
- planting_depth_unit: 'in',
- planting_management_plan_id: 'c9472347-9c24-4c65-93e8-076003deddcd',
- planting_soil: null,
- plants_per_container: null,
- total_plants: 2,
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- management_plan_id: 1165,
- notes: '2',
- pin_coordinate: null,
- planting_management_plan_id: '84198403-349a-4354-bfa2-06bced3b4078',
- planting_method: 'ROW_METHOD',
- row_method: {
- number_of_rows: null,
- plant_spacing: 0.076199997562,
- plant_spacing_unit: 'in',
- planting_depth: 0.126999995936,
- planting_depth_unit: 'in',
- planting_management_plan_id: '84198403-349a-4354-bfa2-06bced3b4078',
- row_length: null,
- row_length_unit: 'cm',
- row_spacing: 0.025399999187,
- row_spacing_unit: 'in',
- row_width: 0.152399995123,
- row_width_unit: 'in',
- same_length: false,
- specify_rows: '4',
- total_rows_length: 0.050799998374,
- total_rows_length_unit: 'in',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '1',
- notes: null,
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 49628,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28051249566314,
- lng: -123.18097180426027,
- },
- {
- lat: 49.27874871033353,
- lng: -123.18311757147218,
- },
- {
- lat: 49.27877670741875,
- lng: -123.17612237036134,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.5,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.29,
- se: null,
- thiamin: 0.65,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: true,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- treated: 'NO',
- management_plan_id: 1171,
- notes: '',
- name: 'Plan 3',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-27T07:00:00.000Z',
- harvest_date: '2021-09-18T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-04T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-09-07T07:00:00.000Z',
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-27T07:00:00.000Z',
- harvest_date: '2021-09-18T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- management_plan_id: 1171,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-04T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-09-07T07:00:00.000Z',
- },
- planting_management_plans: {
- initial: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: false,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1171,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: '93dd010e-41be-4b67-a846-e17197cfe7b2',
- planting_method: 'CONTAINER_METHOD',
- container_method: {
- container_type: null,
- in_ground: false,
- number_of_containers: 23,
- plant_spacing: null,
- plant_spacing_unit: 'cm',
- planting_depth: null,
- planting_depth_unit: 'in',
- planting_management_plan_id: '93dd010e-41be-4b67-a846-e17197cfe7b2',
- planting_soil: null,
- plants_per_container: 33,
- total_plants: null,
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- management_plan_id: 1171,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: '96fa8115-56c5-4aad-9bb5-ae3ab8c5f4b4',
- planting_method: 'ROW_METHOD',
- row_method: {
- number_of_rows: 3,
- plant_spacing: 0.076199997562,
- plant_spacing_unit: 'in',
- planting_depth: null,
- planting_depth_unit: 'in',
- planting_management_plan_id: '96fa8115-56c5-4aad-9bb5-ae3ab8c5f4b4',
- row_length: 0.076199997562,
- row_length_unit: 'in',
- row_spacing: null,
- row_spacing_unit: 'in',
- row_width: null,
- row_width_unit: 'in',
- same_length: true,
- specify_rows: null,
- total_rows_length: null,
- total_rows_length_unit: 'cm',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '1',
- notes: null,
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 49628,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28051249566314,
- lng: -123.18097180426027,
- },
- {
- lat: 49.27874871033353,
- lng: -123.18311757147218,
- },
- {
- lat: 49.27877670741875,
- lng: -123.17612237036134,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.498,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: null,
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.943,
- na: 12,
- niacin: 4.604,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.285,
- se: null,
- thiamin: 0.646,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.318,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 33,
- compliance_file_url: '',
- crop_id: 9,
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 0.5,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- folate: 19,
- genetically_engineered: null,
- k: 452,
- lifecycle: 'PERENNIAL',
- lipid: 2.3,
- mg: 133,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- organic: true,
- ph: 264,
- protein: 12.48,
- riboflavin: 0.29,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- thiamin: 0.65,
- treated: 'NO',
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- zn: 2.77,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- ],
- '1f31e024-2e98-44e4-9837-80f52d8ab010': [
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1163,
- notes: '2',
- name: 'Plan 2',
- start_date: null,
- complete_date: null,
- abandon_date: '2021-08-18T07:00:00.000Z',
- complete_notes: '2',
- abandon_reason: null,
- rating: 5,
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-12T07:00:00.000Z',
- is_seed: null,
- is_wild: true,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-17T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-11T07:00:00.000Z',
- crop_management_plan: {
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-12T07:00:00.000Z',
- is_seed: null,
- is_wild: true,
- management_plan_id: 1163,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-17T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-11T07:00:00.000Z',
- },
- planting_management_plans: {
- initial: {
- estimated_seeds: null,
- estimated_seeds_unit: 'kg',
- estimated_yield: null,
- estimated_yield_unit: 'kg',
- is_final_planting_management_plan: false,
- is_planting_method_known: null,
- location_id: null,
- management_plan_id: 1163,
- notes: null,
- pin_coordinate: {
- lat: 49.280801204515804,
- lng: -123.17563957273866,
- },
- planting_management_plan_id: '3788a3b4-e078-43a1-a5b6-049f808471ee',
- planting_method: null,
- },
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1163,
- notes: '5',
- pin_coordinate: null,
- planting_management_plan_id: '4c0799b8-67dc-4695-a5c3-822ff49ce662',
- planting_method: 'BED_METHOD',
- bed_method: {
- bed_length: 0.076199997562,
- bed_length_unit: 'in',
- bed_spacing: 0.101599996749,
- bed_spacing_unit: 'in',
- bed_width: 0.076199997562,
- bed_width_unit: 'in',
- number_of_beds: 1,
- number_of_rows_in_bed: 2,
- plant_spacing: 0.101599996749,
- plant_spacing_unit: 'in',
- planting_depth: 0.050799998374,
- planting_depth_unit: 'in',
- planting_management_plan_id: '4c0799b8-67dc-4695-a5c3-822ff49ce662',
- specify_beds: '1',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.5,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.29,
- se: null,
- thiamin: 0.65,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: true,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- treated: 'NO',
- management_plan_id: 1166,
- notes: '2',
- name: 'Plan 1',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-13T07:00:00.000Z',
- harvest_date: '2021-08-14T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- needs_transplant: false,
- plant_date: null,
- seed_date: '2021-08-12T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-13T07:00:00.000Z',
- harvest_date: '2021-08-14T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- management_plan_id: 1166,
- needs_transplant: false,
- plant_date: null,
- seed_date: '2021-08-12T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: 0.907184,
- estimated_seeds_unit: 'lb',
- estimated_yield: 1.814368,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1166,
- notes: '1',
- pin_coordinate: null,
- planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
- planting_method: 'BED_METHOD',
- bed_method: {
- bed_length: 0.101599996749,
- bed_length_unit: 'in',
- bed_spacing: 0.152399995123,
- bed_spacing_unit: 'in',
- bed_width: 0.126999995936,
- bed_width_unit: 'in',
- number_of_beds: 1,
- number_of_rows_in_bed: 2,
- plant_spacing: 0.076199997562,
- plant_spacing_unit: 'in',
- planting_depth: 0.101599996749,
- planting_depth_unit: 'in',
- planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
- specify_beds: '3',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.498,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: null,
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.943,
- na: 12,
- niacin: 4.604,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.285,
- se: null,
- thiamin: 0.646,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.318,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 33,
- compliance_file_url: '',
- crop_id: 9,
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 0.5,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- folate: 19,
- genetically_engineered: null,
- k: 452,
- lifecycle: 'PERENNIAL',
- lipid: 2.3,
- mg: 133,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- organic: true,
- ph: 264,
- protein: 12.48,
- riboflavin: 0.29,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- thiamin: 0.65,
- treated: 'NO',
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- zn: 2.77,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.5,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.29,
- se: null,
- thiamin: 0.65,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: true,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- treated: 'NO',
- management_plan_id: 1167,
- notes: '3',
- name: 'Plan 2',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-21T07:00:00.000Z',
- harvest_date: '2021-08-23T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-20T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-22T07:00:00.000Z',
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-21T07:00:00.000Z',
- harvest_date: '2021-08-23T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- management_plan_id: 1167,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-20T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-22T07:00:00.000Z',
- },
- planting_management_plans: {
- initial: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: false,
- is_planting_method_known: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- management_plan_id: 1167,
- notes: '2',
- pin_coordinate: null,
- planting_management_plan_id: '8d1d2917-8f9d-4630-aee4-4204f52edb59',
- planting_method: 'CONTAINER_METHOD',
- container_method: {
- container_type: null,
- in_ground: true,
- number_of_containers: null,
- plant_spacing: 0.101599996749,
- plant_spacing_unit: 'in',
- planting_depth: 0.076199997562,
- planting_depth_unit: 'in',
- planting_management_plan_id: '8d1d2917-8f9d-4630-aee4-4204f52edb59',
- planting_soil: null,
- plants_per_container: null,
- total_plants: 12,
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1167,
- notes: '5',
- pin_coordinate: null,
- planting_management_plan_id: 'ddbefc00-b72a-495a-89c6-bef7dcf9f50a',
- planting_method: 'BED_METHOD',
- bed_method: {
- bed_length: 0.101599996749,
- bed_length_unit: 'in',
- bed_spacing: 0.101599996749,
- bed_spacing_unit: 'in',
- bed_width: 0.076199997562,
- bed_width_unit: 'in',
- number_of_beds: 2,
- number_of_rows_in_bed: 3,
- plant_spacing: 0.050799998374,
- plant_spacing_unit: 'in',
- planting_depth: 0.050799998374,
- planting_depth_unit: 'in',
- planting_management_plan_id: 'ddbefc00-b72a-495a-89c6-bef7dcf9f50a',
- specify_beds: '1',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 33,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare ',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- cu: 0.498,
- depletion_fraction: 0.55,
- end_kc: 0.25,
- energy: 354,
- farm_id: null,
- fe: 3.6,
- fl: null,
- folate: 19,
- initial_kc: 0.3,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 452,
- lipid: 2.3,
- max_height: 1,
- max_rooting_depth: 1.25,
- mg: 133,
- mid_kc: 1.15,
- mn: 1.943,
- na: 12,
- niacin: 4.604,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 0,
- ph: 264,
- protein: 12.48,
- refuse: null,
- reviewed: true,
- riboflavin: 0.285,
- se: null,
- thiamin: 0.646,
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.318,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 2.77,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 33,
- compliance_file_url: '',
- crop_id: 9,
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- crop_variety_photo_url:
- 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 0.5,
- energy: 354,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.6,
- folate: 19,
- genetically_engineered: null,
- k: 452,
- lifecycle: 'PERENNIAL',
- lipid: 2.3,
- mg: 133,
- mn: 1.94,
- na: 12,
- niacin: 4.6,
- nutrient_credits: null,
- organic: true,
- ph: 264,
- protein: 12.48,
- riboflavin: 0.29,
- searched: null,
- seeding_type: 'SEED',
- supplier: '2',
- thiamin: 0.65,
- treated: 'NO',
- vita_rae: 1,
- vitb12: 0,
- vitb6: 0.32,
- vitc: 0,
- zn: 2.77,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1172,
- notes: '',
- name: 'Plan 5',
- start_date: null,
- complete_date: null,
- abandon_date: '2021-08-18T07:00:00.000Z',
- complete_notes: '2',
- abandon_reason: null,
- rating: 3,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-18T07:00:00.000Z',
- harvest_date: '2021-08-19T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- needs_transplant: false,
- plant_date: null,
- seed_date: '2021-08-17T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-18T07:00:00.000Z',
- harvest_date: '2021-08-19T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- management_plan_id: 1172,
- needs_transplant: false,
- plant_date: null,
- seed_date: '2021-08-17T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1172,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: '7f59a3d9-736e-45f5-a3be-6074905ca068',
- planting_method: 'CONTAINER_METHOD',
- container_method: {
- container_type: null,
- in_ground: true,
- number_of_containers: null,
- plant_spacing: 0.050799998374,
- plant_spacing_unit: 'in',
- planting_depth: 0.050799998374,
- planting_depth_unit: 'in',
- planting_management_plan_id: '7f59a3d9-736e-45f5-a3be-6074905ca068',
- planting_soil: null,
- plants_per_container: null,
- total_plants: 1,
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1177,
- notes: '',
- name: 'Plan 10',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: true,
- for_cover: false,
- harvest_date: '2021-08-21T07:00:00.000Z',
- is_wild: false,
- needs_transplant: false,
- estimated_revenue: null,
- germination_date: null,
- is_seed: null,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- transplant_date: null,
- crop_management_plan: {
- already_in_ground: true,
- for_cover: false,
- harvest_date: '2021-08-21T07:00:00.000Z',
- is_wild: false,
- management_plan_id: 1177,
- needs_transplant: false,
- estimated_revenue: null,
- germination_date: null,
- is_seed: null,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- transplant_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: false,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1177,
- planting_management_plan_id: '63af6dd8-1bfc-43c2-b5be-470180cf6b05',
- estimated_seeds: null,
- estimated_seeds_unit: 'kg',
- estimated_yield: null,
- notes: null,
- pin_coordinate: null,
- planting_method: null,
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1178,
- notes: '',
- name: 'Plan 11',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: true,
- for_cover: false,
- harvest_date: '2021-08-29T07:00:00.000Z',
- is_wild: true,
- needs_transplant: true,
- transplant_date: '2021-08-26T07:00:00.000Z',
- estimated_revenue: null,
- germination_date: null,
- is_seed: null,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- crop_management_plan: {
- already_in_ground: true,
- for_cover: false,
- harvest_date: '2021-08-29T07:00:00.000Z',
- is_wild: true,
- management_plan_id: 1178,
- needs_transplant: true,
- transplant_date: '2021-08-26T07:00:00.000Z',
- estimated_revenue: null,
- germination_date: null,
- is_seed: null,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1178,
- notes: '7',
- planting_management_plan_id: 'd746e2f4-ea9a-4ae5-860b-e27ce40b4db1',
- planting_method: 'BED_METHOD',
- is_planting_method_known: null,
- pin_coordinate: null,
- bed_method: {
- bed_length: 0.076199997562,
- bed_length_unit: 'in',
- bed_spacing: 0.152399995123,
- bed_spacing_unit: 'in',
- bed_width: 0.126999995936,
- bed_width_unit: 'in',
- number_of_beds: 2,
- number_of_rows_in_bed: 3,
- plant_spacing: 0.076199997562,
- plant_spacing_unit: 'in',
- planting_depth: 0.101599996749,
- planting_depth_unit: 'in',
- planting_management_plan_id: 'd746e2f4-ea9a-4ae5-860b-e27ce40b4db1',
- specify_beds: '3',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- initial: {
- estimated_yield_unit: 'kg',
- is_final_planting_management_plan: false,
- management_plan_id: 1178,
- pin_coordinate: {
- lat: 49.27961573769133,
- lng: -123.17777789712291,
- },
- planting_management_plan_id: 'd80dacdd-954e-433a-905a-3cf1ecf9f30a',
- estimated_seeds: null,
- estimated_seeds_unit: 'kg',
- estimated_yield: null,
- is_planting_method_known: null,
- location_id: null,
- notes: null,
- planting_method: null,
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- ],
- '61f7cd2c-c09d-43cf-9687-a0502236acfd': [
- {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.03,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.14,
- se: null,
- thiamin: 0.21,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- compliance_file_url: '',
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- genetically_engineered: null,
- lifecycle: 'PERENNIAL',
- organic: null,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- treated: null,
- management_plan_id: 1162,
- notes: '2',
- name: 'Plan 1',
- start_date: null,
- complete_date: '2021-08-18T07:00:00.000Z',
- abandon_date: null,
- complete_notes: '',
- abandon_reason: null,
- rating: 3,
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-15T07:00:00.000Z',
- is_seed: null,
- is_wild: true,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-24T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-13T07:00:00.000Z',
- crop_management_plan: {
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-15T07:00:00.000Z',
- is_seed: null,
- is_wild: true,
- management_plan_id: 1162,
- needs_transplant: true,
- plant_date: null,
- seed_date: '2021-08-24T07:00:00.000Z',
- termination_date: null,
- transplant_date: '2021-08-13T07:00:00.000Z',
- },
- planting_management_plans: {
- initial: {
- estimated_seeds: null,
- estimated_seeds_unit: 'kg',
- estimated_yield: null,
- estimated_yield_unit: 'kg',
- is_final_planting_management_plan: false,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1162,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: '12d43ad9-1baf-4a80-86a8-5dd8e46bc189',
- planting_method: null,
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 0,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- management_plan_id: 1162,
- notes: '5',
- pin_coordinate: null,
- planting_management_plan_id: 'ae141eae-9f01-4c6f-adc8-42ca2c43c42d',
- planting_method: 'BED_METHOD',
- bed_method: {
- bed_length: 0.101599996749,
- bed_length_unit: 'in',
- bed_spacing: 0.101599996749,
- bed_spacing_unit: 'in',
- bed_width: 0.076199997562,
- bed_width_unit: 'in',
- number_of_beds: 2,
- number_of_rows_in_bed: 3,
- plant_spacing: 0.126999995936,
- plant_spacing_unit: 'in',
- planting_depth: 0.050799998374,
- planting_depth_unit: 'in',
- planting_management_plan_id: 'ae141eae-9f01-4c6f-adc8-42ca2c43c42d',
- specify_beds: '1',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- ca: 269,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis ',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- cu: 1.031,
- depletion_fraction: 0.4,
- end_kc: 0.6518,
- energy: 579,
- farm_id: null,
- fe: 3.71,
- fl: null,
- folate: 44,
- initial_kc: 0.4,
- is_avg_depth: false,
- is_avg_kc: false,
- is_avg_nutrient: false,
- k: 733,
- lipid: 49.93,
- max_height: 5,
- max_rooting_depth: 1.5,
- mg: 270,
- mid_kc: 0.9,
- mn: 2.179,
- na: 1,
- niacin: 3.618,
- nutrient_credits: null,
- nutrient_notes: null,
- pantothenic: null,
- percentrefuse: 60,
- ph: 481,
- protein: 21.15,
- refuse: null,
- reviewed: true,
- riboflavin: 1.138,
- se: null,
- thiamin: 0.205,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.137,
- vitc: 0,
- vite: null,
- vitk: null,
- zn: 3.12,
- can_be_cover_crop: null,
- planting_depth: null,
- yield_per_area: null,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- crop_variety: {
- ca: 269,
- compliance_file_url: '',
- crop_id: 32,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- crop_variety_photo_url:
- 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- yield_per_area: null,
- planting_depth: null,
- can_be_cover_crop: null,
- cu: 1.03,
- energy: 579,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- fe: 3.71,
- folate: 44,
- genetically_engineered: null,
- k: 733,
- lifecycle: 'PERENNIAL',
- lipid: 49.93,
- mg: 270,
- mn: 2.18,
- na: 1,
- niacin: 3.62,
- nutrient_credits: null,
- organic: null,
- ph: 481,
- protein: 21.15,
- riboflavin: 1.14,
- searched: null,
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- supplier: '2',
- thiamin: 0.21,
- treated: null,
- vita_rae: 0,
- vitb12: 0,
- vitb6: 0.14,
- vitc: 0,
- zn: 3.12,
- average_seed_weight: null,
- yield_per_plant: null,
- },
- firstTaskDate: 1629356400000,
- status: 'planned',
- },
- ],
-};
-
-const persistedFormData = {
- managementPlans: [
- {
- management_plan_id: 1171,
- },
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1172,
- },
- ],
- locations: [
- {
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- },
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- managementPlansByLocationIds,
- useHookFormPersist: () => {},
- persistedFormData,
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.jsx b/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.jsx
new file mode 100644
index 0000000000..a05702d7f7
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/TaskCrops.stories.jsx
@@ -0,0 +1,2665 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import { chromaticSmallScreen } from '../config/chromatic';
+import PureTaskCrops from '../../../components/Task/PureTaskCrops';
+
+export default {
+ title: 'Form/Task/PureTaskCrops',
+ decorators: decorators,
+ component: PureTaskCrops,
+};
+const managementPlansByLocationIds = {
+ '57bb2bb8-59fc-4a6c-9814-63e8664a7461': [
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1165,
+ notes: '4',
+ name: 'Plan 4',
+ start_date: null,
+ complete_date: null,
+ abandon_date: '2021-08-18T07:00:00.000Z',
+ complete_notes: '',
+ abandon_reason: null,
+ rating: 3,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-30T07:00:00.000Z',
+ harvest_date: '2021-09-01T07:00:00.000Z',
+ is_seed: false,
+ is_wild: null,
+ needs_transplant: true,
+ plant_date: '2021-08-29T07:00:00.000Z',
+ seed_date: '2021-08-24T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-31T07:00:00.000Z',
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-30T07:00:00.000Z',
+ harvest_date: '2021-09-01T07:00:00.000Z',
+ is_seed: false,
+ is_wild: null,
+ management_plan_id: 1165,
+ needs_transplant: true,
+ plant_date: '2021-08-29T07:00:00.000Z',
+ seed_date: '2021-08-24T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-31T07:00:00.000Z',
+ },
+ planting_management_plans: {
+ initial: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: false,
+ is_planting_method_known: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ management_plan_id: 1165,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: 'c9472347-9c24-4c65-93e8-076003deddcd',
+ planting_method: 'CONTAINER_METHOD',
+ container_method: {
+ container_type: null,
+ in_ground: true,
+ number_of_containers: null,
+ plant_spacing: 0.101599996749,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.076199997562,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: 'c9472347-9c24-4c65-93e8-076003deddcd',
+ planting_soil: null,
+ plants_per_container: null,
+ total_plants: 2,
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ management_plan_id: 1165,
+ notes: '2',
+ pin_coordinate: null,
+ planting_management_plan_id: '84198403-349a-4354-bfa2-06bced3b4078',
+ planting_method: 'ROW_METHOD',
+ row_method: {
+ number_of_rows: null,
+ plant_spacing: 0.076199997562,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.126999995936,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '84198403-349a-4354-bfa2-06bced3b4078',
+ row_length: null,
+ row_length_unit: 'cm',
+ row_spacing: 0.025399999187,
+ row_spacing_unit: 'in',
+ row_width: 0.152399995123,
+ row_width_unit: 'in',
+ same_length: false,
+ specify_rows: '4',
+ total_rows_length: 0.050799998374,
+ total_rows_length_unit: 'in',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '1',
+ notes: null,
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 49628,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28051249566314,
+ lng: -123.18097180426027,
+ },
+ {
+ lat: 49.27874871033353,
+ lng: -123.18311757147218,
+ },
+ {
+ lat: 49.27877670741875,
+ lng: -123.17612237036134,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.5,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.29,
+ se: null,
+ thiamin: 0.65,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: true,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ treated: 'NO',
+ management_plan_id: 1171,
+ notes: '',
+ name: 'Plan 3',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-27T07:00:00.000Z',
+ harvest_date: '2021-09-18T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-04T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-09-07T07:00:00.000Z',
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-27T07:00:00.000Z',
+ harvest_date: '2021-09-18T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ management_plan_id: 1171,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-04T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-09-07T07:00:00.000Z',
+ },
+ planting_management_plans: {
+ initial: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: false,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1171,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: '93dd010e-41be-4b67-a846-e17197cfe7b2',
+ planting_method: 'CONTAINER_METHOD',
+ container_method: {
+ container_type: null,
+ in_ground: false,
+ number_of_containers: 23,
+ plant_spacing: null,
+ plant_spacing_unit: 'cm',
+ planting_depth: null,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '93dd010e-41be-4b67-a846-e17197cfe7b2',
+ planting_soil: null,
+ plants_per_container: 33,
+ total_plants: null,
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ management_plan_id: 1171,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: '96fa8115-56c5-4aad-9bb5-ae3ab8c5f4b4',
+ planting_method: 'ROW_METHOD',
+ row_method: {
+ number_of_rows: 3,
+ plant_spacing: 0.076199997562,
+ plant_spacing_unit: 'in',
+ planting_depth: null,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '96fa8115-56c5-4aad-9bb5-ae3ab8c5f4b4',
+ row_length: 0.076199997562,
+ row_length_unit: 'in',
+ row_spacing: null,
+ row_spacing_unit: 'in',
+ row_width: null,
+ row_width_unit: 'in',
+ same_length: true,
+ specify_rows: null,
+ total_rows_length: null,
+ total_rows_length_unit: 'cm',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '1',
+ notes: null,
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 49628,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28051249566314,
+ lng: -123.18097180426027,
+ },
+ {
+ lat: 49.27874871033353,
+ lng: -123.18311757147218,
+ },
+ {
+ lat: 49.27877670741875,
+ lng: -123.17612237036134,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.498,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: null,
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.943,
+ na: 12,
+ niacin: 4.604,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.285,
+ se: null,
+ thiamin: 0.646,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.318,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 33,
+ compliance_file_url: '',
+ crop_id: 9,
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 0.5,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ folate: 19,
+ genetically_engineered: null,
+ k: 452,
+ lifecycle: 'PERENNIAL',
+ lipid: 2.3,
+ mg: 133,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ organic: true,
+ ph: 264,
+ protein: 12.48,
+ riboflavin: 0.29,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ thiamin: 0.65,
+ treated: 'NO',
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ zn: 2.77,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ ],
+ '1f31e024-2e98-44e4-9837-80f52d8ab010': [
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1163,
+ notes: '2',
+ name: 'Plan 2',
+ start_date: null,
+ complete_date: null,
+ abandon_date: '2021-08-18T07:00:00.000Z',
+ complete_notes: '2',
+ abandon_reason: null,
+ rating: 5,
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-12T07:00:00.000Z',
+ is_seed: null,
+ is_wild: true,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-17T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-11T07:00:00.000Z',
+ crop_management_plan: {
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-12T07:00:00.000Z',
+ is_seed: null,
+ is_wild: true,
+ management_plan_id: 1163,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-17T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-11T07:00:00.000Z',
+ },
+ planting_management_plans: {
+ initial: {
+ estimated_seeds: null,
+ estimated_seeds_unit: 'kg',
+ estimated_yield: null,
+ estimated_yield_unit: 'kg',
+ is_final_planting_management_plan: false,
+ is_planting_method_known: null,
+ location_id: null,
+ management_plan_id: 1163,
+ notes: null,
+ pin_coordinate: {
+ lat: 49.280801204515804,
+ lng: -123.17563957273866,
+ },
+ planting_management_plan_id: '3788a3b4-e078-43a1-a5b6-049f808471ee',
+ planting_method: null,
+ },
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1163,
+ notes: '5',
+ pin_coordinate: null,
+ planting_management_plan_id: '4c0799b8-67dc-4695-a5c3-822ff49ce662',
+ planting_method: 'BED_METHOD',
+ bed_method: {
+ bed_length: 0.076199997562,
+ bed_length_unit: 'in',
+ bed_spacing: 0.101599996749,
+ bed_spacing_unit: 'in',
+ bed_width: 0.076199997562,
+ bed_width_unit: 'in',
+ number_of_beds: 1,
+ number_of_rows_in_bed: 2,
+ plant_spacing: 0.101599996749,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.050799998374,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '4c0799b8-67dc-4695-a5c3-822ff49ce662',
+ specify_beds: '1',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.5,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.29,
+ se: null,
+ thiamin: 0.65,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: true,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ treated: 'NO',
+ management_plan_id: 1166,
+ notes: '2',
+ name: 'Plan 1',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-13T07:00:00.000Z',
+ harvest_date: '2021-08-14T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: '2021-08-12T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-13T07:00:00.000Z',
+ harvest_date: '2021-08-14T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ management_plan_id: 1166,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: '2021-08-12T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: 0.907184,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 1.814368,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1166,
+ notes: '1',
+ pin_coordinate: null,
+ planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
+ planting_method: 'BED_METHOD',
+ bed_method: {
+ bed_length: 0.101599996749,
+ bed_length_unit: 'in',
+ bed_spacing: 0.152399995123,
+ bed_spacing_unit: 'in',
+ bed_width: 0.126999995936,
+ bed_width_unit: 'in',
+ number_of_beds: 1,
+ number_of_rows_in_bed: 2,
+ plant_spacing: 0.076199997562,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.101599996749,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
+ specify_beds: '3',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.498,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: null,
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.943,
+ na: 12,
+ niacin: 4.604,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.285,
+ se: null,
+ thiamin: 0.646,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.318,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 33,
+ compliance_file_url: '',
+ crop_id: 9,
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 0.5,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ folate: 19,
+ genetically_engineered: null,
+ k: 452,
+ lifecycle: 'PERENNIAL',
+ lipid: 2.3,
+ mg: 133,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ organic: true,
+ ph: 264,
+ protein: 12.48,
+ riboflavin: 0.29,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ thiamin: 0.65,
+ treated: 'NO',
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ zn: 2.77,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.5,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.29,
+ se: null,
+ thiamin: 0.65,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: true,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ treated: 'NO',
+ management_plan_id: 1167,
+ notes: '3',
+ name: 'Plan 2',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-21T07:00:00.000Z',
+ harvest_date: '2021-08-23T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-20T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-22T07:00:00.000Z',
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-21T07:00:00.000Z',
+ harvest_date: '2021-08-23T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ management_plan_id: 1167,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-20T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-22T07:00:00.000Z',
+ },
+ planting_management_plans: {
+ initial: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: false,
+ is_planting_method_known: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ management_plan_id: 1167,
+ notes: '2',
+ pin_coordinate: null,
+ planting_management_plan_id: '8d1d2917-8f9d-4630-aee4-4204f52edb59',
+ planting_method: 'CONTAINER_METHOD',
+ container_method: {
+ container_type: null,
+ in_ground: true,
+ number_of_containers: null,
+ plant_spacing: 0.101599996749,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.076199997562,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '8d1d2917-8f9d-4630-aee4-4204f52edb59',
+ planting_soil: null,
+ plants_per_container: null,
+ total_plants: 12,
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1167,
+ notes: '5',
+ pin_coordinate: null,
+ planting_management_plan_id: 'ddbefc00-b72a-495a-89c6-bef7dcf9f50a',
+ planting_method: 'BED_METHOD',
+ bed_method: {
+ bed_length: 0.101599996749,
+ bed_length_unit: 'in',
+ bed_spacing: 0.101599996749,
+ bed_spacing_unit: 'in',
+ bed_width: 0.076199997562,
+ bed_width_unit: 'in',
+ number_of_beds: 2,
+ number_of_rows_in_bed: 3,
+ plant_spacing: 0.050799998374,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.050799998374,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: 'ddbefc00-b72a-495a-89c6-bef7dcf9f50a',
+ specify_beds: '1',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 33,
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare ',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ cu: 0.498,
+ depletion_fraction: 0.55,
+ end_kc: 0.25,
+ energy: 354,
+ farm_id: null,
+ fe: 3.6,
+ fl: null,
+ folate: 19,
+ initial_kc: 0.3,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 452,
+ lipid: 2.3,
+ max_height: 1,
+ max_rooting_depth: 1.25,
+ mg: 133,
+ mid_kc: 1.15,
+ mn: 1.943,
+ na: 12,
+ niacin: 4.604,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 0,
+ ph: 264,
+ protein: 12.48,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 0.285,
+ se: null,
+ thiamin: 0.646,
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.318,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 2.77,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 33,
+ compliance_file_url: '',
+ crop_id: 9,
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.digitaloceanspaces.com/crop_variety/47b0c009-2cf0-4aa0-9c96-572fb006cf4b.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 0.5,
+ energy: 354,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.6,
+ folate: 19,
+ genetically_engineered: null,
+ k: 452,
+ lifecycle: 'PERENNIAL',
+ lipid: 2.3,
+ mg: 133,
+ mn: 1.94,
+ na: 12,
+ niacin: 4.6,
+ nutrient_credits: null,
+ organic: true,
+ ph: 264,
+ protein: 12.48,
+ riboflavin: 0.29,
+ searched: null,
+ seeding_type: 'SEED',
+ supplier: '2',
+ thiamin: 0.65,
+ treated: 'NO',
+ vita_rae: 1,
+ vitb12: 0,
+ vitb6: 0.32,
+ vitc: 0,
+ zn: 2.77,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1172,
+ notes: '',
+ name: 'Plan 5',
+ start_date: null,
+ complete_date: null,
+ abandon_date: '2021-08-18T07:00:00.000Z',
+ complete_notes: '2',
+ abandon_reason: null,
+ rating: 3,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-18T07:00:00.000Z',
+ harvest_date: '2021-08-19T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: '2021-08-17T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-18T07:00:00.000Z',
+ harvest_date: '2021-08-19T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ management_plan_id: 1172,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: '2021-08-17T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1172,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: '7f59a3d9-736e-45f5-a3be-6074905ca068',
+ planting_method: 'CONTAINER_METHOD',
+ container_method: {
+ container_type: null,
+ in_ground: true,
+ number_of_containers: null,
+ plant_spacing: 0.050799998374,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.050799998374,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '7f59a3d9-736e-45f5-a3be-6074905ca068',
+ planting_soil: null,
+ plants_per_container: null,
+ total_plants: 1,
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1177,
+ notes: '',
+ name: 'Plan 10',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: true,
+ for_cover: false,
+ harvest_date: '2021-08-21T07:00:00.000Z',
+ is_wild: false,
+ needs_transplant: false,
+ estimated_revenue: null,
+ germination_date: null,
+ is_seed: null,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ transplant_date: null,
+ crop_management_plan: {
+ already_in_ground: true,
+ for_cover: false,
+ harvest_date: '2021-08-21T07:00:00.000Z',
+ is_wild: false,
+ management_plan_id: 1177,
+ needs_transplant: false,
+ estimated_revenue: null,
+ germination_date: null,
+ is_seed: null,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ transplant_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: false,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1177,
+ planting_management_plan_id: '63af6dd8-1bfc-43c2-b5be-470180cf6b05',
+ estimated_seeds: null,
+ estimated_seeds_unit: 'kg',
+ estimated_yield: null,
+ notes: null,
+ pin_coordinate: null,
+ planting_method: null,
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1178,
+ notes: '',
+ name: 'Plan 11',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: true,
+ for_cover: false,
+ harvest_date: '2021-08-29T07:00:00.000Z',
+ is_wild: true,
+ needs_transplant: true,
+ transplant_date: '2021-08-26T07:00:00.000Z',
+ estimated_revenue: null,
+ germination_date: null,
+ is_seed: null,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ crop_management_plan: {
+ already_in_ground: true,
+ for_cover: false,
+ harvest_date: '2021-08-29T07:00:00.000Z',
+ is_wild: true,
+ management_plan_id: 1178,
+ needs_transplant: true,
+ transplant_date: '2021-08-26T07:00:00.000Z',
+ estimated_revenue: null,
+ germination_date: null,
+ is_seed: null,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1178,
+ notes: '7',
+ planting_management_plan_id: 'd746e2f4-ea9a-4ae5-860b-e27ce40b4db1',
+ planting_method: 'BED_METHOD',
+ is_planting_method_known: null,
+ pin_coordinate: null,
+ bed_method: {
+ bed_length: 0.076199997562,
+ bed_length_unit: 'in',
+ bed_spacing: 0.152399995123,
+ bed_spacing_unit: 'in',
+ bed_width: 0.126999995936,
+ bed_width_unit: 'in',
+ number_of_beds: 2,
+ number_of_rows_in_bed: 3,
+ plant_spacing: 0.076199997562,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.101599996749,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: 'd746e2f4-ea9a-4ae5-860b-e27ce40b4db1',
+ specify_beds: '3',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ initial: {
+ estimated_yield_unit: 'kg',
+ is_final_planting_management_plan: false,
+ management_plan_id: 1178,
+ pin_coordinate: {
+ lat: 49.27961573769133,
+ lng: -123.17777789712291,
+ },
+ planting_management_plan_id: 'd80dacdd-954e-433a-905a-3cf1ecf9f30a',
+ estimated_seeds: null,
+ estimated_seeds_unit: 'kg',
+ estimated_yield: null,
+ is_planting_method_known: null,
+ location_id: null,
+ notes: null,
+ planting_method: null,
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ ],
+ '61f7cd2c-c09d-43cf-9687-a0502236acfd': [
+ {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.03,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.14,
+ se: null,
+ thiamin: 0.21,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ compliance_file_url: '',
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ genetically_engineered: null,
+ lifecycle: 'PERENNIAL',
+ organic: null,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ treated: null,
+ management_plan_id: 1162,
+ notes: '2',
+ name: 'Plan 1',
+ start_date: null,
+ complete_date: '2021-08-18T07:00:00.000Z',
+ abandon_date: null,
+ complete_notes: '',
+ abandon_reason: null,
+ rating: 3,
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-15T07:00:00.000Z',
+ is_seed: null,
+ is_wild: true,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-24T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-13T07:00:00.000Z',
+ crop_management_plan: {
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-15T07:00:00.000Z',
+ is_seed: null,
+ is_wild: true,
+ management_plan_id: 1162,
+ needs_transplant: true,
+ plant_date: null,
+ seed_date: '2021-08-24T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: '2021-08-13T07:00:00.000Z',
+ },
+ planting_management_plans: {
+ initial: {
+ estimated_seeds: null,
+ estimated_seeds_unit: 'kg',
+ estimated_yield: null,
+ estimated_yield_unit: 'kg',
+ is_final_planting_management_plan: false,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1162,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: '12d43ad9-1baf-4a80-86a8-5dd8e46bc189',
+ planting_method: null,
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 0,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ management_plan_id: 1162,
+ notes: '5',
+ pin_coordinate: null,
+ planting_management_plan_id: 'ae141eae-9f01-4c6f-adc8-42ca2c43c42d',
+ planting_method: 'BED_METHOD',
+ bed_method: {
+ bed_length: 0.101599996749,
+ bed_length_unit: 'in',
+ bed_spacing: 0.101599996749,
+ bed_spacing_unit: 'in',
+ bed_width: 0.076199997562,
+ bed_width_unit: 'in',
+ number_of_beds: 2,
+ number_of_rows_in_bed: 3,
+ plant_spacing: 0.126999995936,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.050799998374,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: 'ae141eae-9f01-4c6f-adc8-42ca2c43c42d',
+ specify_beds: '1',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ ca: 269,
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis ',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ cu: 1.031,
+ depletion_fraction: 0.4,
+ end_kc: 0.6518,
+ energy: 579,
+ farm_id: null,
+ fe: 3.71,
+ fl: null,
+ folate: 44,
+ initial_kc: 0.4,
+ is_avg_depth: false,
+ is_avg_kc: false,
+ is_avg_nutrient: false,
+ k: 733,
+ lipid: 49.93,
+ max_height: 5,
+ max_rooting_depth: 1.5,
+ mg: 270,
+ mid_kc: 0.9,
+ mn: 2.179,
+ na: 1,
+ niacin: 3.618,
+ nutrient_credits: null,
+ nutrient_notes: null,
+ pantothenic: null,
+ percentrefuse: 60,
+ ph: 481,
+ protein: 21.15,
+ refuse: null,
+ reviewed: true,
+ riboflavin: 1.138,
+ se: null,
+ thiamin: 0.205,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.137,
+ vitc: 0,
+ vite: null,
+ vitk: null,
+ zn: 3.12,
+ can_be_cover_crop: null,
+ planting_depth: null,
+ yield_per_area: null,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ crop_variety: {
+ ca: 269,
+ compliance_file_url: '',
+ crop_id: 32,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ crop_variety_photo_url:
+ 'https://litefarmbeta.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ yield_per_area: null,
+ planting_depth: null,
+ can_be_cover_crop: null,
+ cu: 1.03,
+ energy: 579,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ fe: 3.71,
+ folate: 44,
+ genetically_engineered: null,
+ k: 733,
+ lifecycle: 'PERENNIAL',
+ lipid: 49.93,
+ mg: 270,
+ mn: 2.18,
+ na: 1,
+ niacin: 3.62,
+ nutrient_credits: null,
+ organic: null,
+ ph: 481,
+ protein: 21.15,
+ riboflavin: 1.14,
+ searched: null,
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ supplier: '2',
+ thiamin: 0.21,
+ treated: null,
+ vita_rae: 0,
+ vitb12: 0,
+ vitb6: 0.14,
+ vitc: 0,
+ zn: 3.12,
+ average_seed_weight: null,
+ yield_per_plant: null,
+ },
+ firstTaskDate: 1629356400000,
+ status: 'planned',
+ },
+ ],
+};
+
+const persistedFormData = {
+ managementPlans: [
+ {
+ management_plan_id: 1171,
+ },
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1172,
+ },
+ ],
+ locations: [
+ {
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ },
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ managementPlansByLocationIds,
+ useHookFormPersist: () => ({}),
+ persistedFormData,
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.js b/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.js
deleted file mode 100644
index 94f34c19cd..0000000000
--- a/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.js
+++ /dev/null
@@ -1,849 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-import PureTaskDetails from '../../../../components/Task/PureTaskDetails';
-
-export default {
- title: 'Page/AddCleaningTask',
- decorators: decorators,
- component: PureTaskDetails,
-};
-
-const Template = (args) => ;
-
-const managementPlanByLocations = {
- '1f31e024-2e98-44e4-9837-80f52d8ab010': [
- {
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- can_be_cover_crop: true,
- planting_depth: 0.03,
- yield_per_area: 0.3,
- average_seed_weight: 0.00003,
- yield_per_plant: 0.01,
- lifecycle: 'ANNUAL',
- seeding_type: 'SEED',
- needs_transplant: false,
- germination_days: 1,
- transplant_days: null,
- harvest_days: 90,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.0635,
- seeding_rate: null,
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_variety_name: '1test',
- supplier: '2',
- compliance_file_url: '',
- organic: true,
- treated: 'NO',
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- management_plan_id: 1166,
- notes: '2',
- name: 'Plan 1',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-13T07:00:00.000Z',
- harvest_date: '2021-08-14T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- plant_date: null,
- seed_date: '2021-08-12T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- crop_management_plan: {
- already_in_ground: false,
- estimated_revenue: null,
- for_cover: false,
- germination_date: '2021-08-13T07:00:00.000Z',
- harvest_date: '2021-08-14T07:00:00.000Z',
- is_seed: true,
- is_wild: null,
- management_plan_id: 1166,
- needs_transplant: false,
- plant_date: null,
- seed_date: '2021-08-12T07:00:00.000Z',
- termination_date: null,
- transplant_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: 0.907184,
- estimated_seeds_unit: 'lb',
- estimated_yield: 1.814368,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1166,
- notes: '1',
- pin_coordinate: null,
- planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
- planting_method: 'BED_METHOD',
- bed_method: {
- bed_length: 0.101599996749,
- bed_length_unit: 'in',
- bed_spacing: 0.152399995123,
- bed_spacing_unit: 'in',
- bed_width: 0.126999995936,
- bed_width_unit: 'in',
- number_of_beds: 1,
- number_of_rows_in_bed: 2,
- plant_spacing: 0.076199997562,
- plant_spacing_unit: 'in',
- planting_depth: 0.101599996749,
- planting_depth_unit: 'in',
- planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
- specify_beds: '3',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_group: 'Cereals',
- crop_id: 9,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- crop_specie: 'vulgare',
- crop_subgroup: 'Cereals',
- crop_translation_key: 'BARLEY',
- farm_id: null,
- can_be_cover_crop: true,
- planting_depth: 0.03,
- yield_per_area: 0.3,
- average_seed_weight: 0.00003,
- yield_per_plant: 0.01,
- lifecycle: 'ANNUAL',
- seeding_type: 'SEED',
- needs_transplant: false,
- germination_days: 1,
- transplant_days: null,
- harvest_days: 90,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.0635,
- seeding_rate: null,
- },
- crop_variety: {
- crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
- crop_id: 9,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- crop_variety_name: '1test',
- supplier: '2',
- lifecycle: 'ANNUAL',
- compliance_file_url: '',
- organic: true,
- treated: 'NO',
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
- },
- firstTaskDate: 1628751600000,
- status: 'planned',
- },
- {
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- can_be_cover_crop: false,
- planting_depth: 0.0381,
- yield_per_area: 0.11,
- average_seed_weight: null,
- yield_per_plant: 19.28,
- lifecycle: 'PERENNIAL',
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- needs_transplant: false,
- germination_days: 60,
- transplant_days: null,
- harvest_days: 1095,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.381,
- seeding_rate: null,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- supplier: '2',
- compliance_file_url: '',
- organic: null,
- treated: null,
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- management_plan_id: 1177,
- notes: '',
- name: 'Plan 10',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-21T07:00:00.000Z',
- is_seed: null,
- is_wild: false,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- transplant_date: null,
- crop_management_plan: {
- already_in_ground: true,
- estimated_revenue: null,
- for_cover: false,
- germination_date: null,
- harvest_date: '2021-08-21T07:00:00.000Z',
- is_seed: null,
- is_wild: false,
- management_plan_id: 1177,
- needs_transplant: false,
- plant_date: null,
- seed_date: null,
- termination_date: null,
- transplant_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: null,
- estimated_seeds_unit: 'kg',
- estimated_yield: null,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- is_planting_method_known: false,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- management_plan_id: 1177,
- notes: null,
- pin_coordinate: null,
- planting_management_plan_id: '63af6dd8-1bfc-43c2-b5be-470180cf6b05',
- planting_method: null,
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- farm_id: null,
- can_be_cover_crop: false,
- planting_depth: 0.0381,
- yield_per_area: 0.11,
- average_seed_weight: null,
- yield_per_plant: 19.28,
- lifecycle: 'PERENNIAL',
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- needs_transplant: true,
- germination_days: 60,
- transplant_days: null,
- harvest_days: 1095,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.381,
- seeding_rate: null,
- },
- crop_variety: {
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_id: 32,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- crop_variety_name: '1',
- supplier: '2',
- lifecycle: 'PERENNIAL',
- compliance_file_url: '',
- organic: null,
- treated: null,
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- },
- firstTaskDate: 1628319600000,
- status: 'planned',
- },
- ],
- '61f7cd2c-c09d-43cf-9687-a0502236acfd': [
- {
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- can_be_cover_crop: false,
- planting_depth: 0.0381,
- yield_per_area: 0.11,
- average_seed_weight: null,
- yield_per_plant: 19.28,
- lifecycle: 'PERENNIAL',
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- needs_transplant: true,
- germination_days: 60,
- transplant_days: null,
- harvest_days: 1095,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.381,
- seeding_rate: null,
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_variety_name: '1',
- supplier: '2',
- compliance_file_url: '',
- organic: null,
- treated: null,
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- management_plan_id: 1179,
- notes: '',
- name: 'Plan 12',
- start_date: null,
- complete_date: null,
- abandon_date: null,
- complete_notes: null,
- abandon_reason: null,
- already_in_ground: false,
- for_cover: false,
- germination_date: '2021-11-02T07:00:00.000Z',
- harvest_date: '2024-09-02T07:00:00.000Z',
- is_seed: false,
- plant_date: '2021-08-28T07:00:00.000Z',
- seed_date: '2021-09-03T07:00:00.000Z',
- transplant_date: '2022-11-21T08:00:00.000Z',
- estimated_revenue: null,
- is_wild: null,
- termination_date: null,
- crop_management_plan: {
- already_in_ground: false,
- for_cover: false,
- germination_date: '2021-11-02T07:00:00.000Z',
- harvest_date: '2024-09-02T07:00:00.000Z',
- is_seed: false,
- management_plan_id: 1179,
- needs_transplant: true,
- plant_date: '2021-08-28T07:00:00.000Z',
- seed_date: '2021-09-03T07:00:00.000Z',
- transplant_date: '2022-11-21T08:00:00.000Z',
- estimated_revenue: null,
- is_wild: null,
- termination_date: null,
- },
- planting_management_plans: {
- final: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 5.141333168811,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: true,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- management_plan_id: 1179,
- planting_management_plan_id: '19b7fae3-812e-453d-8ccb-39ed98c534eb',
- planting_method: 'ROW_METHOD',
- is_planting_method_known: null,
- notes: null,
- pin_coordinate: null,
- row_method: {
- number_of_rows: 2,
- plant_spacing: 0.381,
- plant_spacing_unit: 'in',
- planting_depth: 0.0381,
- planting_depth_unit: 'in',
- planting_management_plan_id: '19b7fae3-812e-453d-8ccb-39ed98c534eb',
- row_length: 0.050799998374,
- row_length_unit: 'in',
- row_spacing_unit: 'in',
- row_width_unit: 'in',
- same_length: true,
- row_spacing: null,
- row_width: null,
- specify_rows: null,
- total_rows_length: null,
- total_rows_length_unit: 'cm',
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- initial: {
- estimated_seeds: 0,
- estimated_seeds_unit: 'lb',
- estimated_yield: 115.68,
- estimated_yield_unit: 'lb',
- is_final_planting_management_plan: false,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- management_plan_id: 1179,
- planting_management_plan_id: '0c7787c3-9361-4eb6-8316-c328446b8cc6',
- planting_method: 'BED_METHOD',
- is_planting_method_known: null,
- notes: null,
- pin_coordinate: null,
- bed_method: {
- bed_length: 0.101599996749,
- bed_length_unit: 'in',
- bed_spacing_unit: 'in',
- bed_width_unit: 'in',
- number_of_beds: 2,
- number_of_rows_in_bed: 3,
- plant_spacing: 0.101599996749,
- plant_spacing_unit: 'in',
- planting_depth_unit: 'in',
- planting_management_plan_id: '0c7787c3-9361-4eb6-8316-c328446b8cc6',
- specify_beds: '2',
- bed_spacing: null,
- bed_width: null,
- planting_depth: null,
- },
- location: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- },
- },
- crop: {
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_group: 'Fruit and nuts',
- crop_id: 32,
- crop_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- crop_specie: 'dulcis',
- crop_subgroup: 'Nuts',
- crop_translation_key: 'ALMOND',
- farm_id: null,
- can_be_cover_crop: false,
- planting_depth: 0.0381,
- yield_per_area: 0.11,
- average_seed_weight: null,
- yield_per_plant: 19.28,
- lifecycle: 'PERENNIAL',
- seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
- needs_transplant: true,
- germination_days: 60,
- transplant_days: null,
- harvest_days: 1095,
- termination_days: null,
- planting_method: 'ROW_METHOD',
- plant_spacing: 0.381,
- seeding_rate: null,
- },
- crop_variety: {
- crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
- crop_id: 32,
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- crop_variety_name: '1',
- supplier: '2',
- lifecycle: 'PERENNIAL',
- compliance_file_url: '',
- organic: null,
- treated: null,
- genetically_engineered: null,
- searched: null,
- crop_variety_photo_url:
- 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
- },
- status: 'planned',
- },
- ],
-};
-
-export const CleaningTask = Template.bind({});
-CleaningTask.args = {
- handleGoBack: () => console.log('handleGoBack called'),
- onSubmit: () => console.log('onSave called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- useHookFormPersist: () => {},
- persistedFormData: {
- type: 91,
- due_date: '2021-08-23',
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
- managementPlans: [
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1177,
- },
- {
- management_plan_id: 1179,
- },
- ],
- },
- selectedTaskType: {
- task_type_id: 91,
- task_name: 'Cleaning',
- task_translation_key: 'CLEANING',
- farm_id: null,
- },
- persistedPaths: [],
- products: [],
- system: 'metric',
- managementPlanByLocations,
-};
-CleaningTask.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const PestControlTask = Template.bind({});
-PestControlTask.args = {
- handleGoBack: () => console.log('handleGoBack called'),
- onSubmit: () => console.log('onSave called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- useHookFormPersist: () => {},
- persistedFormData: {
- type: 11,
- due_date: '2021-08-23',
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
- managementPlans: [
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1177,
- },
- {
- management_plan_id: 1179,
- },
- ],
- },
- selectedTaskType: {
- task_type_id: 11,
- task_name: 'Pest Control',
- task_translation_key: 'PEST_CONTROL',
- farm_id: null,
- },
- persistedPaths: [],
- products: [],
- system: 'metric',
- managementPlanByLocations,
-};
-PestControlTask.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const FieldWorkTask = Template.bind({});
-FieldWorkTask.args = {
- handleGoBack: () => console.log('handleGoBack called'),
- onSubmit: () => console.log('onSave called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- useHookFormPersist: () => {},
- persistedFormData: {
- type: 9,
- due_date: '2021-08-23',
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
- managementPlans: [
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1177,
- },
- {
- management_plan_id: 1179,
- },
- ],
- },
- selectedTaskType: {
- task_type_id: 9,
- task_name: 'Field Work',
- task_translation_key: 'FIELD_WORK',
- farm_id: null,
- },
- persistedPaths: [],
- products: [],
- system: 'metric',
- managementPlanByLocations,
-};
-FieldWorkTask.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const SoilAmendmentTask = Template.bind({});
-SoilAmendmentTask.args = {
- handleGoBack: () => console.log('handleGoBack called'),
- onSubmit: () => console.log('onSave called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- useHookFormPersist: () => {},
- persistedFormData: {
- type: 6,
- due_date: '2021-08-23',
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
- managementPlans: [
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1177,
- },
- {
- management_plan_id: 1179,
- },
- ],
- },
- selectedTaskType: {
- task_type_id: 6,
- task_name: 'Soil Amendment',
- task_translation_key: 'SOIL_AMENDMENT',
- farm_id: null,
- },
- farm: {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- country_id: null,
- interested: true,
- },
- persistedPaths: [],
- products: [],
- system: 'metric',
- managementPlanByLocations,
-};
-SoilAmendmentTask.parameters = {
- ...chromaticSmallScreen,
-};
-
-export const HarvestTask = Template.bind({});
-HarvestTask.args = {
- handleGoBack: () => console.log('handleGoBack called'),
- onSubmit: () => console.log('onSave called'),
- handleCancel: () => console.log('handleCancel called'),
- onError: () => console.log('onError called'),
- useHookFormPersist: () => {},
- persistedFormData: {
- type: 8,
- due_date: '2021-08-23',
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- },
- ],
- managementPlans: [
- {
- management_plan_id: 1166,
- },
- {
- management_plan_id: 1177,
- },
- {
- management_plan_id: 1179,
- },
- ],
- harvest_tasks: [
- {
- harvest_everything: false,
- quantity: 0.907184,
- quantity_unit: {
- label: 'lb',
- value: 'lb',
- },
- id: '1f31e024-2e98-44e4-9837-80f52d8ab010.1166',
- },
- {
- harvest_everything: true,
- quantity_unit: {
- label: 't',
- value: 't',
- },
- id: '1f31e024-2e98-44e4-9837-80f52d8ab010.1177',
- },
- {
- harvest_everything: true,
- quantity: 1.3607759999999998,
- quantity_unit: {
- label: 'lb',
- value: 'lb',
- },
- id: '61f7cd2c-c09d-43cf-9687-a0502236acfd.1179',
- },
- ],
- },
- selectedTaskType: {
- task_type_id: 8,
- task_name: 'Harvesting',
- task_translation_key: 'HARVESTING',
- farm_id: null,
- },
- persistedPaths: [],
- products: [],
- system: 'metric',
- managementPlanByLocations,
-};
-HarvestTask.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.jsx b/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.jsx
new file mode 100644
index 0000000000..8cb85b28a1
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/TaskDetail/TaskDetail.stories.jsx
@@ -0,0 +1,849 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+import PureTaskDetails from '../../../../components/Task/PureTaskDetails';
+
+export default {
+ title: 'Page/AddCleaningTask',
+ decorators: decorators,
+ component: PureTaskDetails,
+};
+
+const Template = (args) => ;
+
+const managementPlanByLocations = {
+ '1f31e024-2e98-44e4-9837-80f52d8ab010': [
+ {
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ can_be_cover_crop: true,
+ planting_depth: 0.03,
+ yield_per_area: 0.3,
+ average_seed_weight: 0.00003,
+ yield_per_plant: 0.01,
+ lifecycle: 'ANNUAL',
+ seeding_type: 'SEED',
+ needs_transplant: false,
+ germination_days: 1,
+ transplant_days: null,
+ harvest_days: 90,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.0635,
+ seeding_rate: null,
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_variety_name: '1test',
+ supplier: '2',
+ compliance_file_url: '',
+ organic: true,
+ treated: 'NO',
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ management_plan_id: 1166,
+ notes: '2',
+ name: 'Plan 1',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-13T07:00:00.000Z',
+ harvest_date: '2021-08-14T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ plant_date: null,
+ seed_date: '2021-08-12T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ crop_management_plan: {
+ already_in_ground: false,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: '2021-08-13T07:00:00.000Z',
+ harvest_date: '2021-08-14T07:00:00.000Z',
+ is_seed: true,
+ is_wild: null,
+ management_plan_id: 1166,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: '2021-08-12T07:00:00.000Z',
+ termination_date: null,
+ transplant_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: 0.907184,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 1.814368,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1166,
+ notes: '1',
+ pin_coordinate: null,
+ planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
+ planting_method: 'BED_METHOD',
+ bed_method: {
+ bed_length: 0.101599996749,
+ bed_length_unit: 'in',
+ bed_spacing: 0.152399995123,
+ bed_spacing_unit: 'in',
+ bed_width: 0.126999995936,
+ bed_width_unit: 'in',
+ number_of_beds: 1,
+ number_of_rows_in_bed: 2,
+ plant_spacing: 0.076199997562,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.101599996749,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '934ef282-50bc-4656-af58-19347498a158',
+ specify_beds: '3',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ crop_common_name: 'Barley',
+ crop_genus: 'Hordeum',
+ crop_group: 'Cereals',
+ crop_id: 9,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ crop_specie: 'vulgare',
+ crop_subgroup: 'Cereals',
+ crop_translation_key: 'BARLEY',
+ farm_id: null,
+ can_be_cover_crop: true,
+ planting_depth: 0.03,
+ yield_per_area: 0.3,
+ average_seed_weight: 0.00003,
+ yield_per_plant: 0.01,
+ lifecycle: 'ANNUAL',
+ seeding_type: 'SEED',
+ needs_transplant: false,
+ germination_days: 1,
+ transplant_days: null,
+ harvest_days: 90,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.0635,
+ seeding_rate: null,
+ },
+ crop_variety: {
+ crop_variety_id: '26db3900-fab9-11eb-a22c-391d1a1e54fa',
+ crop_id: 9,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ crop_variety_name: '1test',
+ supplier: '2',
+ lifecycle: 'ANNUAL',
+ compliance_file_url: '',
+ organic: true,
+ treated: 'NO',
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/barley.webp',
+ },
+ firstTaskDate: 1628751600000,
+ status: 'planned',
+ },
+ {
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ can_be_cover_crop: false,
+ planting_depth: 0.0381,
+ yield_per_area: 0.11,
+ average_seed_weight: null,
+ yield_per_plant: 19.28,
+ lifecycle: 'PERENNIAL',
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ needs_transplant: false,
+ germination_days: 60,
+ transplant_days: null,
+ harvest_days: 1095,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.381,
+ seeding_rate: null,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ supplier: '2',
+ compliance_file_url: '',
+ organic: null,
+ treated: null,
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ management_plan_id: 1177,
+ notes: '',
+ name: 'Plan 10',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-21T07:00:00.000Z',
+ is_seed: null,
+ is_wild: false,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ transplant_date: null,
+ crop_management_plan: {
+ already_in_ground: true,
+ estimated_revenue: null,
+ for_cover: false,
+ germination_date: null,
+ harvest_date: '2021-08-21T07:00:00.000Z',
+ is_seed: null,
+ is_wild: false,
+ management_plan_id: 1177,
+ needs_transplant: false,
+ plant_date: null,
+ seed_date: null,
+ termination_date: null,
+ transplant_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: null,
+ estimated_seeds_unit: 'kg',
+ estimated_yield: null,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ is_planting_method_known: false,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ management_plan_id: 1177,
+ notes: null,
+ pin_coordinate: null,
+ planting_management_plan_id: '63af6dd8-1bfc-43c2-b5be-470180cf6b05',
+ planting_method: null,
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ farm_id: null,
+ can_be_cover_crop: false,
+ planting_depth: 0.0381,
+ yield_per_area: 0.11,
+ average_seed_weight: null,
+ yield_per_plant: 19.28,
+ lifecycle: 'PERENNIAL',
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ needs_transplant: true,
+ germination_days: 60,
+ transplant_days: null,
+ harvest_days: 1095,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.381,
+ seeding_rate: null,
+ },
+ crop_variety: {
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_id: 32,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ crop_variety_name: '1',
+ supplier: '2',
+ lifecycle: 'PERENNIAL',
+ compliance_file_url: '',
+ organic: null,
+ treated: null,
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ },
+ firstTaskDate: 1628319600000,
+ status: 'planned',
+ },
+ ],
+ '61f7cd2c-c09d-43cf-9687-a0502236acfd': [
+ {
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ can_be_cover_crop: false,
+ planting_depth: 0.0381,
+ yield_per_area: 0.11,
+ average_seed_weight: null,
+ yield_per_plant: 19.28,
+ lifecycle: 'PERENNIAL',
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ needs_transplant: true,
+ germination_days: 60,
+ transplant_days: null,
+ harvest_days: 1095,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.381,
+ seeding_rate: null,
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_variety_name: '1',
+ supplier: '2',
+ compliance_file_url: '',
+ organic: null,
+ treated: null,
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ management_plan_id: 1179,
+ notes: '',
+ name: 'Plan 12',
+ start_date: null,
+ complete_date: null,
+ abandon_date: null,
+ complete_notes: null,
+ abandon_reason: null,
+ already_in_ground: false,
+ for_cover: false,
+ germination_date: '2021-11-02T07:00:00.000Z',
+ harvest_date: '2024-09-02T07:00:00.000Z',
+ is_seed: false,
+ plant_date: '2021-08-28T07:00:00.000Z',
+ seed_date: '2021-09-03T07:00:00.000Z',
+ transplant_date: '2022-11-21T08:00:00.000Z',
+ estimated_revenue: null,
+ is_wild: null,
+ termination_date: null,
+ crop_management_plan: {
+ already_in_ground: false,
+ for_cover: false,
+ germination_date: '2021-11-02T07:00:00.000Z',
+ harvest_date: '2024-09-02T07:00:00.000Z',
+ is_seed: false,
+ management_plan_id: 1179,
+ needs_transplant: true,
+ plant_date: '2021-08-28T07:00:00.000Z',
+ seed_date: '2021-09-03T07:00:00.000Z',
+ transplant_date: '2022-11-21T08:00:00.000Z',
+ estimated_revenue: null,
+ is_wild: null,
+ termination_date: null,
+ },
+ planting_management_plans: {
+ final: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 5.141333168811,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: true,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ management_plan_id: 1179,
+ planting_management_plan_id: '19b7fae3-812e-453d-8ccb-39ed98c534eb',
+ planting_method: 'ROW_METHOD',
+ is_planting_method_known: null,
+ notes: null,
+ pin_coordinate: null,
+ row_method: {
+ number_of_rows: 2,
+ plant_spacing: 0.381,
+ plant_spacing_unit: 'in',
+ planting_depth: 0.0381,
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '19b7fae3-812e-453d-8ccb-39ed98c534eb',
+ row_length: 0.050799998374,
+ row_length_unit: 'in',
+ row_spacing_unit: 'in',
+ row_width_unit: 'in',
+ same_length: true,
+ row_spacing: null,
+ row_width: null,
+ specify_rows: null,
+ total_rows_length: null,
+ total_rows_length_unit: 'cm',
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ initial: {
+ estimated_seeds: 0,
+ estimated_seeds_unit: 'lb',
+ estimated_yield: 115.68,
+ estimated_yield_unit: 'lb',
+ is_final_planting_management_plan: false,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ management_plan_id: 1179,
+ planting_management_plan_id: '0c7787c3-9361-4eb6-8316-c328446b8cc6',
+ planting_method: 'BED_METHOD',
+ is_planting_method_known: null,
+ notes: null,
+ pin_coordinate: null,
+ bed_method: {
+ bed_length: 0.101599996749,
+ bed_length_unit: 'in',
+ bed_spacing_unit: 'in',
+ bed_width_unit: 'in',
+ number_of_beds: 2,
+ number_of_rows_in_bed: 3,
+ plant_spacing: 0.101599996749,
+ plant_spacing_unit: 'in',
+ planting_depth_unit: 'in',
+ planting_management_plan_id: '0c7787c3-9361-4eb6-8316-c328446b8cc6',
+ specify_beds: '2',
+ bed_spacing: null,
+ bed_width: null,
+ planting_depth: null,
+ },
+ location: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ },
+ },
+ crop: {
+ crop_common_name: 'Almond',
+ crop_genus: 'Prunus',
+ crop_group: 'Fruit and nuts',
+ crop_id: 32,
+ crop_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ crop_specie: 'dulcis',
+ crop_subgroup: 'Nuts',
+ crop_translation_key: 'ALMOND',
+ farm_id: null,
+ can_be_cover_crop: false,
+ planting_depth: 0.0381,
+ yield_per_area: 0.11,
+ average_seed_weight: null,
+ yield_per_plant: 19.28,
+ lifecycle: 'PERENNIAL',
+ seeding_type: 'SEEDLING_OR_PLANTING_STOCK',
+ needs_transplant: true,
+ germination_days: 60,
+ transplant_days: null,
+ harvest_days: 1095,
+ termination_days: null,
+ planting_method: 'ROW_METHOD',
+ plant_spacing: 0.381,
+ seeding_rate: null,
+ },
+ crop_variety: {
+ crop_variety_id: 'fd98b0fe-c7dc-11eb-9f35-0242ac120002',
+ crop_id: 32,
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ crop_variety_name: '1',
+ supplier: '2',
+ lifecycle: 'PERENNIAL',
+ compliance_file_url: '',
+ organic: null,
+ treated: null,
+ genetically_engineered: null,
+ searched: null,
+ crop_variety_photo_url:
+ 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/almond.webp',
+ },
+ status: 'planned',
+ },
+ ],
+};
+
+export const CleaningTask = Template.bind({});
+CleaningTask.args = {
+ handleGoBack: () => console.log('handleGoBack called'),
+ onSubmit: () => console.log('onSave called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ type: 91,
+ due_date: '2021-08-23',
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+ managementPlans: [
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1177,
+ },
+ {
+ management_plan_id: 1179,
+ },
+ ],
+ },
+ selectedTaskType: {
+ task_type_id: 91,
+ task_name: 'Cleaning',
+ task_translation_key: 'CLEANING',
+ farm_id: null,
+ },
+ persistedPaths: [],
+ products: [],
+ system: 'metric',
+ managementPlanByLocations,
+};
+CleaningTask.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const PestControlTask = Template.bind({});
+PestControlTask.args = {
+ handleGoBack: () => console.log('handleGoBack called'),
+ onSubmit: () => console.log('onSave called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ type: 11,
+ due_date: '2021-08-23',
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+ managementPlans: [
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1177,
+ },
+ {
+ management_plan_id: 1179,
+ },
+ ],
+ },
+ selectedTaskType: {
+ task_type_id: 11,
+ task_name: 'Pest Control',
+ task_translation_key: 'PEST_CONTROL',
+ farm_id: null,
+ },
+ persistedPaths: [],
+ products: [],
+ system: 'metric',
+ managementPlanByLocations,
+};
+PestControlTask.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const FieldWorkTask = Template.bind({});
+FieldWorkTask.args = {
+ handleGoBack: () => console.log('handleGoBack called'),
+ onSubmit: () => console.log('onSave called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ type: 9,
+ due_date: '2021-08-23',
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+ managementPlans: [
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1177,
+ },
+ {
+ management_plan_id: 1179,
+ },
+ ],
+ },
+ selectedTaskType: {
+ task_type_id: 9,
+ task_name: 'Field Work',
+ task_translation_key: 'FIELD_WORK',
+ farm_id: null,
+ },
+ persistedPaths: [],
+ products: [],
+ system: 'metric',
+ managementPlanByLocations,
+};
+FieldWorkTask.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const SoilAmendmentTask = Template.bind({});
+SoilAmendmentTask.args = {
+ handleGoBack: () => console.log('handleGoBack called'),
+ onSubmit: () => console.log('onSave called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ type: 6,
+ due_date: '2021-08-23',
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+ managementPlans: [
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1177,
+ },
+ {
+ management_plan_id: 1179,
+ },
+ ],
+ },
+ selectedTaskType: {
+ task_type_id: 6,
+ task_name: 'Soil Amendment',
+ task_translation_key: 'SOIL_AMENDMENT',
+ farm_id: null,
+ },
+ farm: {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ country_id: null,
+ interested: true,
+ },
+ persistedPaths: [],
+ products: [],
+ system: 'metric',
+ managementPlanByLocations,
+};
+SoilAmendmentTask.parameters = {
+ ...chromaticSmallScreen,
+};
+
+export const HarvestTask = Template.bind({});
+HarvestTask.args = {
+ handleGoBack: () => console.log('handleGoBack called'),
+ onSubmit: () => console.log('onSave called'),
+ handleCancel: () => console.log('handleCancel called'),
+ onError: () => console.log('onError called'),
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ type: 8,
+ due_date: '2021-08-23',
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ },
+ ],
+ managementPlans: [
+ {
+ management_plan_id: 1166,
+ },
+ {
+ management_plan_id: 1177,
+ },
+ {
+ management_plan_id: 1179,
+ },
+ ],
+ harvest_tasks: [
+ {
+ harvest_everything: false,
+ quantity: 0.907184,
+ quantity_unit: {
+ label: 'lb',
+ value: 'lb',
+ },
+ id: '1f31e024-2e98-44e4-9837-80f52d8ab010.1166',
+ },
+ {
+ harvest_everything: true,
+ quantity_unit: {
+ label: 't',
+ value: 't',
+ },
+ id: '1f31e024-2e98-44e4-9837-80f52d8ab010.1177',
+ },
+ {
+ harvest_everything: true,
+ quantity: 1.3607759999999998,
+ quantity_unit: {
+ label: 'lb',
+ value: 'lb',
+ },
+ id: '61f7cd2c-c09d-43cf-9687-a0502236acfd.1179',
+ },
+ ],
+ },
+ selectedTaskType: {
+ task_type_id: 8,
+ task_name: 'Harvesting',
+ task_translation_key: 'HARVESTING',
+ farm_id: null,
+ },
+ persistedPaths: [],
+ products: [],
+ system: 'metric',
+ managementPlanByLocations,
+};
+HarvestTask.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.js b/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.js
deleted file mode 100644
index 22a3447d04..0000000000
--- a/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.js
+++ /dev/null
@@ -1,412 +0,0 @@
-import React from 'react';
-import decorators from '../../config/decorators';
-import { chromaticSmallScreen } from '../../config/chromatic';
-import PureTaskLocations from '../../../../components/Task/TaskLocations';
-
-export default {
- title: 'Form/Task/PureTaskLocations',
- decorators: decorators,
- component: PureTaskLocations,
-};
-const locations = [
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: '',
- location_id: '22dce0a8-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '22dce0a9-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'farm_site_boundary',
- total_area: 746999,
- total_area_unit: 'ac',
- grid_points: [
- {
- lat: 49.28302420606871,
- lng: -123.18500584661867,
- },
- {
- lat: 49.27707498070813,
- lng: -123.18442648947145,
- },
- {
- lat: 49.27627703001983,
- lng: -123.1710369020691,
- },
- {
- lat: 49.28340213261163,
- lng: -123.1701356798401,
- },
- ],
- perimeter: 3517,
- perimeter_unit: 'mi',
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '34',
- notes: '',
- location_id: '0271eef6-045f-11ec-bac7-c1b8e9a6c31a',
- figure_id: '0271eef7-045f-11ec-bac7-c1b8e9a6c31a',
- type: 'farm_site_boundary',
- total_area: 2980,
- total_area_unit: 'ac',
- grid_points: [
- {
- lat: 49.281851915495416,
- lng: -123.17072040140535,
- },
- {
- lat: 49.2807530864911,
- lng: -123.17114955484773,
- },
- {
- lat: 49.28074608750178,
- lng: -123.17075258791353,
- },
- {
- lat: 49.2818029236409,
- lng: -123.17045218050386,
- },
- ],
- perimeter: 295,
- perimeter_unit: 'ft',
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '1',
- notes: null,
- location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
- figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 49628,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28051249566314,
- lng: -123.18097180426027,
- },
- {
- lat: 49.27874871033353,
- lng: -123.18311757147218,
- },
- {
- lat: 49.27877670741875,
- lng: -123.17612237036134,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: null,
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 50614,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.280988426928936,
- lng: -123.18064993917848,
- },
- {
- lat: 49.279140668080345,
- lng: -123.1756288439026,
- },
- {
- lat: 49.280876443514906,
- lng: -123.17356890737916,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: null,
- location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
- figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
- type: 'field',
- total_area: 37415,
- total_area_unit: 'm2',
- grid_points: [
- {
- lat: 49.28056848781515,
- lng: -123.17292517721559,
- },
- {
- lat: 49.278804704488074,
- lng: -123.17485636770631,
- },
- {
- lat: 49.27804877803772,
- lng: -123.17043608724977,
- },
- ],
- perimeter: null,
- perimeter_unit: 'm',
- station_id: 6173331,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '34',
- notes: '3',
- location_id: 'a73726a8-e066-11eb-ac43-0242ac120002',
- figure_id: 'a73b034a-e066-11eb-ac43-0242ac120002',
- type: 'field',
- total_area: 840.00037161252,
- total_area_unit: 'ft2',
- grid_points: [
- {
- lat: 49.27841624373156,
- lng: -123.17622965872194,
- },
- {
- lat: 49.277380333422414,
- lng: -123.17380494177247,
- },
- {
- lat: 49.278465238950545,
- lng: -123.17614382803346,
- },
- ],
- perimeter: 427,
- perimeter_unit: 'mi',
- station_id: null,
- organic_status: 'Non-Organic',
- transition_date: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '45',
- notes: '',
- location_id: 'e33c39c0-01a1-11ec-a06b-ddb78ab7af2b',
- figure_id: 'e33c39c1-01a1-11ec-a06b-ddb78ab7af2b',
- type: 'garden',
- total_area: 47829,
- total_area_unit: 'ac',
- grid_points: [
- {
- lat: 49.28180904762536,
- lng: -123.17670172750856,
- },
- {
- lat: 49.27832350264812,
- lng: -123.17944830953981,
- },
- {
- lat: 49.27798753348927,
- lng: -123.17762440740968,
- },
- {
- lat: 49.28158508426991,
- lng: -123.17556447088624,
- },
- ],
- perimeter: 1088,
- perimeter_unit: 'mi',
- organic_status: 'Non-Organic',
- station_id: null,
- transition_date: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: '',
- location_id: '2e189520-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '2e189521-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'watercourse',
- length: 851,
- width: 1.000658367979,
- line_points: [
- {
- lat: 49.28077758294594,
- lng: -123.18148678839113,
- },
- {
- lat: 49.27953174781689,
- lng: -123.16992110311891,
- },
- ],
- length_unit: 'mi',
- width_unit: 'ft',
- total_area: 13621,
- total_area_unit: 'ac',
- used_for_irrigation: null,
- buffer_width: 15.000121919996,
- buffer_width_unit: 'ft',
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '3',
- notes: '',
- location_id: '36d55c2a-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '36d55c2b-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'fence',
- length: 594,
- width: 0,
- line_points: [
- {
- lat: 49.281393489810945,
- lng: -123.17916935980226,
- },
- {
- lat: 49.27806190185972,
- lng: -123.17277497351076,
- },
- ],
- length_unit: 'mi',
- pressure_treated: null,
- width_unit: 'm',
- total_area: null,
- total_area_unit: 'm2',
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '4',
- notes: '',
- location_id: '76b4c92e-045e-11ec-bac7-c1b8e9a6c31a',
- figure_id: '76b4c92f-045e-11ec-bac7-c1b8e9a6c31a',
- type: 'fence',
- length: 589,
- width: 0,
- line_points: [
- {
- lat: 49.28118002296169,
- lng: -123.17934638559724,
- },
- {
- lat: 49.27793241333064,
- lng: -123.17295199930574,
- },
- ],
- length_unit: 'mi',
- pressure_treated: null,
- width_unit: 'm',
- total_area: null,
- total_area_unit: 'm2',
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: '',
- location_id: '0366746e-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '0366746f-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'gate',
- point: {
- lat: 49.27991979950127,
- lng: -123.18058083927218,
- },
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: '',
- location_id: '0e7167f6-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '0e7167f7-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'gate',
- point: {
- lat: 49.27762093953046,
- lng: -123.17702359259034,
- },
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '4',
- notes: '',
- location_id: 'afeb4b96-0468-11ec-bac7-c1b8e9a6c31a',
- figure_id: 'afeb4b97-0468-11ec-bac7-c1b8e9a6c31a',
- type: 'gate',
- point: {
- lat: 49.27951075032591,
- lng: -123.17970580160524,
- },
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '4',
- notes: '',
- location_id: 'ca5e016c-0468-11ec-bac7-c1b8e9a6c31a',
- figure_id: 'ca5e016d-0468-11ec-bac7-c1b8e9a6c31a',
- type: 'gate',
- point: {
- lat: 49.27987385356563,
- lng: -123.18041716952165,
- },
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: '',
- location_id: '0966e81c-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '0966e81d-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'water_valve',
- point: {
- lat: 49.28032264679955,
- lng: -123.17470616400148,
- },
- source: 'Municipal water',
- flow_rate_unit: 'gal/min',
- flow_rate: null,
- },
- {
- farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
- name: '2',
- notes: '',
- location_id: '1480c696-043a-11ec-bac7-c1b8e9a6c31a',
- figure_id: '1480c697-043a-11ec-bac7-c1b8e9a6c31a',
- type: 'water_valve',
- point: {
- lat: 49.27762093953046,
- lng: -123.17702359259034,
- },
- source: 'Municipal water',
- flow_rate_unit: 'gal/min',
- flow_rate: null,
- },
-];
-
-const persistedFormData = {
- locations: [
- {
- location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
- },
- {
- location_id: '0e7167f6-043a-11ec-bac7-c1b8e9a6c31a',
- },
- {
- location_id: '36d55c2a-043a-11ec-bac7-c1b8e9a6c31a',
- },
- {
- location_id: '0271eef6-045f-11ec-bac7-c1b8e9a6c31a',
- },
- ],
- type: 11,
- due_date: '2021-08-12',
- managementPlans: [],
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = {
- locations,
- useHookFormPersist: () => {},
- persistedFormData,
- farmCenterCoordinate: {
- lat: 49.26886611583817,
- lng: -123.18239233683167,
- },
-};
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.jsx b/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.jsx
new file mode 100644
index 0000000000..1476811e39
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Task/TaskLocation/TaskLocation.stories.jsx
@@ -0,0 +1,412 @@
+import React from 'react';
+import decorators from '../../config/Decorators';
+import { chromaticSmallScreen } from '../../config/chromatic';
+import PureTaskLocations from '../../../../components/Task/TaskLocations';
+
+export default {
+ title: 'Form/Task/PureTaskLocations',
+ decorators: decorators,
+ component: PureTaskLocations,
+};
+const locations = [
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: '',
+ location_id: '22dce0a8-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '22dce0a9-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'farm_site_boundary',
+ total_area: 746999,
+ total_area_unit: 'ac',
+ grid_points: [
+ {
+ lat: 49.28302420606871,
+ lng: -123.18500584661867,
+ },
+ {
+ lat: 49.27707498070813,
+ lng: -123.18442648947145,
+ },
+ {
+ lat: 49.27627703001983,
+ lng: -123.1710369020691,
+ },
+ {
+ lat: 49.28340213261163,
+ lng: -123.1701356798401,
+ },
+ ],
+ perimeter: 3517,
+ perimeter_unit: 'mi',
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '34',
+ notes: '',
+ location_id: '0271eef6-045f-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '0271eef7-045f-11ec-bac7-c1b8e9a6c31a',
+ type: 'farm_site_boundary',
+ total_area: 2980,
+ total_area_unit: 'ac',
+ grid_points: [
+ {
+ lat: 49.281851915495416,
+ lng: -123.17072040140535,
+ },
+ {
+ lat: 49.2807530864911,
+ lng: -123.17114955484773,
+ },
+ {
+ lat: 49.28074608750178,
+ lng: -123.17075258791353,
+ },
+ {
+ lat: 49.2818029236409,
+ lng: -123.17045218050386,
+ },
+ ],
+ perimeter: 295,
+ perimeter_unit: 'ft',
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '1',
+ notes: null,
+ location_id: '57bb2bb8-59fc-4a6c-9814-63e8664a7461',
+ figure_id: '7f9e1126-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 49628,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28051249566314,
+ lng: -123.18097180426027,
+ },
+ {
+ lat: 49.27874871033353,
+ lng: -123.18311757147218,
+ },
+ {
+ lat: 49.27877670741875,
+ lng: -123.17612237036134,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: null,
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ figure_id: '7fa87148-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 50614,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.280988426928936,
+ lng: -123.18064993917848,
+ },
+ {
+ lat: 49.279140668080345,
+ lng: -123.1756288439026,
+ },
+ {
+ lat: 49.280876443514906,
+ lng: -123.17356890737916,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: null,
+ location_id: '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ figure_id: '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ type: 'field',
+ total_area: 37415,
+ total_area_unit: 'm2',
+ grid_points: [
+ {
+ lat: 49.28056848781515,
+ lng: -123.17292517721559,
+ },
+ {
+ lat: 49.278804704488074,
+ lng: -123.17485636770631,
+ },
+ {
+ lat: 49.27804877803772,
+ lng: -123.17043608724977,
+ },
+ ],
+ perimeter: null,
+ perimeter_unit: 'm',
+ station_id: 6173331,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '34',
+ notes: '3',
+ location_id: 'a73726a8-e066-11eb-ac43-0242ac120002',
+ figure_id: 'a73b034a-e066-11eb-ac43-0242ac120002',
+ type: 'field',
+ total_area: 840.00037161252,
+ total_area_unit: 'ft2',
+ grid_points: [
+ {
+ lat: 49.27841624373156,
+ lng: -123.17622965872194,
+ },
+ {
+ lat: 49.277380333422414,
+ lng: -123.17380494177247,
+ },
+ {
+ lat: 49.278465238950545,
+ lng: -123.17614382803346,
+ },
+ ],
+ perimeter: 427,
+ perimeter_unit: 'mi',
+ station_id: null,
+ organic_status: 'Non-Organic',
+ transition_date: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '45',
+ notes: '',
+ location_id: 'e33c39c0-01a1-11ec-a06b-ddb78ab7af2b',
+ figure_id: 'e33c39c1-01a1-11ec-a06b-ddb78ab7af2b',
+ type: 'garden',
+ total_area: 47829,
+ total_area_unit: 'ac',
+ grid_points: [
+ {
+ lat: 49.28180904762536,
+ lng: -123.17670172750856,
+ },
+ {
+ lat: 49.27832350264812,
+ lng: -123.17944830953981,
+ },
+ {
+ lat: 49.27798753348927,
+ lng: -123.17762440740968,
+ },
+ {
+ lat: 49.28158508426991,
+ lng: -123.17556447088624,
+ },
+ ],
+ perimeter: 1088,
+ perimeter_unit: 'mi',
+ organic_status: 'Non-Organic',
+ station_id: null,
+ transition_date: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: '',
+ location_id: '2e189520-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '2e189521-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'watercourse',
+ length: 851,
+ width: 1.000658367979,
+ line_points: [
+ {
+ lat: 49.28077758294594,
+ lng: -123.18148678839113,
+ },
+ {
+ lat: 49.27953174781689,
+ lng: -123.16992110311891,
+ },
+ ],
+ length_unit: 'mi',
+ width_unit: 'ft',
+ total_area: 13621,
+ total_area_unit: 'ac',
+ used_for_irrigation: null,
+ buffer_width: 15.000121919996,
+ buffer_width_unit: 'ft',
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '3',
+ notes: '',
+ location_id: '36d55c2a-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '36d55c2b-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'fence',
+ length: 594,
+ width: 0,
+ line_points: [
+ {
+ lat: 49.281393489810945,
+ lng: -123.17916935980226,
+ },
+ {
+ lat: 49.27806190185972,
+ lng: -123.17277497351076,
+ },
+ ],
+ length_unit: 'mi',
+ pressure_treated: null,
+ width_unit: 'm',
+ total_area: null,
+ total_area_unit: 'm2',
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '4',
+ notes: '',
+ location_id: '76b4c92e-045e-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '76b4c92f-045e-11ec-bac7-c1b8e9a6c31a',
+ type: 'fence',
+ length: 589,
+ width: 0,
+ line_points: [
+ {
+ lat: 49.28118002296169,
+ lng: -123.17934638559724,
+ },
+ {
+ lat: 49.27793241333064,
+ lng: -123.17295199930574,
+ },
+ ],
+ length_unit: 'mi',
+ pressure_treated: null,
+ width_unit: 'm',
+ total_area: null,
+ total_area_unit: 'm2',
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: '',
+ location_id: '0366746e-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '0366746f-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'gate',
+ point: {
+ lat: 49.27991979950127,
+ lng: -123.18058083927218,
+ },
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: '',
+ location_id: '0e7167f6-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '0e7167f7-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'gate',
+ point: {
+ lat: 49.27762093953046,
+ lng: -123.17702359259034,
+ },
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '4',
+ notes: '',
+ location_id: 'afeb4b96-0468-11ec-bac7-c1b8e9a6c31a',
+ figure_id: 'afeb4b97-0468-11ec-bac7-c1b8e9a6c31a',
+ type: 'gate',
+ point: {
+ lat: 49.27951075032591,
+ lng: -123.17970580160524,
+ },
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '4',
+ notes: '',
+ location_id: 'ca5e016c-0468-11ec-bac7-c1b8e9a6c31a',
+ figure_id: 'ca5e016d-0468-11ec-bac7-c1b8e9a6c31a',
+ type: 'gate',
+ point: {
+ lat: 49.27987385356563,
+ lng: -123.18041716952165,
+ },
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: '',
+ location_id: '0966e81c-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '0966e81d-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'water_valve',
+ point: {
+ lat: 49.28032264679955,
+ lng: -123.17470616400148,
+ },
+ source: 'Municipal water',
+ flow_rate_unit: 'gal/min',
+ flow_rate: null,
+ },
+ {
+ farm_id: '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ name: '2',
+ notes: '',
+ location_id: '1480c696-043a-11ec-bac7-c1b8e9a6c31a',
+ figure_id: '1480c697-043a-11ec-bac7-c1b8e9a6c31a',
+ type: 'water_valve',
+ point: {
+ lat: 49.27762093953046,
+ lng: -123.17702359259034,
+ },
+ source: 'Municipal water',
+ flow_rate_unit: 'gal/min',
+ flow_rate: null,
+ },
+];
+
+const persistedFormData = {
+ locations: [
+ {
+ location_id: '1f31e024-2e98-44e4-9837-80f52d8ab010',
+ },
+ {
+ location_id: '0e7167f6-043a-11ec-bac7-c1b8e9a6c31a',
+ },
+ {
+ location_id: '36d55c2a-043a-11ec-bac7-c1b8e9a6c31a',
+ },
+ {
+ location_id: '0271eef6-045f-11ec-bac7-c1b8e9a6c31a',
+ },
+ ],
+ type: 11,
+ due_date: '2021-08-12',
+ managementPlans: [],
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = {
+ locations,
+ useHookFormPersist: () => ({}),
+ persistedFormData,
+ farmCenterCoordinate: {
+ lat: 49.26886611583817,
+ lng: -123.18239233683167,
+ },
+};
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.js b/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.js
deleted file mode 100644
index b96d0acb6d..0000000000
--- a/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import PureHarvestCompleteQuantity from '../../../components/Task/TaskComplete/HarvestComplete/Quantity';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Tasks/HarvestCompleteQuantity',
- component: PureHarvestCompleteQuantity,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const HarvestCompleteQuantity = Template.bind({});
-HarvestCompleteQuantity.args = {
- onCancel: () => {},
- onGoBack: () => {},
- system: 'metric',
- useHookFormPersist: () => {},
- persistedFormData: {},
-};
diff --git a/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.jsx b/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.jsx
new file mode 100644
index 0000000000..26bdb1e739
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Tasks/HarvestTaskQuantity.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import PureHarvestCompleteQuantity from '../../../components/Task/TaskComplete/HarvestComplete/Quantity';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Tasks/HarvestCompleteQuantity',
+ component: PureHarvestCompleteQuantity,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const HarvestCompleteQuantity = Template.bind({});
+HarvestCompleteQuantity.args = {
+ onCancel: () => {},
+ onGoBack: () => {},
+ system: 'metric',
+ useHookFormPersist: () => ({}),
+ persistedFormData: {},
+};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.js b/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.js
deleted file mode 100644
index 68acbdcb51..0000000000
--- a/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import PureTaskComplete from '../../../components/Task/TaskComplete';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Tasks/TaskComplete',
- component: PureTaskComplete,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const TaskComplete = Template.bind({});
-TaskComplete.args = {
- onCancel: () => {},
- onGoBack: () => {},
- onSave: () => {},
- useHookFormPersist: () => {},
- persistedFormData: {},
-};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.jsx b/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.jsx
new file mode 100644
index 0000000000..8520dec8bd
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Tasks/TaskComplete.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import PureTaskComplete from '../../../components/Task/TaskComplete';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Tasks/TaskComplete',
+ component: PureTaskComplete,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const TaskComplete = Template.bind({});
+TaskComplete.args = {
+ onCancel: () => {},
+ onGoBack: () => {},
+ onSave: () => {},
+ useHookFormPersist: () => ({}),
+ persistedFormData: {},
+};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.js b/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.js
deleted file mode 100644
index ab7cf9ddb3..0000000000
--- a/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import React from 'react';
-import PureCompleteStepOne from '../../../components/Task/TaskComplete/StepOne';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Tasks/TaskComplete-1',
- component: PureCompleteStepOne,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const TaskCompleteCleaning = Template.bind({});
-TaskCompleteCleaning.args = {
- onCancel: () => {},
- onGoBack: () => {},
- onSave: () => {},
- useHookFormPersist: () => {},
- persistedFormData: {
- cleaning_task: {
- cleaning_target: 'target',
- agent_used: true,
- water_usage: 50,
- water_usage_unit: 'l',
- product_id: 2,
- product_quantity: 300,
- product_quantity_unit: 'ml',
- product: {
- name: 'Test product',
- supplier: 'Test supplier',
- type: 'cleaning_task',
- on_permitted_substances_list: 'YES',
- farm_id: '1231456',
- },
- },
- },
- selectedTaskType: { task_translation_key: 'CLEANING' },
- farm: '1231456',
- system: 'metric',
- products: [
- {
- product_id: 2,
- name: 'Test product',
- supplier: 'Test supplier',
- type: 'cleaning_task',
- on_permitted_substances_list: true,
- farm_id: '1231456',
- },
- ],
-};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.jsx b/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.jsx
new file mode 100644
index 0000000000..497742966d
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Tasks/TaskCompleteOne.stories.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import PureCompleteStepOne from '../../../components/Task/TaskComplete/StepOne';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Tasks/TaskComplete-1',
+ component: PureCompleteStepOne,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const TaskCompleteCleaning = Template.bind({});
+TaskCompleteCleaning.args = {
+ onCancel: () => {},
+ onGoBack: () => {},
+ onSave: () => {},
+ useHookFormPersist: () => ({}),
+ persistedFormData: {
+ cleaning_task: {
+ cleaning_target: 'target',
+ agent_used: true,
+ water_usage: 50,
+ water_usage_unit: 'l',
+ product_id: 2,
+ product_quantity: 300,
+ product_quantity_unit: 'ml',
+ product: {
+ name: 'Test product',
+ supplier: 'Test supplier',
+ type: 'cleaning_task',
+ on_permitted_substances_list: 'YES',
+ farm_id: '1231456',
+ },
+ },
+ },
+ selectedTaskType: { task_translation_key: 'CLEANING' },
+ farm: '1231456',
+ system: 'metric',
+ products: [
+ {
+ product_id: 2,
+ name: 'Test product',
+ supplier: 'Test supplier',
+ type: 'cleaning_task',
+ on_permitted_substances_list: true,
+ farm_id: '1231456',
+ },
+ ],
+};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.js b/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.js
deleted file mode 100644
index 039a13f2e8..0000000000
--- a/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import React from 'react';
-import PureTaskDate from '../../../components/Task/TaskDate';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Tasks/TaskDate',
- component: PureTaskDate,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-export const TaskDate = Template.bind({});
-TaskDate.args = {
- onCancel: () => { },
- onGoBack: () => { },
- onContinue: () => { },
- useHookFormPersist: () => { },
- persistedFormData: {},
-};
\ No newline at end of file
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.jsx b/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.jsx
new file mode 100644
index 0000000000..d0ba667bee
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Tasks/TaskDate.stories.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import PureTaskDate from '../../../components/Task/TaskDate';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Tasks/TaskDate',
+ component: PureTaskDate,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+export const TaskDate = Template.bind({});
+TaskDate.args = {
+ onCancel: () => { },
+ onGoBack: () => { },
+ onContinue: () => { },
+ useHookFormPersist: () => { },
+ persistedFormData: {},
+};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.js b/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.js
deleted file mode 100644
index 315840627b..0000000000
--- a/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.js
+++ /dev/null
@@ -1,150 +0,0 @@
-import React from 'react';
-import PureTaskReadOnly from '../../../components/Task/TaskReadOnly';
-import decorator from '../config/decorators';
-
-export default {
- title: 'Form/Crop/Tasks/TaskReadOnly',
- component: PureTaskReadOnly,
- decorators: decorator,
-};
-
-const Template = (args) => ;
-
-const cropLocations = [
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: 'eq',
- notes: '',
- location_id: '8b47b24e-f427-11eb-b310-9b4fc6232458',
- figure_id: '8b47b24f-f427-11eb-b310-9b4fc6232458',
- type: 'field',
- total_area: 5587,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26919164618451,
- lng: -123.18165204714356,
- },
- {
- lat: 49.268547584065274,
- lng: -123.18288586329041,
- },
- {
- lat: 49.268603589800726,
- lng: -123.1806328077179,
- },
- ],
- perimeter: 377,
- perimeter_unit: 'm',
- organic_status: 'Non-Organic',
- transition_date: '2021-08-03T07:00:00.000Z',
- station_id: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: 'w',
- notes: '',
- location_id: 'c361c80a-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'c361c80b-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'garden',
- total_area: 5309,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26919514649913,
- lng: -123.18276784609375,
- },
- {
- lat: 49.26819404639292,
- lng: -123.18202755640564,
- },
- {
- lat: 49.26790001313183,
- lng: -123.18312189768372,
- },
- ],
- perimeter: 356,
- perimeter_unit: 'm',
- organic_status: 'Non-Organic',
- station_id: null,
- transition_date: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: '4',
- notes: '',
- location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'ce8f9677-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'greenhouse',
- total_area: 9938,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26823605100145,
- lng: -123.18331501673279,
- },
- {
- lat: 49.26825705329233,
- lng: -123.18087957094727,
- },
- {
- lat: 49.26926515273966,
- lng: -123.18101904581604,
- },
- ],
- perimeter: 492,
- organic_status: 'Non-Organic',
- supplemental_lighting: null,
- co2_enrichment: null,
- greenhouse_heated: null,
- perimeter_unit: 'm',
- transition_date: null,
- },
- {
- farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
- name: '3',
- notes: '',
- location_id: 'd4ec5e8c-f70a-11eb-8dd7-6f2c0c6a4580',
- figure_id: 'd4ec5e8d-f70a-11eb-8dd7-6f2c0c6a4580',
- type: 'buffer_zone',
- length: 224,
- width: 8,
- line_points: [
- {
- lat: 49.26831305935756,
- lng: -123.18393728922425,
- },
- {
- lat: 49.26787200987272,
- lng: -123.18092248629151,
- },
- ],
- width_unit: 'm',
- total_area: 1795,
- total_area_unit: 'ha',
- length_unit: 'm',
- },
-];
-
-export const TaskReadOnly = Template.bind({});
-TaskReadOnly.args = {
- task: {
- taskType: [
- {
- task_translation_key: 'Task type',
- },
- ],
- due_date: '06/21/2021T',
- locations: cropLocations,
- onwer_user_id: '1',
- notes: '',
- assignee_user_id: '1',
- },
- users: [{ user_id: '1', first_name: 'John', last_name: 'Doe' }],
- user: {
- user_id: '1',
- },
- isAdmin: true,
- managementPlansByLocationIds: [],
- onGoBack: () => {},
-};
diff --git a/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.jsx b/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.jsx
new file mode 100644
index 0000000000..281def104d
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/Tasks/TaskReadOnly.stories.jsx
@@ -0,0 +1,806 @@
+import React from 'react';
+import PureTaskReadOnly from '../../../components/Task/TaskReadOnly';
+import decorator from '../config/Decorators';
+
+export default {
+ title: 'Form/Crop/Tasks/TaskReadOnly',
+ component: PureTaskReadOnly,
+ decorators: decorator,
+};
+
+const Template = (args) => ;
+
+const cropLocations = [
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: 'eq',
+ notes: '',
+ location_id: '8b47b24e-f427-11eb-b310-9b4fc6232458',
+ figure_id: '8b47b24f-f427-11eb-b310-9b4fc6232458',
+ type: 'field',
+ total_area: 5587,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26919164618451,
+ lng: -123.18165204714356,
+ },
+ {
+ lat: 49.268547584065274,
+ lng: -123.18288586329041,
+ },
+ {
+ lat: 49.268603589800726,
+ lng: -123.1806328077179,
+ },
+ ],
+ perimeter: 377,
+ perimeter_unit: 'm',
+ organic_status: 'Non-Organic',
+ transition_date: '2021-08-03T07:00:00.000Z',
+ station_id: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: 'w',
+ notes: '',
+ location_id: 'c361c80a-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'c361c80b-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'garden',
+ total_area: 5309,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26919514649913,
+ lng: -123.18276784609375,
+ },
+ {
+ lat: 49.26819404639292,
+ lng: -123.18202755640564,
+ },
+ {
+ lat: 49.26790001313183,
+ lng: -123.18312189768372,
+ },
+ ],
+ perimeter: 356,
+ perimeter_unit: 'm',
+ organic_status: 'Non-Organic',
+ station_id: null,
+ transition_date: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: '4',
+ notes: '',
+ location_id: 'ce8f9676-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'ce8f9677-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'greenhouse',
+ total_area: 9938,
+ total_area_unit: 'ha',
+ grid_points: [
+ {
+ lat: 49.26823605100145,
+ lng: -123.18331501673279,
+ },
+ {
+ lat: 49.26825705329233,
+ lng: -123.18087957094727,
+ },
+ {
+ lat: 49.26926515273966,
+ lng: -123.18101904581604,
+ },
+ ],
+ perimeter: 492,
+ organic_status: 'Non-Organic',
+ supplemental_lighting: null,
+ co2_enrichment: null,
+ greenhouse_heated: null,
+ perimeter_unit: 'm',
+ transition_date: null,
+ },
+ {
+ farm_id: 'd49b0838-c812-11eb-b18a-0242ac120002',
+ name: '3',
+ notes: '',
+ location_id: 'd4ec5e8c-f70a-11eb-8dd7-6f2c0c6a4580',
+ figure_id: 'd4ec5e8d-f70a-11eb-8dd7-6f2c0c6a4580',
+ type: 'buffer_zone',
+ length: 224,
+ width: 8,
+ line_points: [
+ {
+ lat: 49.26831305935756,
+ lng: -123.18393728922425,
+ },
+ {
+ lat: 49.26787200987272,
+ lng: -123.18092248629151,
+ },
+ ],
+ width_unit: 'm',
+ total_area: 1795,
+ total_area_unit: 'ha',
+ length_unit: 'm',
+ },
+];
+
+export const TaskReadOnly = Template.bind({});
+TaskReadOnly.args = {
+ task: {
+ 'task_id': 2379,
+ 'due_date': '2021-10-13T07:00:00.000Z',
+ 'owner_user_id': '104942873090979111002',
+ 'notes': null,
+ 'completion_notes': null,
+ 'task_type_id': 92,
+ 'assignee_user_id': '104942873090979111002',
+ 'coordinates': null,
+ 'duration': null,
+ 'wage_at_moment': 0,
+ 'happiness': null,
+ 'complete_date': null,
+ 'late_time': null,
+ 'for_review_time': null,
+ 'abandon_date': null,
+ 'locations': [
+ {
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'name': '3',
+ 'notes': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'deleted': false,
+ 'figure_id': '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ 'type': 'field',
+ 'total_area': 37415,
+ 'total_area_unit': 'm2',
+ 'grid_points': [
+ {
+ 'lat': 49.28056848781515,
+ 'lng': -123.17292517721559,
+ },
+ {
+ 'lat': 49.278804704488074,
+ 'lng': -123.17485636770631,
+ },
+ {
+ 'lat': 49.27804877803772,
+ 'lng': -123.17043608724977,
+ },
+ ],
+ 'perimeter': null,
+ 'perimeter_unit': 'm',
+ 'station_id': 6173331,
+ 'organic_status': 'Non-Organic',
+ 'transition_date': null,
+ },
+ ],
+ 'managementPlans': [
+ {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': true,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ 'crop_variety_id': '82776686-c480-11eb-bb7c-0242ac120002',
+ 'crop_variety_name': '',
+ 'supplier': null,
+ 'compliance_file_url': null,
+ 'organic': null,
+ 'treated': null,
+ 'genetically_engineered': null,
+ 'searched': null,
+ 'crop_variety_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': null,
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ },
+ 'management_plan_id': 1175,
+ 'notes': '',
+ 'name': 'Plan 16',
+ 'start_date': '2021-10-29T07:00:00.000Z',
+ 'complete_date': null,
+ 'abandon_date': null,
+ 'complete_notes': null,
+ 'abandon_reason': null,
+ 'already_in_ground': true,
+ 'estimated_revenue': null,
+ 'for_cover': true,
+ 'germination_date': null,
+ 'harvest_date': null,
+ 'is_seed': null,
+ 'is_wild': true,
+ 'plant_date': null,
+ 'seed_date': null,
+ 'termination_date': '2021-10-27T07:00:00.000Z',
+ 'transplant_date': '2021-10-13T07:00:00.000Z',
+ 'estimated_yield_unit': 'kg',
+ 'estimated_yield': null,
+ 'estimated_price_per_mass': null,
+ 'estimated_price_per_mass_unit': 'lb',
+ 'crop_management_plan': {
+ 'already_in_ground': true,
+ 'estimated_revenue': null,
+ 'for_cover': true,
+ 'germination_date': null,
+ 'harvest_date': null,
+ 'is_seed': null,
+ 'is_wild': true,
+ 'management_plan_id': 1175,
+ 'needs_transplant': true,
+ 'plant_date': null,
+ 'seed_date': null,
+ 'termination_date': '2021-10-27T07:00:00.000Z',
+ 'transplant_date': '2021-10-13T07:00:00.000Z',
+ 'estimated_yield_unit': 'kg',
+ 'estimated_yield': null,
+ 'estimated_price_per_mass': null,
+ 'estimated_price_per_mass_unit': 'lb',
+ },
+ 'crop_variety': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ 'crop_variety_id': '82776686-c480-11eb-bb7c-0242ac120002',
+ 'crop_variety_name': '',
+ 'supplier': null,
+ 'compliance_file_url': null,
+ 'organic': null,
+ 'treated': null,
+ 'genetically_engineered': null,
+ 'searched': null,
+ 'crop_variety_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': null,
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ },
+ },
+ 'planting_management_plan': {
+ 'estimated_seeds': 0.00006,
+ 'estimated_seeds_unit': 'lb',
+ 'is_final_planting_management_plan': true,
+ 'is_planting_method_known': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': null,
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_method': 'CONTAINER_METHOD',
+ 'container_method': {
+ 'container_type': null,
+ 'in_ground': false,
+ 'number_of_containers': 2,
+ 'plant_spacing': null,
+ 'plant_spacing_unit': 'cm',
+ 'planting_depth': 0.019,
+ 'planting_depth_unit': 'in',
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_soil': '4',
+ 'plants_per_container': 3,
+ 'total_plants': null,
+ },
+ 'location': {
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'name': '3',
+ 'notes': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'deleted': false,
+ 'figure_id': '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ 'type': 'field',
+ 'total_area': 37415,
+ 'total_area_unit': 'm2',
+ 'grid_points': [
+ {
+ 'lat': 49.28056848781515,
+ 'lng': -123.17292517721559,
+ },
+ {
+ 'lat': 49.278804704488074,
+ 'lng': -123.17485636770631,
+ },
+ {
+ 'lat': 49.27804877803772,
+ 'lng': -123.17043608724977,
+ },
+ ],
+ 'perimeter': null,
+ 'perimeter_unit': 'm',
+ 'station_id': 6173331,
+ 'organic_status': 'Non-Organic',
+ 'transition_date': null,
+ },
+ },
+ 'prev_planting_management_plan': {
+ 'estimated_seeds': null,
+ 'estimated_seeds_unit': 'kg',
+ 'is_final_planting_management_plan': false,
+ 'is_planting_method_known': null,
+ 'location_id': null,
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': {
+ 'lat': 49.28057023756891,
+ 'lng': -123.17484563887025,
+ },
+ 'planting_management_plan_id': 'b28fc18d-0a0d-405f-9926-2cbcc7dd5e36',
+ 'planting_method': null,
+ },
+ },
+ ],
+ 'abandonment_reason': null,
+ 'other_abandonment_reason': null,
+ 'abandonment_notes': null,
+ 'taskType': {
+ 'task_type_id': 92,
+ 'task_name': 'Transplant',
+ 'task_translation_key': 'TRANSPLANT_TASK',
+ 'farm_id': null,
+ 'deleted': false,
+ },
+ 'transplant_task': {
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'task_id': 2379,
+ 'prev_planting_management_plan_id': 'b28fc18d-0a0d-405f-9926-2cbcc7dd5e36',
+ 'planting_management_plan': {
+ 'estimated_seeds': 0.00006,
+ 'estimated_seeds_unit': 'lb',
+ 'is_final_planting_management_plan': true,
+ 'is_planting_method_known': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': null,
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_method': 'CONTAINER_METHOD',
+ 'container_method': {
+ 'container_type': null,
+ 'in_ground': false,
+ 'number_of_containers': 2,
+ 'plant_spacing': null,
+ 'plant_spacing_unit': 'cm',
+ 'planting_depth': 0.019,
+ 'planting_depth_unit': 'in',
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_soil': '4',
+ 'plants_per_container': 3,
+ 'total_plants': null,
+ },
+ 'location': {
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'name': '3',
+ 'notes': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'deleted': false,
+ 'figure_id': '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ 'type': 'field',
+ 'total_area': 37415,
+ 'total_area_unit': 'm2',
+ 'grid_points': [
+ {
+ 'lat': 49.28056848781515,
+ 'lng': -123.17292517721559,
+ },
+ {
+ 'lat': 49.278804704488074,
+ 'lng': -123.17485636770631,
+ },
+ {
+ 'lat': 49.27804877803772,
+ 'lng': -123.17043608724977,
+ },
+ ],
+ 'perimeter': null,
+ 'perimeter_unit': 'm',
+ 'station_id': 6173331,
+ 'organic_status': 'Non-Organic',
+ 'transition_date': null,
+ },
+ },
+ 'prev_planting_management_plan': {
+ 'estimated_seeds': null,
+ 'estimated_seeds_unit': 'kg',
+ 'is_final_planting_management_plan': false,
+ 'is_planting_method_known': null,
+ 'location_id': null,
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': {
+ 'lat': 49.28057023756891,
+ 'lng': -123.17484563887025,
+ },
+ 'planting_management_plan_id': 'b28fc18d-0a0d-405f-9926-2cbcc7dd5e36',
+ 'planting_method': null,
+ },
+ },
+ 'pinCoordinates': [
+ {
+ 'lat': 49.28057023756891,
+ 'lng': -123.17484563887025,
+ },
+ ],
+ 'managementPlansByPinCoordinate': {
+ '49.28057, -123.174846': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': true,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ 'crop_variety_id': '82776686-c480-11eb-bb7c-0242ac120002',
+ 'crop_variety_name': '',
+ 'supplier': null,
+ 'compliance_file_url': null,
+ 'organic': null,
+ 'treated': null,
+ 'genetically_engineered': null,
+ 'searched': null,
+ 'crop_variety_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': null,
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ },
+ 'management_plan_id': 1175,
+ 'notes': '',
+ 'name': 'Plan 16',
+ 'start_date': '2021-10-29T07:00:00.000Z',
+ 'complete_date': null,
+ 'abandon_date': null,
+ 'complete_notes': null,
+ 'abandon_reason': null,
+ 'already_in_ground': true,
+ 'estimated_revenue': null,
+ 'for_cover': true,
+ 'germination_date': null,
+ 'harvest_date': null,
+ 'is_seed': null,
+ 'is_wild': true,
+ 'plant_date': null,
+ 'seed_date': null,
+ 'termination_date': '2021-10-27T07:00:00.000Z',
+ 'transplant_date': '2021-10-13T07:00:00.000Z',
+ 'estimated_yield_unit': 'kg',
+ 'estimated_yield': null,
+ 'estimated_price_per_mass': null,
+ 'estimated_price_per_mass_unit': 'lb',
+ 'crop_management_plan': {
+ 'already_in_ground': true,
+ 'estimated_revenue': null,
+ 'for_cover': true,
+ 'germination_date': null,
+ 'harvest_date': null,
+ 'is_seed': null,
+ 'is_wild': true,
+ 'management_plan_id': 1175,
+ 'needs_transplant': true,
+ 'plant_date': null,
+ 'seed_date': null,
+ 'termination_date': '2021-10-27T07:00:00.000Z',
+ 'transplant_date': '2021-10-13T07:00:00.000Z',
+ 'estimated_yield_unit': 'kg',
+ 'estimated_yield': null,
+ 'estimated_price_per_mass': null,
+ 'estimated_price_per_mass_unit': 'lb',
+ },
+ 'crop_variety': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ 'crop_variety_id': '82776686-c480-11eb-bb7c-0242ac120002',
+ 'crop_variety_name': '',
+ 'supplier': null,
+ 'compliance_file_url': null,
+ 'organic': null,
+ 'treated': null,
+ 'genetically_engineered': null,
+ 'searched': null,
+ 'crop_variety_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop': {
+ 'crop_common_name': 'Alfalfa for fodder',
+ 'crop_genus': 'Medicago',
+ 'crop_group': 'Other crops',
+ 'crop_id': 142,
+ 'crop_photo_url': 'https://litefarm.nyc3.cdn.digitaloceanspaces.com/default_crop/v2/alfalfa_for_fodder.webp',
+ 'crop_specie': 'sativa',
+ 'crop_subgroup': 'Grasses and other fodder crops',
+ 'crop_translation_key': 'ALFALFA_FOR_FODDER',
+ 'farm_id': null,
+ 'can_be_cover_crop': true,
+ 'planting_depth': 0.019,
+ 'yield_per_area': 4,
+ 'average_seed_weight': 0.00001,
+ 'yield_per_plant': null,
+ 'lifecycle': 'PERENNIAL',
+ 'seeding_type': 'SEED',
+ 'needs_transplant': false,
+ 'germination_days': 3,
+ 'transplant_days': null,
+ 'harvest_days': 60,
+ 'termination_days': null,
+ 'planting_method': 'ROW_METHOD',
+ 'plant_spacing': 0.6,
+ 'seeding_rate': null,
+ 'hs_code_id': '12149090',
+ },
+ },
+ 'planting_management_plan': {
+ 'estimated_seeds': 0.00006,
+ 'estimated_seeds_unit': 'lb',
+ 'is_final_planting_management_plan': true,
+ 'is_planting_method_known': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': null,
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_method': 'CONTAINER_METHOD',
+ 'container_method': {
+ 'container_type': null,
+ 'in_ground': false,
+ 'number_of_containers': 2,
+ 'plant_spacing': null,
+ 'plant_spacing_unit': 'cm',
+ 'planting_depth': 0.019,
+ 'planting_depth_unit': 'in',
+ 'planting_management_plan_id': '36c1f7b7-6194-4473-bc2c-1d2aa757e795',
+ 'planting_soil': '4',
+ 'plants_per_container': 3,
+ 'total_plants': null,
+ },
+ 'location': {
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'name': '3',
+ 'notes': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'deleted': false,
+ 'figure_id': '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ 'type': 'field',
+ 'total_area': 37415,
+ 'total_area_unit': 'm2',
+ 'grid_points': [
+ {
+ 'lat': 49.28056848781515,
+ 'lng': -123.17292517721559,
+ },
+ {
+ 'lat': 49.278804704488074,
+ 'lng': -123.17485636770631,
+ },
+ {
+ 'lat': 49.27804877803772,
+ 'lng': -123.17043608724977,
+ },
+ ],
+ 'perimeter': null,
+ 'perimeter_unit': 'm',
+ 'station_id': 6173331,
+ 'organic_status': 'Non-Organic',
+ 'transition_date': null,
+ },
+ },
+ 'prev_planting_management_plan': {
+ 'estimated_seeds': null,
+ 'estimated_seeds_unit': 'kg',
+ 'is_final_planting_management_plan': false,
+ 'is_planting_method_known': null,
+ 'location_id': null,
+ 'management_plan_id': 1175,
+ 'notes': null,
+ 'pin_coordinate': {
+ 'lat': 49.28057023756891,
+ 'lng': -123.17484563887025,
+ },
+ 'planting_management_plan_id': 'b28fc18d-0a0d-405f-9926-2cbcc7dd5e36',
+ 'planting_method': null,
+ },
+ 'firstTaskDate': '2021-10-13T07:00:00.000Z',
+ 'status': 'active',
+ },
+ },
+ 'managementPlansByLocation': {},
+ 'locationsById': {
+ '61f7cd2c-c09d-43cf-9687-a0502236acfd': {
+ 'farm_id': '71d84984-88cc-11eb-84e5-0a7facd3678d',
+ 'name': '3',
+ 'notes': null,
+ 'location_id': '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ 'deleted': false,
+ 'figure_id': '7fa88c46-c480-11eb-bb7c-0242ac120002',
+ 'type': 'field',
+ 'total_area': 37415,
+ 'total_area_unit': 'm2',
+ 'grid_points': [
+ {
+ 'lat': 49.28056848781515,
+ 'lng': -123.17292517721559,
+ },
+ {
+ 'lat': 49.278804704488074,
+ 'lng': -123.17485636770631,
+ },
+ {
+ 'lat': 49.27804877803772,
+ 'lng': -123.17043608724977,
+ },
+ ],
+ 'perimeter': null,
+ 'perimeter_unit': 'm',
+ 'station_id': 6173331,
+ 'organic_status': 'Non-Organic',
+ 'transition_date': null,
+ },
+ },
+ 'selectedLocationIds': [
+ '61f7cd2c-c09d-43cf-9687-a0502236acfd',
+ ],
+ },
+ users: [{ user_id: '1', first_name: 'John', last_name: 'Doe' }],
+ user: {
+ user_id: '1',
+ grid_points: {
+ 'lat': 49.276368899999994,
+ 'lng': -123.177324,
+ },
+ },
+ isAdmin: true,
+ managementPlansByLocationIds: [],
+ onGoBack: () => {
+ },
+ products: [],
+ harvestUseTypes: [],
+ maxZoomRef: { current: 19 },
+ getMaxZoom: () => 19,
+ system: 'metric',
+};
diff --git a/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.js b/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.js
deleted file mode 100644
index 55878f99f5..0000000000
--- a/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import decorators from '../config/decorators';
-import PureViewNotInterestedInCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification';
-import { chromaticSmallScreen } from '../config/chromatic';
-import PureViewSupportedCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification';
-import PureViewUnsupportedCertification from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification';
-
-export default {
- title: 'Page/ViewCertification',
- decorators: decorators,
- component: PureViewSupportedCertification,
-};
-
-const supportedCertifier = {
- certifier_name: 'British Columbia Association for Regenerative Agriculture',
- certifier_acronym: 'BCARA',
-};
-const supportedCertificationName = 'Organic';
-
-const unsupportedCertifierName = 'Oregon Tilth';
-
-const unsupportedCertificationName = 'Organic';
-
-const Supported = (args) => ;
-
-export const SupportedCertification = Supported.bind({});
-SupportedCertification.args = {
- supportedCertificationName,
- supportedCertifier,
- onBack: () => {},
-};
-SupportedCertification.parameters = {
- ...chromaticSmallScreen,
-};
-
-const Unsupported = (args) => ;
-
-export const UnsupportedCertification = Unsupported.bind({});
-UnsupportedCertification.args = {
- unsupportedCertifierName,
- unsupportedCertificationName,
-};
-UnsupportedCertification.parameters = {
- ...chromaticSmallScreen,
-};
-
-const NotInterested = (args) => ;
-
-export const NotInterestedInCertification = NotInterested.bind({});
-NotInterestedInCertification.args = {};
-NotInterestedInCertification.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.jsx b/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.jsx
new file mode 100644
index 0000000000..cd0bbc98bc
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/ViewCertification/ViewCertification.stories.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import decorators from '../config/Decorators';
+import PureViewNotInterestedInCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewNotInterestedInCertification';
+import { chromaticSmallScreen } from '../config/chromatic';
+import PureViewSupportedCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewSupportedCertification';
+import PureViewUnsupportedCertification
+ from '../../../components/OrganicCertifierSurvey/ViewCertification/PureViewUnsupportedCertification';
+
+export default {
+ title: 'Page/ViewCertification',
+ decorators: decorators,
+ component: PureViewSupportedCertification,
+};
+
+const supportedCertifier = {
+ certifier_name: 'British Columbia Association for Regenerative Agriculture',
+ certifier_acronym: 'BCARA',
+};
+const supportedCertificationName = 'Organic';
+
+const unsupportedCertifierName = 'Oregon Tilth';
+
+const unsupportedCertificationName = 'Organic';
+
+const Supported = (args) => ;
+
+export const SupportedCertification = Supported.bind({});
+SupportedCertification.args = {
+ supportedCertificationName,
+ supportedCertifier,
+ onBack: () => {},
+};
+SupportedCertification.parameters = {
+ ...chromaticSmallScreen,
+};
+
+const Unsupported = (args) => ;
+
+export const UnsupportedCertification = Unsupported.bind({});
+UnsupportedCertification.args = {
+ unsupportedCertifierName,
+ unsupportedCertificationName,
+};
+UnsupportedCertification.parameters = {
+ ...chromaticSmallScreen,
+};
+
+const NotInterested = (args) => ;
+
+export const NotInterestedInCertification = NotInterested.bind({});
+NotInterestedInCertification.args = {};
+NotInterestedInCertification.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Pages/config/Decorators.jsx b/packages/webapp/src/stories/Pages/config/Decorators.jsx
new file mode 100644
index 0000000000..3e8dc0e088
--- /dev/null
+++ b/packages/webapp/src/stories/Pages/config/Decorators.jsx
@@ -0,0 +1,99 @@
+import React from 'react';
+import { Provider } from 'react-redux';
+import { Router } from 'react-router-dom';
+import history from '../../../history';
+import { action } from '@storybook/addon-actions';
+import state from '../../../../.storybook/state';
+import NavBar from '../../../containers/Navigation';
+import theme from '../../../assets/theme';
+import { CssBaseline, ThemeProvider } from '@material-ui/core';
+
+const setIdToken = () => {
+ if (!localStorage.getItem('id_token')) {
+ localStorage.setItem('id_token', 'id_token');
+ }
+};
+
+export default [
+ (story) => {
+ setIdToken();
+ return
+
+ },
+];
+
+export const authenticatedDecorators = [
+ (story) => {
+ setIdToken();
+ return
+ },
+];
+
+export const decoratorsWithStore = [
+ (story) => {
+ return
+ {story()}
+ ;
+
+ },
+];
+
+export const componentDecorators = [
+ (story) => {
+ return {story()}
;
+ },
+];
+
+export const componentDecoratorsGreyBackground = [
+ (story) => {
+ return {story()}
;
+ },
+];
+
+export const componentDecoratorsWithoutPadding = [
+ (story) => {
+ return story();
+ },
+];
diff --git a/packages/webapp/src/stories/Pages/config/decorators.js b/packages/webapp/src/stories/Pages/config/decorators.js
deleted file mode 100644
index 43fc494fe0..0000000000
--- a/packages/webapp/src/stories/Pages/config/decorators.js
+++ /dev/null
@@ -1,188 +0,0 @@
-import React from 'react';
-import { Provider } from 'react-redux';
-import { Router } from 'react-router-dom';
-import history from '../../../history';
-import { action } from '@storybook/addon-actions';
-import state from './state';
-import NavBar from '../../../containers/Navigation';
-import theme from '../../../assets/theme';
-import { useTranslation } from 'react-i18next';
-import { CssBaseline, ThemeProvider } from '@material-ui/core';
-
-const store = {
- getState: () => {
- return state;
- },
- subscribe: () => 0,
- dispatch: action('dispatch'),
-};
-
-const auth = (isAuthenticated = false) => ({
- logout: () => {},
- isAuthenticated: () => isAuthenticated,
-});
-export const useI18next = () => {
- const { t, ready } = useTranslation(
- [
- 'certifications',
- 'crop_group',
- 'crop_nutrients',
- 'filter',
- 'translation',
- 'crop',
- 'common',
- 'disease',
- 'task',
- 'expense',
- 'fertilizer',
- 'message',
- 'gender',
- 'role',
- 'harvest_uses',
- 'soil',
- ],
- { useSuspense: false },
- );
- return ready;
-};
-
-const setIdToken = () => {
- if (!localStorage.getItem('id_token')) {
- localStorage.setItem('id_token', 'id_token');
- }
-};
-
-export default [
- (story) => {
- const ready = useI18next();
- setIdToken();
- return ready ? (
-
-
-
-
-
-
-
-
- ) : (
- loading
- );
- },
-];
-
-export const authenticatedDecorators = [
- (story) => {
- const ready = useI18next();
- setIdToken();
- return ready ? (
-
-
-
-
-
-
-
-
- ) : (
- loading
- );
- },
-];
-
-export const decoratorsWithStore = [
- (story) => {
- const ready = useI18next();
- return ready ? (
-
-
- <>
-
-
- {story()}
-
- >
-
-
- ) : (
- loading
- );
- },
-];
-
-export const themeWrapper = (story) => (
-
-
- {story()}
-
-);
-
-export const componentDecorators = [
- (story) => {
- const ready = useI18next();
- return ready ? {story()}
: loading
;
- },
- themeWrapper,
-];
-
-export const componentDecoratorsGreyBackground = [
- (story) => {
- const ready = useI18next();
- return ready ? (
- {story()}
- ) : (
- loading
- );
- },
- themeWrapper,
-];
-
-export const componentDecoratorsWithoutPadding = [
- (story) => {
- const ready = useI18next();
- return ready ? story() : loading
;
- },
- themeWrapper,
-];
diff --git a/packages/webapp/src/stories/Pages/config/state.js b/packages/webapp/src/stories/Pages/config/state.js
deleted file mode 100755
index 769aa4c1ab..0000000000
--- a/packages/webapp/src/stories/Pages/config/state.js
+++ /dev/null
@@ -1,11997 +0,0 @@
-export default {
- toastr: {
- toastrs: [],
- confirm: null,
- },
- profileForms: {
- addInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
- },
- farm: {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
- },
- notification: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- userInfo: {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
- },
- farmInfo: {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
- },
- editInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
- },
- signUpInfo: {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
- },
- forms: {
- $form: {
- initialValue: {
- addInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
- },
- farm: {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
- },
- notification: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- userInfo: {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
- },
- farmInfo: {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
- },
- editInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
- },
- signUpInfo: {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
- },
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms',
- value: {
- addInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
- },
- farm: {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
- },
- notification: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- userInfo: {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
- },
- farmInfo: {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
- },
- editInfo: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
- },
- signUpInfo: {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
- },
- },
- },
- addInfo: {
- $form: {
- initialValue: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo',
- value: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: '',
- amount: null,
- },
- },
- },
- first_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.first_name',
- value: '',
- },
- last_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.last_name',
- value: '',
- },
- email: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.email',
- value: '',
- },
- role: {
- initialValue: 'Worker',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.role',
- value: 'Worker',
- },
- pay: {
- $form: {
- initialValue: {
- type: '',
- amount: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.pay',
- value: {
- type: '',
- amount: null,
- },
- },
- type: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.pay.type',
- value: '',
- },
- amount: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.addInfo.pay.amount',
- value: null,
- },
- },
- },
- farm: {
- $form: {
- initialValue: {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm',
- value: {
- farm_name: '',
- address: '',
- gridPoints: {},
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- sandbox: false,
- },
- },
- farm_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.farm_name',
- value: '',
- },
- address: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.address',
- value: '',
- },
- gridPoints: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.gridPoints',
- value: {},
- },
- },
- unit: {
- initialValue: 'metric',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.unit',
- value: 'metric',
- },
- currency: {
- initialValue: 'CAD',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.currency',
- value: 'CAD',
- },
- date: {
- initialValue: 'MM/DD/YY',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.date',
- value: 'MM/DD/YY',
- },
- sandbox: {
- initialValue: false,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farm.sandbox',
- value: false,
- },
- },
- notification: {
- $form: {
- initialValue: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification',
- value: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- },
- alert_pest: {
- initialValue: true,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification.alert_pest',
- value: true,
- },
- alert_weather: {
- initialValue: true,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification.alert_weather',
- value: true,
- },
- alert_worker_finish: {
- initialValue: true,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification.alert_worker_finish',
- value: true,
- },
- alert_before_planned_date: {
- initialValue: true,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification.alert_before_planned_date',
- value: true,
- },
- alert_action_after_scouting: {
- initialValue: true,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.notification.alert_action_after_scouting',
- value: true,
- },
- },
- userInfo: {
- $form: {
- initialValue: {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo',
- value: {
- first_name: '',
- last_name: '',
- email: '',
- phone_number: '',
- address: '',
- profile_picture: '',
- },
- },
- first_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.first_name',
- value: '',
- },
- last_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.last_name',
- value: '',
- },
- email: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.email',
- value: '',
- },
- phone_number: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.phone_number',
- value: '',
- },
- address: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.address',
- value: '',
- },
- profile_picture: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.userInfo.profile_picture',
- value: '',
- },
- },
- farmInfo: {
- $form: {
- initialValue: {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo',
- value: {
- farm_name: '',
- unit: 'metric',
- currency: 'CAD',
- date: 'MM/DD/YY',
- phone_number: '',
- phone_country: '',
- address: '',
- gridPoints: {},
- },
- },
- farm_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.farm_name',
- value: '',
- },
- unit: {
- initialValue: 'metric',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.unit',
- value: 'metric',
- },
- currency: {
- initialValue: 'CAD',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.currency',
- value: 'CAD',
- },
- date: {
- initialValue: 'MM/DD/YY',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.date',
- value: 'MM/DD/YY',
- },
- phone_number: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.phone_number',
- value: '',
- },
- phone_country: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.phone_country',
- value: '',
- },
- address: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.address',
- value: '',
- },
- gridPoints: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.farmInfo.gridPoints',
- value: {},
- },
- },
- },
- editInfo: {
- $form: {
- initialValue: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo',
- value: {
- first_name: '',
- last_name: '',
- email: '',
- role: 'Worker',
- pay: {
- type: 'hourly',
- amount: 0,
- },
- },
- },
- first_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.first_name',
- value: '',
- },
- last_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.last_name',
- value: '',
- },
- email: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.email',
- value: '',
- },
- role: {
- initialValue: 'Worker',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.role',
- value: 'Worker',
- },
- pay: {
- $form: {
- initialValue: {
- type: 'hourly',
- amount: 0,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.pay',
- value: {
- type: 'hourly',
- amount: 0,
- },
- },
- type: {
- initialValue: 'hourly',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.pay.type',
- value: 'hourly',
- },
- amount: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.editInfo.pay.amount',
- value: 0,
- },
- },
- },
- signUpInfo: {
- $form: {
- initialValue: {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.signUpInfo',
- value: {
- first_name: '',
- last_name: '',
- email: '',
- password: '',
- },
- },
- first_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.signUpInfo.first_name',
- value: '',
- },
- last_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.signUpInfo.last_name',
- value: '',
- },
- email: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.signUpInfo.email',
- value: '',
- },
- password: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'profileForms.signUpInfo.password',
- value: '',
- },
- },
- },
- },
- entitiesReducer: {
- userFarmReducer: {
- farmIdUserIdTuple: [
- {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- {
- farm_id: '1f3f1d40-5f89-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- {
- farm_id: 'a1c9a974-5f89-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- {
- farm_id: 'e674adee-5f89-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- {
- farm_id: '22672200-5f8a-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- ],
- byFarmIdUserId: {
- 'cebbe678-5f88-11eb-89a9-31fa75807a90': {
- 'b04de06a-5f88-11eb-89a9-31fa75807a90': {
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- role_id: 1,
- has_consent: true,
- status: 'Active',
- consent_version: '3.0',
- wage: {
- type: 'hourly',
- amount: 0,
- },
- step_one: true,
- step_one_end: '2021-01-26T03:44:35.418Z',
- step_two: true,
- step_two_end: '2021-01-26T03:44:37.081Z',
- step_three: true,
- step_three_end: '2021-01-26T03:44:39.504Z',
- step_four: true,
- step_four_end: '2021-01-26T03:44:42.233Z',
- step_five: true,
- step_five_end: '2021-01-26T03:44:43.490Z',
- role: 'Owner',
- first_name: 'story',
- last_name: 'book',
- profile_picture: null,
- email: 'litefarmdev0+storybook@gmail.com',
- phone_number: null,
- user_address: null,
- notification_setting: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- language_preference: 'en',
- status_id: 1,
- gender: 'PREFER_NOT_TO_SAY',
- birth_year: 1990,
- farm_name: 'first farm',
- address: 'UBC Bus Loop, University Endowment Lands, BC V6T, Canada',
- units: {
- currency: 'CAD',
- measurement: 'metric',
- },
- grid_points: {
- lat: 49.2675373,
- lng: -123.2474431,
- },
- farm_phone_number: null,
- sandbox_farm: false,
- owner_operated: null,
- country_id: null,
- owner_name: 'story book',
- },
- },
- '1f3f1d40-5f89-11eb-89a9-31fa75807a90': {
- 'b04de06a-5f88-11eb-89a9-31fa75807a90': {
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- farm_id: '1f3f1d40-5f89-11eb-89a9-31fa75807a90',
- role_id: 5,
- has_consent: true,
- status: 'Active',
- consent_version: '3.0',
- wage: {
- type: 'hourly',
- amount: 0,
- },
- step_one: true,
- step_one_end: '2021-01-26T03:46:50.516Z',
- step_two: true,
- step_two_end: '2021-01-26T03:46:53.575Z',
- step_three: true,
- step_three_end: '2021-01-26T03:46:55.839Z',
- step_four: true,
- step_four_end: '2021-01-26T03:46:58.835Z',
- step_five: true,
- step_five_end: '2021-01-26T03:47:02.305Z',
- role: 'Extension Officer',
- first_name: 'story',
- last_name: 'book',
- profile_picture: null,
- email: 'litefarmdev0+storybook@gmail.com',
- phone_number: null,
- user_address: null,
- notification_setting: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- language_preference: 'en',
- status_id: 1,
- gender: 'PREFER_NOT_TO_SAY',
- birth_year: 1990,
- farm_name: 'second farm',
- address: '49.276368899999994, -123.177324',
- units: {
- currency: 'CAD',
- measurement: 'metric',
- },
- grid_points: {
- lat: 49.276368899999994,
- lng: -123.177324,
- },
- farm_phone_number: null,
- sandbox_farm: false,
- owner_operated: null,
- country_id: null,
- owner_name: null,
- },
- },
- 'a1c9a974-5f89-11eb-89a9-31fa75807a90': {
- 'b04de06a-5f88-11eb-89a9-31fa75807a90': {
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- farm_id: 'a1c9a974-5f89-11eb-89a9-31fa75807a90',
- role_id: 3,
- has_consent: false,
- status: 'Invited',
- consent_version: '1.0',
- wage: {
- type: 'hourly',
- amount: 0,
- },
- step_one: true,
- step_one_end: null,
- step_two: true,
- step_two_end: null,
- step_three: false,
- step_three_end: null,
- step_four: true,
- step_four_end: null,
- step_five: true,
- step_five_end: null,
- role: 'Worker',
- first_name: 'story',
- last_name: 'book',
- profile_picture: null,
- email: 'litefarmdev0+storybook@gmail.com',
- phone_number: null,
- user_address: null,
- notification_setting: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- language_preference: 'en',
- status_id: 1,
- gender: 'PREFER_NOT_TO_SAY',
- birth_year: 1990,
- farm_name: 'invited',
- address: 'Invitation Oak, San Antonio, TX 78261, USA',
- units: {
- currency: 'USD',
- measurement: 'imperial',
- },
- grid_points: {
- lat: 29.6690664,
- lng: -98.41689240000001,
- },
- farm_phone_number: null,
- sandbox_farm: false,
- owner_operated: null,
- country_id: null,
- owner_name: 'story book 2',
- },
- },
- 'e674adee-5f89-11eb-89a9-31fa75807a90': {
- 'b04de06a-5f88-11eb-89a9-31fa75807a90': {
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- farm_id: 'e674adee-5f89-11eb-89a9-31fa75807a90',
- role_id: 2,
- has_consent: false,
- status: 'Inactive',
- consent_version: '1.0',
- wage: {
- type: 'hourly',
- amount: 0,
- },
- step_one: true,
- step_one_end: null,
- step_two: true,
- step_two_end: null,
- step_three: false,
- step_three_end: null,
- step_four: true,
- step_four_end: null,
- step_five: true,
- step_five_end: null,
- role: 'Manager',
- first_name: 'story',
- last_name: 'book',
- profile_picture: null,
- email: 'litefarmdev0+storybook@gmail.com',
- phone_number: null,
- user_address: null,
- notification_setting: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- language_preference: 'en',
- status_id: 1,
- gender: 'PREFER_NOT_TO_SAY',
- birth_year: 1990,
- farm_name: 'access revoked',
- address:
- 'Northgate Cyberzone Northgate Ave, Alabang, Muntinlupa, 1781 Metro Manila, Philippines',
- units: {
- currency: 'PHP',
- measurement: 'metric',
- },
- grid_points: {
- lat: 14.426127,
- lng: 121.0402656,
- },
- farm_phone_number: null,
- sandbox_farm: false,
- owner_operated: null,
- country_id: null,
- owner_name: 'story book 2',
- },
- },
- '22672200-5f8a-11eb-89a9-31fa75807a90': {
- 'b04de06a-5f88-11eb-89a9-31fa75807a90': {
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- farm_id: '22672200-5f8a-11eb-89a9-31fa75807a90',
- role_id: 1,
- has_consent: true,
- status: 'Active',
- consent_version: '3.0',
- wage: {
- type: 'hourly',
- amount: 0,
- },
- step_one: true,
- step_one_end: '2021-01-26T03:54:05.306Z',
- step_two: true,
- step_two_end: '2021-01-26T03:54:07.590Z',
- step_three: true,
- step_three_end: '2021-01-26T03:54:10.296Z',
- step_four: true,
- step_four_end: '2021-01-26T03:54:12.876Z',
- step_five: true,
- step_five_end: '2021-01-26T03:54:15.215Z',
- role: 'Owner',
- first_name: 'story',
- last_name: 'book',
- profile_picture: null,
- email: 'litefarmdev0+storybook@gmail.com',
- phone_number: null,
- user_address: null,
- notification_setting: {
- alert_pest: true,
- alert_weather: true,
- alert_worker_finish: true,
- alert_before_planned_date: true,
- alert_action_after_scouting: true,
- },
- language_preference: 'en',
- status_id: 1,
- gender: 'PREFER_NOT_TO_SAY',
- birth_year: 1990,
- farm_name: 'selected farm',
- address: '49.276368899999994, -123.177324',
- units: {
- currency: 'CAD',
- measurement: 'metric',
- },
- grid_points: {
- lat: 49.276368899999994,
- lng: -123.177324,
- },
- farm_phone_number: null,
- sandbox_farm: false,
- owner_operated: null,
- country_id: null,
- owner_name: 'story book',
- },
- },
- },
- loading: false,
- error: null,
- loaded: true,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- user_id: 'b04de06a-5f88-11eb-89a9-31fa75807a90',
- },
- certifierSurveyReducer: {
- ids: ['cebbe678-5f88-11eb-89a9-31fa75807a90'],
- entities: {
- 'cebbe678-5f88-11eb-89a9-31fa75807a90': {
- interested: false,
- survey_id: 'd2cee530-5f88-11eb-89a9-31fa75807a90',
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- },
- },
- loading: false,
- error: null,
- },
- rolesReducer: {
- roles: [
- {
- role_id: 1,
- role: 'Owner',
- },
- {
- role_id: 2,
- role: 'Manager',
- },
- {
- role_id: 3,
- role: 'Worker',
- },
- {
- role_id: 5,
- role: 'Extension Officer',
- },
- ],
- loading: false,
- loaded: true,
- error: null,
- },
- cropReducer: {
- ids: [
- 3,
- 1,
- 2,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 20,
- 21,
- 22,
- 23,
- 24,
- 25,
- 26,
- 27,
- 28,
- 29,
- 30,
- 31,
- 32,
- 33,
- 34,
- 35,
- 36,
- 37,
- 38,
- 39,
- 40,
- 41,
- 42,
- 43,
- 44,
- 45,
- 46,
- 47,
- 48,
- 49,
- 50,
- 51,
- 52,
- 53,
- 54,
- 55,
- 56,
- 57,
- 58,
- 59,
- 60,
- 61,
- 62,
- 63,
- 64,
- 65,
- 66,
- 67,
- 68,
- 69,
- 70,
- 71,
- 72,
- 73,
- 74,
- 75,
- 76,
- 77,
- 78,
- 79,
- 80,
- 81,
- 82,
- 83,
- 84,
- 85,
- 86,
- 87,
- 88,
- 89,
- 90,
- 91,
- 92,
- 93,
- 94,
- 95,
- 96,
- 97,
- 98,
- 99,
- 100,
- 101,
- 102,
- 103,
- 104,
- 105,
- 106,
- 138,
- 107,
- 108,
- 109,
- 110,
- 111,
- 112,
- 113,
- 114,
- 115,
- 116,
- 117,
- 118,
- 119,
- 120,
- 121,
- 122,
- 123,
- 124,
- 125,
- 126,
- 127,
- 128,
- 129,
- 130,
- 131,
- 132,
- 133,
- 134,
- 135,
- 136,
- 137,
- 139,
- 140,
- 141,
- 142,
- 143,
- 144,
- 145,
- 146,
- 147,
- 148,
- 149,
- 150,
- 151,
- 152,
- 153,
- 154,
- 155,
- 156,
- 157,
- 158,
- 159,
- 160,
- 161,
- 162,
- 163,
- 164,
- 165,
- 166,
- 167,
- ],
- entities: {
- 1: {
- crop_id: 1,
- crop_common_name: 'Tea',
- crop_genus: 'Camellia',
- crop_specie: 'sinensis ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 1.2,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.95,
- mid_kc: 1,
- end_kc: 1,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: 0,
- lipid: 0,
- energy: 6.23125,
- ca: 0,
- fe: 0.124625,
- mg: 18.6938,
- ph: 6.23125,
- k: 230.556,
- na: 18.6938,
- zn: 0.124625,
- cu: 0.0623125,
- fl: null,
- mn: 1.36464,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0,
- riboflavin: 0.0872375,
- niacin: 0,
- pantothenic: null,
- vitb6: 0,
- folate: 31.1562,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TEA',
- },
- 2: {
- crop_id: 2,
- crop_common_name: 'Coffee',
- crop_genus: 'Coffea',
- crop_specie: 'spp. ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 1.2,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.9,
- mid_kc: 0.95,
- end_kc: 0.95,
- max_height: 2.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: 1.9878,
- lipid: 0.3313,
- energy: 16.565,
- ca: 33.13,
- fe: 0.16565,
- mg: 49.695,
- ph: 49.695,
- k: 811.685,
- na: 33.13,
- zn: 0.3313,
- cu: 0.03313,
- fl: null,
- mn: 0.380995,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.23191,
- riboflavin: 1.25894,
- niacin: 3.16391,
- pantothenic: null,
- vitb6: 0.016565,
- folate: 33.13,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'COFFEE',
- },
- 3: {
- crop_id: 3,
- crop_common_name: 'Hops',
- crop_genus: 'Humulus',
- crop_specie: 'lupulus ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 1.1,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.05,
- end_kc: 0.85,
- max_height: 5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'HOPS',
- },
- 4: {
- crop_id: 4,
- crop_common_name: 'Mint (all varieties)',
- crop_genus: 'Mentha',
- crop_specie: 'spp. ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Temporary spice crops',
- max_rooting_depth: 0.6,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 1.15,
- end_kc: 1.1,
- max_height: 0.7,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 39,
- refuse: null,
- protein: 3.75,
- lipid: 0.94,
- energy: 70,
- ca: 243,
- fe: 5.08,
- mg: 80,
- ph: 73,
- k: 569,
- na: 31,
- zn: 1.11,
- cu: 0.329,
- fl: null,
- mn: 1.176,
- se: null,
- vita_rae: 212,
- vite: null,
- vitc: 31.8,
- thiamin: 0.082,
- riboflavin: 0.266,
- niacin: 1.706,
- pantothenic: null,
- vitb6: 0.129,
- folate: 114,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MINT_ALL_VARIETIES',
- },
- 5: {
- crop_id: 5,
- crop_common_name: 'Cocoa (cacao)',
- crop_genus: 'Theobroma',
- crop_specie: 'cacao ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.85,
- depletion_fraction: 0.3,
- is_avg_depth: false,
- initial_kc: 1,
- mid_kc: 1.05,
- end_kc: 1.05,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 19.6,
- lipid: 13.7,
- energy: 228,
- ca: 128,
- fe: 13.86,
- mg: 499,
- ph: 734,
- k: 1524,
- na: 21,
- zn: 6.81,
- cu: 3.788,
- fl: null,
- mn: 3.837,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.078,
- riboflavin: 0.241,
- niacin: 2.185,
- pantothenic: null,
- vitb6: 0.118,
- folate: 32,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'COCOA_CACAO',
- },
- 6: {
- crop_id: 6,
- crop_common_name: 'Oats',
- crop_genus: 'Ave',
- crop_specie: 'spp. ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.15,
- end_kc: 0.25,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 16.89,
- lipid: 6.9,
- energy: 389,
- ca: 54,
- fe: 4.72,
- mg: 177,
- ph: 523,
- k: 429,
- na: 2,
- zn: 3.97,
- cu: 0.626,
- fl: null,
- mn: 4.916,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.763,
- riboflavin: 0.139,
- niacin: 0.961,
- pantothenic: null,
- vitb6: 0.119,
- folate: 56,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'OATS',
- },
- 7: {
- crop_id: 7,
- crop_common_name: 'Millet (Japanese)',
- crop_genus: 'Echinochloa',
- crop_specie: 'esculenta ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_JAPANESE',
- },
- 8: {
- crop_id: 8,
- crop_common_name: 'Millet (finger)',
- crop_genus: 'Eleusine',
- crop_specie: 'coracana ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_FINGER',
- },
- 9: {
- crop_id: 9,
- crop_common_name: 'Barley',
- crop_genus: 'Hordeum',
- crop_specie: 'vulgare ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.15,
- end_kc: 0.25,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 12.48,
- lipid: 2.3,
- energy: 354,
- ca: 33,
- fe: 3.6,
- mg: 133,
- ph: 264,
- k: 452,
- na: 12,
- zn: 2.77,
- cu: 0.498,
- fl: null,
- mn: 1.943,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 0,
- thiamin: 0.646,
- riboflavin: 0.285,
- niacin: 4.604,
- pantothenic: null,
- vitb6: 0.318,
- folate: 19,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BARLEY',
- },
- 10: {
- crop_id: 10,
- crop_common_name: 'Rice (African)',
- crop_genus: 'Oryza',
- crop_specie: 'glaberrima ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.204,
- is_avg_depth: false,
- initial_kc: 1.05,
- mid_kc: 1.2,
- end_kc: 0.75,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 6.5,
- lipid: 0.52,
- energy: 358,
- ca: 3,
- fe: 4.23,
- mg: 23,
- ph: 95,
- k: 76,
- na: 1,
- zn: 1.1,
- cu: 0.21,
- fl: null,
- mn: 1.037,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.565,
- riboflavin: 0.048,
- niacin: 4.113,
- pantothenic: null,
- vitb6: 0.171,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RICE_AFRICAN',
- },
- 11: {
- crop_id: 11,
- crop_common_name: 'Rice',
- crop_genus: 'Oryza',
- crop_specie: 'sativa ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.204,
- is_avg_depth: false,
- initial_kc: 1.05,
- mid_kc: 1.2,
- end_kc: 0.75,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 6.5,
- lipid: 0.52,
- energy: 358,
- ca: 3,
- fe: 4.23,
- mg: 23,
- ph: 95,
- k: 76,
- na: 1,
- zn: 1.1,
- cu: 0.21,
- fl: null,
- mn: 1.037,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.565,
- riboflavin: 0.048,
- niacin: 4.113,
- pantothenic: null,
- vitb6: 0.171,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RICE',
- },
- 12: {
- crop_id: 12,
- crop_common_name: 'Millet (proso)',
- crop_genus: 'Panicum',
- crop_specie: 'miliaceum ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_PROSO',
- },
- 13: {
- crop_id: 13,
- crop_common_name: 'Millet (bajra, pearl)',
- crop_genus: 'Pennisetum',
- crop_specie: 'americanum ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_BAJRA_PEARL',
- },
- 14: {
- crop_id: 14,
- crop_common_name: 'Rye',
- crop_genus: 'Secale',
- crop_specie: 'cereale ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 0.8,
- depletion_fraction: 0.6,
- is_avg_depth: false,
- initial_kc: 0.95,
- mid_kc: 1.05,
- end_kc: 1,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 10.34,
- lipid: 1.63,
- energy: 338,
- ca: 24,
- fe: 2.63,
- mg: 110,
- ph: 332,
- k: 510,
- na: 2,
- zn: 2.65,
- cu: 0.367,
- fl: null,
- mn: 2.577,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 0,
- thiamin: 0.316,
- riboflavin: 0.251,
- niacin: 4.27,
- pantothenic: null,
- vitb6: 0.294,
- folate: 38,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RYE',
- },
- 15: {
- crop_id: 15,
- crop_common_name: 'Millet (foxtail)',
- crop_genus: 'Setaria',
- crop_specie: 'italica ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_FOXTAIL',
- },
- 16: {
- crop_id: 16,
- crop_common_name: 'Broom millet',
- crop_genus: 'Sorghum',
- crop_specie: 'bicolor ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BROOM_MILLET',
- },
- 17: {
- crop_id: 17,
- crop_common_name: 'Broom sorghum',
- crop_genus: 'Sorghum',
- crop_specie: 'bicolor ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.1,
- end_kc: 0.55,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 10.62,
- lipid: 3.46,
- energy: 329,
- ca: 13,
- fe: 3.36,
- mg: 165,
- ph: 289,
- k: 363,
- na: 2,
- zn: 1.67,
- cu: 0.284,
- fl: null,
- mn: 1.605,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.332,
- riboflavin: 0.096,
- niacin: 3.688,
- pantothenic: null,
- vitb6: 0.443,
- folate: 20,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BROOM_SORGHUM',
- },
- 18: {
- crop_id: 18,
- crop_common_name: 'Millet (broom)',
- crop_genus: 'Sorghum',
- crop_specie: 'bicolor ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1,
- end_kc: 0.3,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 11.02,
- lipid: 4.22,
- energy: 378,
- ca: 8,
- fe: 3.01,
- mg: 114,
- ph: 285,
- k: 195,
- na: 5,
- zn: 1.68,
- cu: 0.75,
- fl: null,
- mn: 1.632,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.421,
- riboflavin: 0.29,
- niacin: 4.72,
- pantothenic: null,
- vitb6: 0.384,
- folate: 85,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MILLET_BROOM',
- },
- 19: {
- crop_id: 19,
- crop_common_name: 'Sorghum',
- crop_genus: 'Sorghum',
- crop_specie: 'bicolor ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.1,
- end_kc: 0.55,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 10.62,
- lipid: 3.46,
- energy: 329,
- ca: 13,
- fe: 3.36,
- mg: 165,
- ph: 289,
- k: 363,
- na: 2,
- zn: 1.67,
- cu: 0.284,
- fl: null,
- mn: 1.605,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.332,
- riboflavin: 0.096,
- niacin: 3.688,
- pantothenic: null,
- vitb6: 0.443,
- folate: 20,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SORGHUM',
- },
- 20: {
- crop_id: 20,
- crop_common_name: 'Wheat',
- crop_genus: 'Triticum',
- crop_specie: 'aestivum ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.55,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 1.15,
- end_kc: 0.3,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 15.4,
- lipid: 1.92,
- energy: 329,
- ca: 25,
- fe: 3.6,
- mg: 124,
- ph: 332,
- k: 340,
- na: 2,
- zn: 2.78,
- cu: 0.41,
- fl: null,
- mn: 4.055,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.504,
- riboflavin: 0.11,
- niacin: 5.71,
- pantothenic: null,
- vitb6: 0.336,
- folate: 43,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'WHEAT',
- },
- 21: {
- crop_id: 21,
- crop_common_name: 'Pineapple',
- crop_genus: 'Ananas',
- crop_specie: 'comosus ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.45,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 0.3,
- end_kc: 0.3,
- max_height: 0.8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 49,
- refuse: null,
- protein: 0.54,
- lipid: 0.12,
- energy: 50,
- ca: 13,
- fe: 0.29,
- mg: 12,
- ph: 8,
- k: 109,
- na: 1,
- zn: 0.12,
- cu: 0.11,
- fl: null,
- mn: 0.927,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 47.8,
- thiamin: 0.079,
- riboflavin: 0.032,
- niacin: 0.5,
- pantothenic: null,
- vitb6: 0.112,
- folate: 18,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PINEAPPLE',
- },
- 22: {
- crop_id: 22,
- crop_common_name: 'Grapefruit',
- crop_genus: 'Citrus',
- crop_specie: 'paradisi ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: 2,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 50,
- refuse: null,
- protein: 0.63,
- lipid: 0.1,
- energy: 32,
- ca: 12,
- fe: 0.09,
- mg: 8,
- ph: 8,
- k: 139,
- na: 0,
- zn: 0.07,
- cu: 0.047,
- fl: null,
- mn: 0.012,
- se: null,
- vita_rae: 46,
- vite: null,
- vitc: 34.4,
- thiamin: 0.036,
- riboflavin: 0.02,
- niacin: 0.25,
- pantothenic: null,
- vitb6: 0.042,
- folate: 10,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GRAPEFRUIT',
- },
- 23: {
- crop_id: 23,
- crop_common_name: 'Strawberry',
- crop_genus: 'Fragaria',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.25,
- depletion_fraction: 0.2,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 0.85,
- end_kc: 0.75,
- max_height: 0.2,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 6,
- refuse: null,
- protein: 0.67,
- lipid: 0.3,
- energy: 32,
- ca: 16,
- fe: 0.41,
- mg: 13,
- ph: 24,
- k: 153,
- na: 1,
- zn: 0.14,
- cu: 0.048,
- fl: null,
- mn: 0.386,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 58.8,
- thiamin: 0.024,
- riboflavin: 0.022,
- niacin: 0.386,
- pantothenic: null,
- vitb6: 0.047,
- folate: 24,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'STRAWBERRY',
- },
- 24: {
- crop_id: 24,
- crop_common_name: 'Walnut',
- crop_genus: 'Juglans',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 2.05,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1.1,
- end_kc: 0.6518,
- max_height: 4.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 76,
- refuse: null,
- protein: 24.06,
- lipid: 59.33,
- energy: 619,
- ca: 61,
- fe: 3.12,
- mg: 201,
- ph: 513,
- k: 523,
- na: 2,
- zn: 3.37,
- cu: 1.36,
- fl: null,
- mn: 3.896,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 1.7,
- thiamin: 0.057,
- riboflavin: 0.13,
- niacin: 0.47,
- pantothenic: null,
- vitb6: 0.583,
- folate: 31,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'WALNUT',
- },
- 25: {
- crop_id: 25,
- crop_common_name: 'Apple',
- crop_genus: 'Malus',
- crop_specie: 'sylvestris ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 0.45,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 0.3,
- end_kc: 0.3,
- max_height: 0.8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 0.26,
- lipid: 0.17,
- energy: 52,
- ca: 6,
- fe: 0.12,
- mg: 5,
- ph: 11,
- k: 107,
- na: 1,
- zn: 0.04,
- cu: 0.027,
- fl: null,
- mn: 0.035,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 4.6,
- thiamin: 0.017,
- riboflavin: 0.026,
- niacin: 0.091,
- pantothenic: null,
- vitb6: 0.041,
- folate: 3,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'APPLE',
- },
- 26: {
- crop_id: 26,
- crop_common_name: 'Banana',
- crop_genus: 'Musa',
- crop_specie: 'paradisiaca ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.7,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1.1,
- end_kc: 1,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 36,
- refuse: null,
- protein: 1.09,
- lipid: 0.33,
- energy: 89,
- ca: 5,
- fe: 0.26,
- mg: 27,
- ph: 22,
- k: 358,
- na: 1,
- zn: 0.15,
- cu: 0.078,
- fl: null,
- mn: 0.27,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 8.7,
- thiamin: 0.031,
- riboflavin: 0.073,
- niacin: 0.665,
- pantothenic: null,
- vitb6: 0.367,
- folate: 20,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BANANA',
- },
- 27: {
- crop_id: 27,
- crop_common_name: 'Plantain',
- crop_genus: 'Musa',
- crop_specie: 'sapientum ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.95,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 1.05,
- end_kc: 0.9,
- max_height: 0.8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 35,
- refuse: null,
- protein: 1.3,
- lipid: 0.37,
- energy: 122,
- ca: 3,
- fe: 0.6,
- mg: 37,
- ph: 34,
- k: 499,
- na: 4,
- zn: 0.14,
- cu: 0.081,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 56,
- vite: null,
- vitc: 18.4,
- thiamin: 0.052,
- riboflavin: 0.054,
- niacin: 0.686,
- pantothenic: null,
- vitb6: 0.299,
- folate: 22,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PLANTAIN',
- },
- 28: {
- crop_id: 28,
- crop_common_name: 'Avocado',
- crop_genus: 'Persea',
- crop_specie: 'americana ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.7,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 0.85,
- end_kc: 0.75,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 26,
- refuse: null,
- protein: 2,
- lipid: 14.66,
- energy: 160,
- ca: 12,
- fe: 0.55,
- mg: 29,
- ph: 52,
- k: 485,
- na: 7,
- zn: 0.64,
- cu: 0.19,
- fl: null,
- mn: 0.142,
- se: null,
- vita_rae: 7,
- vite: null,
- vitc: 10,
- thiamin: 0.067,
- riboflavin: 0.13,
- niacin: 1.738,
- pantothenic: null,
- vitb6: 0.257,
- folate: 81,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'AVOCADO',
- },
- 29: {
- crop_id: 29,
- crop_common_name: 'Dates',
- crop_genus: 'Phoenix',
- crop_specie: 'dactylifera ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 2,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.9,
- mid_kc: 0.95,
- end_kc: 0.95,
- max_height: 8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 2.45,
- lipid: 0.39,
- energy: 282,
- ca: 39,
- fe: 1.02,
- mg: 43,
- ph: 62,
- k: 656,
- na: 2,
- zn: 0.29,
- cu: 0.206,
- fl: null,
- mn: 0.262,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0.4,
- thiamin: 0.052,
- riboflavin: 0.066,
- niacin: 1.274,
- pantothenic: null,
- vitb6: 0.165,
- folate: 19,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'DATES',
- },
- 30: {
- crop_id: 30,
- crop_common_name: 'Pistachio nut',
- crop_genus: 'Pistacia',
- crop_specie: 'vera ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1.1,
- end_kc: 0.45,
- max_height: 4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 47,
- refuse: null,
- protein: 20.27,
- lipid: 45.39,
- energy: 562,
- ca: 105,
- fe: 3.92,
- mg: 121,
- ph: 490,
- k: 1025,
- na: 1,
- zn: 2.2,
- cu: 1.3,
- fl: null,
- mn: 1.2,
- se: null,
- vita_rae: 21,
- vite: null,
- vitc: 5.6,
- thiamin: 0.87,
- riboflavin: 0.16,
- niacin: 1.3,
- pantothenic: null,
- vitb6: 1.7,
- folate: 51,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PISTACHIO_NUT',
- },
- 31: {
- crop_id: 31,
- crop_common_name: 'Apricot',
- crop_genus: 'Prunus',
- crop_specie: 'armeniaca ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.55,
- mid_kc: 0.9,
- end_kc: 0.6518,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 7,
- refuse: null,
- protein: 1.4,
- lipid: 0.39,
- energy: 48,
- ca: 13,
- fe: 0.39,
- mg: 10,
- ph: 23,
- k: 259,
- na: 1,
- zn: 0.2,
- cu: 0.078,
- fl: null,
- mn: 0.077,
- se: null,
- vita_rae: 96,
- vite: null,
- vitc: 10,
- thiamin: 0.03,
- riboflavin: 0.04,
- niacin: 0.6,
- pantothenic: null,
- vitb6: 0.054,
- folate: 9,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'APRICOT',
- },
- 32: {
- crop_id: 32,
- crop_common_name: 'Almond',
- crop_genus: 'Prunus',
- crop_specie: 'dulcis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 0.9,
- end_kc: 0.6518,
- max_height: 5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 60,
- refuse: null,
- protein: 21.15,
- lipid: 49.93,
- energy: 579,
- ca: 269,
- fe: 3.71,
- mg: 270,
- ph: 481,
- k: 733,
- na: 1,
- zn: 3.12,
- cu: 1.031,
- fl: null,
- mn: 2.179,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.205,
- riboflavin: 1.138,
- niacin: 3.618,
- pantothenic: null,
- vitb6: 0.137,
- folate: 44,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ALMOND',
- },
- 33: {
- crop_id: 33,
- crop_common_name: 'Peach',
- crop_genus: 'Prunus',
- crop_specie: 'persica ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.55,
- mid_kc: 0.9,
- end_kc: 0.6518,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 4,
- refuse: null,
- protein: 0.91,
- lipid: 0.25,
- energy: 39,
- ca: 6,
- fe: 0.25,
- mg: 9,
- ph: 20,
- k: 190,
- na: 0,
- zn: 0.17,
- cu: 0.068,
- fl: null,
- mn: 0.061,
- se: null,
- vita_rae: 16,
- vite: null,
- vitc: 6.6,
- thiamin: 0.024,
- riboflavin: 0.031,
- niacin: 0.806,
- pantothenic: null,
- vitb6: 0.025,
- folate: 4,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PEACH',
- },
- 34: {
- crop_id: 34,
- crop_common_name: 'Pear',
- crop_genus: 'Pyrus',
- crop_specie: 'communis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 0.95,
- end_kc: 0.7518,
- max_height: 4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 0.36,
- lipid: 0.14,
- energy: 57,
- ca: 9,
- fe: 0.18,
- mg: 7,
- ph: 12,
- k: 116,
- na: 1,
- zn: 0.1,
- cu: 0.082,
- fl: null,
- mn: 0.048,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 4.3,
- thiamin: 0.012,
- riboflavin: 0.026,
- niacin: 0.161,
- pantothenic: null,
- vitb6: 0.029,
- folate: 7,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PEAR',
- },
- 35: {
- crop_id: 35,
- crop_common_name: 'Grapes ',
- crop_genus: 'Vitis',
- crop_specie: 'vinifera ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Grapes',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: 2,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 42,
- refuse: null,
- protein: 0.63,
- lipid: 0.35,
- energy: 67,
- ca: 14,
- fe: 0.29,
- mg: 5,
- ph: 10,
- k: 191,
- na: 2,
- zn: 0.04,
- cu: 0.04,
- fl: null,
- mn: 0.718,
- se: null,
- vita_rae: 5,
- vite: null,
- vitc: 4,
- thiamin: 0.092,
- riboflavin: 0.057,
- niacin: 0.3,
- pantothenic: null,
- vitb6: 0.11,
- folate: 4,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GRAPES_',
- },
- 36: {
- crop_id: 36,
- crop_common_name: 'Chickpea (gram pea)',
- crop_genus: 'Cicer',
- crop_specie: 'arietinum ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.8,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1,
- end_kc: 0.35,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 20.47,
- lipid: 6.04,
- energy: 378,
- ca: 57,
- fe: 4.31,
- mg: 79,
- ph: 252,
- k: 718,
- na: 24,
- zn: 2.76,
- cu: 0.656,
- fl: null,
- mn: 21.306,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 4,
- thiamin: 0.477,
- riboflavin: 0.212,
- niacin: 1.541,
- pantothenic: null,
- vitb6: 0.535,
- folate: 557,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 50,
- crop_translation_key: 'CHICKPEA_GRAM_PEA',
- },
- 37: {
- crop_id: 37,
- crop_common_name: 'Lentil',
- crop_genus: 'Lens',
- crop_specie: 'culinaris ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.7,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1.1,
- end_kc: 0.3,
- max_height: 0.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 24.63,
- lipid: 1.06,
- energy: 352,
- ca: 35,
- fe: 6.51,
- mg: 47,
- ph: 281,
- k: 677,
- na: 6,
- zn: 3.27,
- cu: 0.754,
- fl: null,
- mn: 1.393,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 4.5,
- thiamin: 0.873,
- riboflavin: 0.211,
- niacin: 2.605,
- pantothenic: null,
- vitb6: 0.54,
- folate: 479,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 40,
- crop_translation_key: 'LENTIL',
- },
- 38: {
- crop_id: 38,
- crop_common_name: 'Groundnut (peanut)',
- crop_genus: 'Arachis',
- crop_specie: 'hypogaea ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1.15,
- end_kc: 0.6,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 25.8,
- lipid: 49.24,
- energy: 567,
- ca: 92,
- fe: 4.58,
- mg: 168,
- ph: 376,
- k: 705,
- na: 18,
- zn: 3.27,
- cu: 1.144,
- fl: null,
- mn: 1.934,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.64,
- riboflavin: 0.135,
- niacin: 12.066,
- pantothenic: null,
- vitb6: 0.348,
- folate: 240,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 80,
- crop_translation_key: 'GROUNDNUT_PEANUT',
- },
- 39: {
- crop_id: 39,
- crop_common_name: 'Safflower',
- crop_genus: 'Carthamus',
- crop_specie: 'tinctorius ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.6,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 1.15,
- end_kc: 0.25,
- max_height: 0.8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 49,
- refuse: null,
- protein: 16.18,
- lipid: 38.45,
- energy: 517,
- ca: 78,
- fe: 4.9,
- mg: 353,
- ph: 644,
- k: 687,
- na: 3,
- zn: 5.05,
- cu: 1.747,
- fl: null,
- mn: 2.014,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 0,
- thiamin: 1.163,
- riboflavin: 0.415,
- niacin: 2.284,
- pantothenic: null,
- vitb6: 1.17,
- folate: 160,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SAFFLOWER',
- },
- 40: {
- crop_id: 40,
- crop_common_name: 'Soybean',
- crop_genus: 'Glycine',
- crop_specie: 'max ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 0.95,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1.15,
- end_kc: 0.5,
- max_height: 0.7,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 36.49,
- lipid: 19.94,
- energy: 446,
- ca: 277,
- fe: 15.7,
- mg: 280,
- ph: 704,
- k: 1797,
- na: 2,
- zn: 4.89,
- cu: 1.658,
- fl: null,
- mn: 2.517,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 6,
- thiamin: 0.874,
- riboflavin: 0.87,
- niacin: 1.623,
- pantothenic: null,
- vitb6: 0.377,
- folate: 375,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 80,
- crop_translation_key: 'SOYBEAN',
- },
- 41: {
- crop_id: 41,
- crop_common_name: 'Sunflower',
- crop_genus: 'Helianthus',
- crop_specie: 'annuus ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.6,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 1.15,
- end_kc: 0.25,
- max_height: 0.8,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 46,
- refuse: null,
- protein: 20.78,
- lipid: 51.46,
- energy: 584,
- ca: 78,
- fe: 5.25,
- mg: 325,
- ph: 660,
- k: 645,
- na: 9,
- zn: 5,
- cu: 1.8,
- fl: null,
- mn: 1.95,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 1.4,
- thiamin: 1.48,
- riboflavin: 0.355,
- niacin: 8.335,
- pantothenic: null,
- vitb6: 1.345,
- folate: 227,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SUNFLOWER',
- },
- 42: {
- crop_id: 42,
- crop_common_name: 'Olive',
- crop_genus: 'Olea',
- crop_specie: 'europaea ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Permanent oilseed crops',
- max_rooting_depth: 1.45,
- depletion_fraction: 0.65,
- is_avg_depth: false,
- initial_kc: 0.65,
- mid_kc: 0.7,
- end_kc: 0.7,
- max_height: 4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0.84,
- lipid: 10.68,
- energy: 115,
- ca: 88,
- fe: 3.3,
- mg: 4,
- ph: 3,
- k: 8,
- na: 735,
- zn: 0.22,
- cu: 0.251,
- fl: null,
- mn: 0.02,
- se: null,
- vita_rae: 20,
- vite: null,
- vitc: 0.9,
- thiamin: 0.003,
- riboflavin: 0,
- niacin: 0.037,
- pantothenic: null,
- vitb6: 0.009,
- folate: 0,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'OLIVE',
- },
- 43: {
- crop_id: 43,
- crop_common_name: 'Sesame',
- crop_genus: 'Sesamum',
- crop_specie: 'indicum ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.6,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 1.1,
- end_kc: 0.25,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 20.45,
- lipid: 61.21,
- energy: 631,
- ca: 60,
- fe: 6.36,
- mg: 345,
- ph: 667,
- k: 370,
- na: 47,
- zn: 6.73,
- cu: 1.4,
- fl: null,
- mn: 1.44,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 0,
- thiamin: 0.699,
- riboflavin: 0.09,
- niacin: 5.8,
- pantothenic: null,
- vitb6: 0.4,
- folate: 115,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SESAME',
- },
- 44: {
- crop_id: 44,
- crop_common_name: 'Sisal',
- crop_genus: 'Agave',
- crop_specie: 'sisalana ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.8,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 0.6,
- end_kc: 0.6,
- max_height: 1.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SISAL',
- },
- 45: {
- crop_id: 45,
- crop_common_name: 'Cotton (all varieties)',
- crop_genus: 'Gossypium',
- crop_specie: 'spp. ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 1.35,
- depletion_fraction: 0.65,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 1.15,
- end_kc: 0.6,
- max_height: 1.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 32.59,
- lipid: 36.29,
- energy: 506,
- ca: 100,
- fe: 5.4,
- mg: 440,
- ph: 800,
- k: 1350,
- na: 25,
- zn: 6,
- cu: 1.2,
- fl: null,
- mn: 2.181,
- se: null,
- vita_rae: 22,
- vite: null,
- vitc: 9,
- thiamin: 0.75,
- riboflavin: 0.255,
- niacin: 3,
- pantothenic: null,
- vitb6: 0.782,
- folate: 233,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'COTTON_ALL_VARIETIES',
- },
- 46: {
- crop_id: 46,
- crop_common_name: 'Rubber',
- crop_genus: 'Hevea',
- crop_specie: 'brasiliensis ',
- crop_group: 'Other crops',
- crop_subgroup: 'Rubber',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.95,
- mid_kc: 1,
- end_kc: 1,
- max_height: 10,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RUBBER',
- },
- 47: {
- crop_id: 47,
- crop_common_name: 'Flax ',
- crop_genus: 'Linum',
- crop_specie: 'usitatissimum ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.35,
- mid_kc: 1.1,
- end_kc: 0.25,
- max_height: 1.2,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 18.29,
- lipid: 42.16,
- energy: 534,
- ca: 255,
- fe: 5.73,
- mg: 392,
- ph: 642,
- k: 813,
- na: 30,
- zn: 4.34,
- cu: 1.22,
- fl: null,
- mn: 2.482,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0.6,
- thiamin: 1.644,
- riboflavin: 0.161,
- niacin: 3.08,
- pantothenic: null,
- vitb6: 0.473,
- folate: 87,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'FLAX_',
- },
- 48: {
- crop_id: 48,
- crop_common_name: 'Sweet potato',
- crop_genus: 'Ipomoea',
- crop_specie: 'batatas ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.5,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1.15,
- end_kc: 0.754,
- max_height: 0.6,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 28,
- refuse: null,
- protein: 1.57,
- lipid: 0.05,
- energy: 86,
- ca: 30,
- fe: 0.61,
- mg: 25,
- ph: 47,
- k: 337,
- na: 55,
- zn: 0.3,
- cu: 0.151,
- fl: null,
- mn: 0.258,
- se: null,
- vita_rae: 709,
- vite: null,
- vitc: 2.4,
- thiamin: 0.078,
- riboflavin: 0.061,
- niacin: 0.557,
- pantothenic: null,
- vitb6: 0.209,
- folate: 11,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SWEET_POTATO',
- },
- 49: {
- crop_id: 49,
- crop_common_name: 'Cassava (manioc)',
- crop_genus: 'Manihot',
- crop_specie: 'esculenta ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.38,
- is_avg_depth: false,
- initial_kc: 0.3,
- mid_kc: 0.803,
- end_kc: 0.3,
- max_height: 1,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 16,
- refuse: null,
- protein: 1.36,
- lipid: 0.28,
- energy: 160,
- ca: 16,
- fe: 0.27,
- mg: 21,
- ph: 27,
- k: 271,
- na: 14,
- zn: 0.34,
- cu: 0.1,
- fl: null,
- mn: 0.384,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 20.6,
- thiamin: 0.087,
- riboflavin: 0.048,
- niacin: 0.854,
- pantothenic: null,
- vitb6: 0.088,
- folate: 27,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CASSAVA_MANIOC',
- },
- 50: {
- crop_id: 50,
- crop_common_name: 'Potato',
- crop_genus: 'Solamum',
- crop_specie: 'tuberosum ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.5,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1.15,
- end_kc: 0.754,
- max_height: 0.6,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 25,
- refuse: null,
- protein: 2.14,
- lipid: 0.08,
- energy: 79,
- ca: 13,
- fe: 0.86,
- mg: 23,
- ph: 55,
- k: 417,
- na: 5,
- zn: 0.29,
- cu: 0.103,
- fl: null,
- mn: 0.157,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 5.7,
- thiamin: 0.082,
- riboflavin: 0.033,
- niacin: 1.035,
- pantothenic: null,
- vitb6: 0.345,
- folate: 14,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'POTATO',
- },
- 51: {
- crop_id: 51,
- crop_common_name: 'Sugarcane',
- crop_genus: 'Saccharum',
- crop_specie: 'officinarum ',
- crop_group: 'Sugar crops',
- crop_subgroup: 'Sugar crops (other)',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.65,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1.25,
- end_kc: 0.75,
- max_height: 3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0,
- lipid: 0,
- energy: 399,
- ca: 12,
- fe: 0.37,
- mg: 2,
- ph: 1,
- k: 29,
- na: 3,
- zn: 0.03,
- cu: 0.009,
- fl: null,
- mn: 0.046,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SUGARCANE',
- },
- 52: {
- crop_id: 52,
- crop_common_name: 'Onion',
- crop_genus: 'Allium',
- crop_specie: 'cepa ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.45,
- depletion_fraction: 0.3,
- is_avg_depth: false,
- initial_kc: 1.05,
- mid_kc: 1.05,
- end_kc: 0.75,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 1.1,
- lipid: 0.1,
- energy: 40,
- ca: 23,
- fe: 0.21,
- mg: 10,
- ph: 29,
- k: 146,
- na: 4,
- zn: 0.17,
- cu: 0.039,
- fl: null,
- mn: 0.129,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 7.4,
- thiamin: 0.046,
- riboflavin: 0.027,
- niacin: 0.116,
- pantothenic: null,
- vitb6: 0.12,
- folate: 19,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ONION',
- },
- 53: {
- crop_id: 53,
- crop_common_name: 'Garlic',
- crop_genus: 'Allium',
- crop_specie: 'sativum ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.3,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1,
- end_kc: 0.7,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 13,
- refuse: null,
- protein: 6.36,
- lipid: 0.5,
- energy: 149,
- ca: 181,
- fe: 1.7,
- mg: 25,
- ph: 153,
- k: 401,
- na: 17,
- zn: 1.16,
- cu: 0.299,
- fl: null,
- mn: 1.672,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 31.2,
- thiamin: 0.2,
- riboflavin: 0.11,
- niacin: 0.7,
- pantothenic: null,
- vitb6: 1.235,
- folate: 3,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GARLIC',
- },
- 54: {
- crop_id: 54,
- crop_common_name: 'Celery',
- crop_genus: 'Apium',
- crop_specie: 'graveolens ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.2,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 1,
- max_height: 0.6,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 11,
- refuse: null,
- protein: 0.69,
- lipid: 0.17,
- energy: 16,
- ca: 40,
- fe: 0.2,
- mg: 11,
- ph: 24,
- k: 260,
- na: 80,
- zn: 0.13,
- cu: 0.035,
- fl: null,
- mn: 0.103,
- se: null,
- vita_rae: 22,
- vite: null,
- vitc: 3.1,
- thiamin: 0.021,
- riboflavin: 0.057,
- niacin: 0.32,
- pantothenic: null,
- vitb6: 0.074,
- folate: 36,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CELERY',
- },
- 55: {
- crop_id: 55,
- crop_common_name: 'Celeriac',
- crop_genus: 'Apium',
- crop_specie: 'graveolens var. rapaceum ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.2,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 1,
- max_height: 0.6,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 14,
- refuse: null,
- protein: 1.5,
- lipid: 0.3,
- energy: 42,
- ca: 43,
- fe: 0.7,
- mg: 20,
- ph: 115,
- k: 300,
- na: 100,
- zn: 0.33,
- cu: 0.07,
- fl: null,
- mn: 0.158,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 8,
- thiamin: 0.05,
- riboflavin: 0.06,
- niacin: 0.7,
- pantothenic: null,
- vitb6: 0.165,
- folate: 8,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CELERIAC',
- },
- 56: {
- crop_id: 56,
- crop_common_name: 'Asparagus',
- crop_genus: 'Asparagus',
- crop_specie: 'officinalis ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 0.957,
- end_kc: 0.3,
- max_height: 0.5,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 47,
- refuse: null,
- protein: 2.2,
- lipid: 0.12,
- energy: 20,
- ca: 24,
- fe: 2.14,
- mg: 14,
- ph: 52,
- k: 202,
- na: 2,
- zn: 0.54,
- cu: 0.189,
- fl: null,
- mn: 0.158,
- se: null,
- vita_rae: 38,
- vite: null,
- vitc: 5.6,
- thiamin: 0.143,
- riboflavin: 0.141,
- niacin: 0.978,
- pantothenic: null,
- vitb6: 0.091,
- folate: 52,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ASPARAGUS',
- },
- 57: {
- crop_id: 57,
- crop_common_name: 'Cabbage, Chinese',
- crop_genus: 'Brassica',
- crop_specie: 'chinensis ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.65,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 12,
- refuse: null,
- protein: 1.5,
- lipid: 0.2,
- energy: 13,
- ca: 105,
- fe: 0.8,
- mg: 19,
- ph: 37,
- k: 252,
- na: 65,
- zn: 0.19,
- cu: 0.021,
- fl: null,
- mn: 0.159,
- se: null,
- vita_rae: 223,
- vite: null,
- vitc: 45,
- thiamin: 0.04,
- riboflavin: 0.07,
- niacin: 0.5,
- pantothenic: null,
- vitb6: 0.194,
- folate: 66,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CABBAGE_CHINESE',
- },
- 58: {
- crop_id: 58,
- crop_common_name: 'Broccoli',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.5,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 39,
- refuse: null,
- protein: 2.82,
- lipid: 0.37,
- energy: 34,
- ca: 47,
- fe: 0.73,
- mg: 21,
- ph: 66,
- k: 316,
- na: 33,
- zn: 0.41,
- cu: 0.049,
- fl: null,
- mn: 0.21,
- se: null,
- vita_rae: 31,
- vite: null,
- vitc: 89.2,
- thiamin: 0.071,
- riboflavin: 0.117,
- niacin: 0.639,
- pantothenic: null,
- vitb6: 0.175,
- folate: 63,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BROCCOLI',
- },
- 59: {
- crop_id: 59,
- crop_common_name: 'Cauliflower',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea var. botrytis ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.55,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 61,
- refuse: null,
- protein: 1.92,
- lipid: 0.28,
- energy: 25,
- ca: 22,
- fe: 0.42,
- mg: 15,
- ph: 44,
- k: 299,
- na: 30,
- zn: 0.27,
- cu: 0.039,
- fl: null,
- mn: 0.155,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 48.2,
- thiamin: 0.05,
- riboflavin: 0.06,
- niacin: 0.507,
- pantothenic: null,
- vitb6: 0.184,
- folate: 57,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CAULIFLOWER',
- },
- 60: {
- crop_id: 60,
- crop_common_name: 'Cabbage',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea var. capitata ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.65,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 12,
- refuse: null,
- protein: 1.5,
- lipid: 0.2,
- energy: 13,
- ca: 105,
- fe: 0.8,
- mg: 19,
- ph: 37,
- k: 252,
- na: 65,
- zn: 0.19,
- cu: 0.021,
- fl: null,
- mn: 0.159,
- se: null,
- vita_rae: 223,
- vite: null,
- vitc: 45,
- thiamin: 0.04,
- riboflavin: 0.07,
- niacin: 0.5,
- pantothenic: null,
- vitb6: 0.194,
- folate: 66,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CABBAGE',
- },
- 61: {
- crop_id: 61,
- crop_common_name: 'Brussels sprouts',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea var. gemmifera ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.5,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 3.38,
- lipid: 0.3,
- energy: 43,
- ca: 42,
- fe: 1.4,
- mg: 23,
- ph: 69,
- k: 389,
- na: 25,
- zn: 0.42,
- cu: 0.07,
- fl: null,
- mn: 0.337,
- se: null,
- vita_rae: 38,
- vite: null,
- vitc: 85,
- thiamin: 0.139,
- riboflavin: 0.09,
- niacin: 0.745,
- pantothenic: null,
- vitb6: 0.219,
- folate: 61,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BRUSSELS_SPROUTS',
- },
- 62: {
- crop_id: 62,
- crop_common_name: 'Watermelon',
- crop_genus: 'Citrullus',
- crop_specie: 'lanatus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.15,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.4,
- mid_kc: 1,
- end_kc: 0.75,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 48,
- refuse: null,
- protein: 0.61,
- lipid: 0.15,
- energy: 30,
- ca: 7,
- fe: 0.24,
- mg: 10,
- ph: 11,
- k: 112,
- na: 1,
- zn: 0.1,
- cu: 0.042,
- fl: null,
- mn: 0.038,
- se: null,
- vita_rae: 28,
- vite: null,
- vitc: 8.1,
- thiamin: 0.033,
- riboflavin: 0.021,
- niacin: 0.178,
- pantothenic: null,
- vitb6: 0.045,
- folate: 3,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'WATERMELON',
- },
- 63: {
- crop_id: 63,
- crop_common_name: 'Cantaloupe',
- crop_genus: 'Cucumis',
- crop_specie: 'melo ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.2,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 0.85,
- end_kc: 0.6,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 49,
- refuse: null,
- protein: 0.84,
- lipid: 0.19,
- energy: 34,
- ca: 9,
- fe: 0.21,
- mg: 12,
- ph: 15,
- k: 267,
- na: 16,
- zn: 0.18,
- cu: 0.041,
- fl: null,
- mn: 0.041,
- se: null,
- vita_rae: 169,
- vite: null,
- vitc: 36.7,
- thiamin: 0.041,
- riboflavin: 0.019,
- niacin: 0.734,
- pantothenic: null,
- vitb6: 0.072,
- folate: 21,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CANTALOUPE',
- },
- 64: {
- crop_id: 64,
- crop_common_name: 'Cucumber',
- crop_genus: 'Cucumis',
- crop_specie: 'sativus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 0.95,
- depletion_fraction: 0.5,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 1,
- end_kc: 0.8,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 3,
- refuse: null,
- protein: 0.65,
- lipid: 0.11,
- energy: 15,
- ca: 16,
- fe: 0.28,
- mg: 13,
- ph: 24,
- k: 147,
- na: 2,
- zn: 0.2,
- cu: 0.041,
- fl: null,
- mn: 0.079,
- se: null,
- vita_rae: 5,
- vite: null,
- vitc: 2.8,
- thiamin: 0.027,
- riboflavin: 0.033,
- niacin: 0.098,
- pantothenic: null,
- vitb6: 0.04,
- folate: 7,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CUCUMBER',
- },
- 65: {
- crop_id: 65,
- crop_common_name: 'Squash',
- crop_genus: 'Cucurbita',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.25,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 1,
- end_kc: 0.8,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 5,
- refuse: null,
- protein: 1.21,
- lipid: 0.18,
- energy: 16,
- ca: 15,
- fe: 0.35,
- mg: 17,
- ph: 38,
- k: 262,
- na: 2,
- zn: 0.29,
- cu: 0.051,
- fl: null,
- mn: 0.175,
- se: null,
- vita_rae: 10,
- vite: null,
- vitc: 17,
- thiamin: 0.048,
- riboflavin: 0.142,
- niacin: 0.487,
- pantothenic: null,
- vitb6: 0.218,
- folate: 29,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SQUASH',
- },
- 66: {
- crop_id: 66,
- crop_common_name: 'Artichoke',
- crop_genus: 'Cynara',
- crop_specie: 'scolymus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1,
- end_kc: 0.95,
- max_height: 0.7,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 60,
- refuse: null,
- protein: 3.27,
- lipid: 0.15,
- energy: 47,
- ca: 44,
- fe: 1.28,
- mg: 60,
- ph: 90,
- k: 370,
- na: 94,
- zn: 0.49,
- cu: 0.231,
- fl: null,
- mn: 0.256,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 11.7,
- thiamin: 0.072,
- riboflavin: 0.066,
- niacin: 1.046,
- pantothenic: null,
- vitb6: 0.116,
- folate: 68,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ARTICHOKE',
- },
- 67: {
- crop_id: 67,
- crop_common_name: 'Carrot',
- crop_genus: 'Daucus',
- crop_specie: 'carota ssp. sativa ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 11,
- refuse: null,
- protein: 0.93,
- lipid: 0.24,
- energy: 41,
- ca: 33,
- fe: 0.3,
- mg: 12,
- ph: 35,
- k: 320,
- na: 69,
- zn: 0.24,
- cu: 0.045,
- fl: null,
- mn: 0.143,
- se: null,
- vita_rae: 835,
- vite: null,
- vitc: 5.9,
- thiamin: 0.066,
- riboflavin: 0.058,
- niacin: 0.983,
- pantothenic: null,
- vitb6: 0.138,
- folate: 19,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CARROT',
- },
- 68: {
- crop_id: 68,
- crop_common_name: 'Jerusalem artichoke',
- crop_genus: 'Helianthus',
- crop_specie: 'tuberosus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.45,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1,
- end_kc: 0.95,
- max_height: 0.7,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 31,
- refuse: null,
- protein: 2,
- lipid: 0.01,
- energy: 73,
- ca: 14,
- fe: 3.4,
- mg: 17,
- ph: 78,
- k: 429,
- na: 4,
- zn: 0.12,
- cu: 0.14,
- fl: null,
- mn: 0.06,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 4,
- thiamin: 0.2,
- riboflavin: 0.06,
- niacin: 1.3,
- pantothenic: null,
- vitb6: 0.077,
- folate: 13,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'JERUSALEM_ARTICHOKE',
- },
- 69: {
- crop_id: 69,
- crop_common_name: 'Lettuce',
- crop_genus: 'Lactuca',
- crop_specie: 'sativa var. capitata ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.3,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1,
- end_kc: 0.95,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 26,
- refuse: null,
- protein: 1.35,
- lipid: 0.22,
- energy: 13,
- ca: 35,
- fe: 1.24,
- mg: 13,
- ph: 33,
- k: 238,
- na: 5,
- zn: 0.2,
- cu: 0.016,
- fl: null,
- mn: 0.179,
- se: null,
- vita_rae: 166,
- vite: null,
- vitc: 3.7,
- thiamin: 0.057,
- riboflavin: 0.062,
- niacin: 0.357,
- pantothenic: null,
- vitb6: 0.082,
- folate: 73,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LETTUCE',
- },
- 70: {
- crop_id: 70,
- crop_common_name: 'Tomato',
- crop_genus: 'Lycopersicon',
- crop_specie: 'esculentum ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.1,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.6,
- mid_kc: 1.152,
- end_kc: 0.8,
- max_height: 0.6,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 9,
- refuse: null,
- protein: 0.88,
- lipid: 0.2,
- energy: 18,
- ca: 10,
- fe: 0.27,
- mg: 11,
- ph: 24,
- k: 237,
- na: 5,
- zn: 0.17,
- cu: 0.059,
- fl: null,
- mn: 0.114,
- se: null,
- vita_rae: 42,
- vite: null,
- vitc: 13.7,
- thiamin: 0.037,
- riboflavin: 0.019,
- niacin: 0.594,
- pantothenic: null,
- vitb6: 0.08,
- folate: 15,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TOMATO',
- },
- 71: {
- crop_id: 71,
- crop_common_name: 'Parsnip',
- crop_genus: 'Pastinaca',
- crop_specie: 'sativa ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.4,
- is_avg_depth: false,
- initial_kc: 0.5,
- mid_kc: 1.05,
- end_kc: 0.95,
- max_height: 0.4,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 15,
- refuse: null,
- protein: 1.2,
- lipid: 0.3,
- energy: 75,
- ca: 36,
- fe: 0.59,
- mg: 29,
- ph: 71,
- k: 375,
- na: 10,
- zn: 0.59,
- cu: 0.12,
- fl: null,
- mn: 0.56,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 17,
- thiamin: 0.09,
- riboflavin: 0.05,
- niacin: 0.7,
- pantothenic: null,
- vitb6: 0.09,
- folate: 67,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PARSNIP',
- },
- 72: {
- crop_id: 72,
- crop_common_name: 'Radish',
- crop_genus: 'Raphanus',
- crop_specie: 'sativus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.3,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 0.9,
- end_kc: 0.85,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 9,
- refuse: null,
- protein: 1.43,
- lipid: 0.25,
- energy: 23,
- ca: 19,
- fe: 0.57,
- mg: 13,
- ph: 40,
- k: 302,
- na: 22,
- zn: 0.62,
- cu: 0.341,
- fl: null,
- mn: 0.138,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 8,
- thiamin: 0.016,
- riboflavin: 0.028,
- niacin: 0.255,
- pantothenic: null,
- vitb6: 0.057,
- folate: 60,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RADISH',
- },
- 73: {
- crop_id: 73,
- crop_common_name: 'Spinach',
- crop_genus: 'Spinacia',
- crop_specie: 'oleracea ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.4,
- depletion_fraction: 0.2,
- is_avg_depth: false,
- initial_kc: 0.7,
- mid_kc: 1,
- end_kc: 0.95,
- max_height: 0.3,
- is_avg_kc: false,
- nutrient_notes: null,
- percentrefuse: 28,
- refuse: null,
- protein: 2.86,
- lipid: 0.39,
- energy: 23,
- ca: 99,
- fe: 2.71,
- mg: 79,
- ph: 49,
- k: 558,
- na: 79,
- zn: 0.53,
- cu: 0.13,
- fl: null,
- mn: 0.897,
- se: null,
- vita_rae: 469,
- vite: null,
- vitc: 28.1,
- thiamin: 0.078,
- riboflavin: 0.189,
- niacin: 0.724,
- pantothenic: null,
- vitb6: 0.195,
- folate: 194,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SPINACH',
- },
- 74: {
- crop_id: 74,
- crop_common_name: 'Chili (all varieties)',
- crop_genus: 'Capsicum',
- crop_specie: 'spp. ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Temporary spice crops',
- max_rooting_depth: 0.6,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.6,
- mid_kc: 1.15,
- end_kc: 1.1,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 27,
- refuse: null,
- protein: 1.87,
- lipid: 0.44,
- energy: 40,
- ca: 14,
- fe: 1.03,
- mg: 23,
- ph: 43,
- k: 322,
- na: 9,
- zn: 0.26,
- cu: 0.129,
- fl: null,
- mn: 0.187,
- se: null,
- vita_rae: 48,
- vite: null,
- vitc: 143.7,
- thiamin: 0.072,
- riboflavin: 0.086,
- niacin: 1.244,
- pantothenic: null,
- vitb6: 0.506,
- folate: 23,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CHILI_ALL_VARIETIES',
- },
- 75: {
- crop_id: 75,
- crop_common_name: 'Caraway seeds',
- crop_genus: 'Carum',
- crop_specie: 'carvi ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Temporary spice crops',
- max_rooting_depth: 0.6,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.6,
- mid_kc: 1.15,
- end_kc: 1.1,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 19.77,
- lipid: 14.59,
- energy: 333,
- ca: 689,
- fe: 16.23,
- mg: 258,
- ph: 568,
- k: 1351,
- na: 17,
- zn: 5.5,
- cu: 0.91,
- fl: null,
- mn: 1.3,
- se: null,
- vita_rae: 18,
- vite: null,
- vitc: 21,
- thiamin: 0.383,
- riboflavin: 0.379,
- niacin: 3.606,
- pantothenic: null,
- vitb6: 0.36,
- folate: 10,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CARAWAY_SEEDS',
- },
- 76: {
- crop_id: 76,
- crop_common_name: 'Cinnamon',
- crop_genus: 'Cinnamomum',
- crop_specie: 'verum ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 3.99,
- lipid: 1.24,
- energy: 247,
- ca: 1002,
- fe: 8.32,
- mg: 60,
- ph: 64,
- k: 431,
- na: 10,
- zn: 1.83,
- cu: 0.339,
- fl: null,
- mn: 17.466,
- se: null,
- vita_rae: 15,
- vite: null,
- vitc: 3.8,
- thiamin: 0.022,
- riboflavin: 0.041,
- niacin: 1.332,
- pantothenic: null,
- vitb6: 0.158,
- folate: 6,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CINNAMON',
- },
- 77: {
- crop_id: 77,
- crop_common_name: 'Cardamom',
- crop_genus: 'Elettaria',
- crop_specie: 'cardamomum ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 10.76,
- lipid: 6.7,
- energy: 311,
- ca: 383,
- fe: 13.97,
- mg: 229,
- ph: 178,
- k: 1119,
- na: 18,
- zn: 7.47,
- cu: 0.383,
- fl: null,
- mn: 28,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 21,
- thiamin: 0.198,
- riboflavin: 0.182,
- niacin: 1.102,
- pantothenic: null,
- vitb6: 0.23,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CARDAMOM',
- },
- 78: {
- crop_id: 78,
- crop_common_name: 'Drumstick tree',
- crop_genus: 'Moringa',
- crop_specie: 'oleifera ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 38,
- refuse: null,
- protein: 9.4,
- lipid: 1.4,
- energy: 64,
- ca: 185,
- fe: 4,
- mg: 147,
- ph: 112,
- k: 337,
- na: 9,
- zn: 0.6,
- cu: 0.105,
- fl: null,
- mn: 1.063,
- se: null,
- vita_rae: 378,
- vite: null,
- vitc: 51.7,
- thiamin: 0.257,
- riboflavin: 0.66,
- niacin: 2.22,
- pantothenic: null,
- vitb6: 1.2,
- folate: 40,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'DRUMSTICK_TREE',
- },
- 79: {
- crop_id: 79,
- crop_common_name: 'Mace',
- crop_genus: 'Myristica',
- crop_specie: 'fragrans ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 6.71,
- lipid: 32.38,
- energy: 475,
- ca: 252,
- fe: 13.9,
- mg: 163,
- ph: 110,
- k: 463,
- na: 80,
- zn: 2.3,
- cu: 2.467,
- fl: null,
- mn: 1.5,
- se: null,
- vita_rae: 40,
- vite: null,
- vitc: 21,
- thiamin: 0.312,
- riboflavin: 0.448,
- niacin: 1.35,
- pantothenic: null,
- vitb6: 0.16,
- folate: 76,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MACE',
- },
- 80: {
- crop_id: 80,
- crop_common_name: 'Nutmeg',
- crop_genus: 'Myristica',
- crop_specie: 'fragrans ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 5.84,
- lipid: 36.31,
- energy: 525,
- ca: 184,
- fe: 3.04,
- mg: 183,
- ph: 213,
- k: 350,
- na: 16,
- zn: 2.15,
- cu: 1.027,
- fl: null,
- mn: 2.9,
- se: null,
- vita_rae: 5,
- vite: null,
- vitc: 3,
- thiamin: 0.346,
- riboflavin: 0.057,
- niacin: 1.299,
- pantothenic: null,
- vitb6: 0.16,
- folate: 76,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'NUTMEG',
- },
- 81: {
- crop_id: 81,
- crop_common_name: 'Anise seeds',
- crop_genus: 'Pimpinella',
- crop_specie: 'anisum ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Temporary spice crops',
- max_rooting_depth: 0.6,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.6,
- mid_kc: 1.15,
- end_kc: 1.1,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 17.6,
- lipid: 15.9,
- energy: 337,
- ca: 646,
- fe: 36.96,
- mg: 170,
- ph: 440,
- k: 1441,
- na: 16,
- zn: 5.3,
- cu: 0.91,
- fl: null,
- mn: 2.3,
- se: null,
- vita_rae: 16,
- vite: null,
- vitc: 21,
- thiamin: 0.34,
- riboflavin: 0.29,
- niacin: 3.06,
- pantothenic: null,
- vitb6: 0.65,
- folate: 10,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ANISE_SEEDS',
- },
- 82: {
- crop_id: 82,
- crop_common_name: 'Black pepper',
- crop_genus: 'Piper',
- crop_specie: 'nigrum ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 18,
- refuse: null,
- protein: 1.66,
- lipid: 0.45,
- energy: 27,
- ca: 14,
- fe: 0.46,
- mg: 17,
- ph: 32,
- k: 256,
- na: 13,
- zn: 0.25,
- cu: 0.094,
- fl: null,
- mn: 0.1,
- se: null,
- vita_rae: 17,
- vite: null,
- vitc: 82.7,
- thiamin: 0.081,
- riboflavin: 0.054,
- niacin: 1.242,
- pantothenic: null,
- vitb6: 0.357,
- folate: 29,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BLACK_PEPPER',
- },
- 83: {
- crop_id: 83,
- crop_common_name: 'Vanilla',
- crop_genus: 'Vanilla',
- crop_specie: 'planifolia ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0.06,
- lipid: 0.06,
- energy: 288,
- ca: 11,
- fe: 0.12,
- mg: 12,
- ph: 6,
- k: 148,
- na: 9,
- zn: 0.11,
- cu: 0.072,
- fl: null,
- mn: 0.23,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.011,
- riboflavin: 0.095,
- niacin: 0.425,
- pantothenic: null,
- vitb6: 0.026,
- folate: 0,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'VANILLA',
- },
- 84: {
- crop_id: 84,
- crop_common_name: 'Ginger',
- crop_genus: 'Zingiber',
- crop_specie: 'officinale ',
- crop_group: 'Beverage and spice crops',
- crop_subgroup: 'Permanent spice crops',
- max_rooting_depth: 0.99,
- depletion_fraction: 0.4,
- is_avg_depth: true,
- initial_kc: 0.75,
- mid_kc: 1.04,
- end_kc: 0.99,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 8.98,
- lipid: 4.24,
- energy: 335,
- ca: 114,
- fe: 19.8,
- mg: 214,
- ph: 168,
- k: 1320,
- na: 27,
- zn: 3.64,
- cu: 0.48,
- fl: null,
- mn: 33.3,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 0.7,
- thiamin: 0.046,
- riboflavin: 0.17,
- niacin: 9.62,
- pantothenic: null,
- vitb6: 0.626,
- folate: 13,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GINGER',
- },
- 85: {
- crop_id: 85,
- crop_common_name: 'Quinoa',
- crop_genus: 'Chenopodium',
- crop_specie: 'quinoa ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 14.12,
- lipid: 6.07,
- energy: 368,
- ca: 47,
- fe: 4.57,
- mg: 197,
- ph: 457,
- k: 563,
- na: 5,
- zn: 3.1,
- cu: 0.59,
- fl: null,
- mn: 2.033,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: null,
- thiamin: 0.36,
- riboflavin: 0.318,
- niacin: 1.52,
- pantothenic: null,
- vitb6: 0.487,
- folate: 184,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'QUINOA',
- },
- 86: {
- crop_id: 86,
- crop_common_name: 'Tef',
- crop_genus: 'Eragrostis',
- crop_specie: 'abyssinica ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 13.3,
- lipid: 2.38,
- energy: 367,
- ca: 180,
- fe: 7.63,
- mg: 184,
- ph: 429,
- k: 427,
- na: 12,
- zn: 3.63,
- cu: 0.81,
- fl: null,
- mn: 9.24,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: null,
- thiamin: 0.39,
- riboflavin: 0.27,
- niacin: 3.363,
- pantothenic: null,
- vitb6: 0.482,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TEF',
- },
- 87: {
- crop_id: 87,
- crop_common_name: 'Buckwheat',
- crop_genus: 'Fagopyrum',
- crop_specie: 'esculentum ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: 1,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 13.25,
- lipid: 3.4,
- energy: 343,
- ca: 18,
- fe: 2.2,
- mg: 231,
- ph: 347,
- k: 460,
- na: 1,
- zn: 2.4,
- cu: 1.1,
- fl: null,
- mn: 1.3,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.101,
- riboflavin: 0.425,
- niacin: 7.02,
- pantothenic: null,
- vitb6: 0.21,
- folate: 30,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BUCKWHEAT',
- },
- 88: {
- crop_id: 88,
- crop_common_name: 'Durum wheat',
- crop_genus: 'Triticum',
- crop_specie: 'durum ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: 1,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 13.68,
- lipid: 2.47,
- energy: 339,
- ca: 34,
- fe: 3.52,
- mg: 144,
- ph: 508,
- k: 431,
- na: 2,
- zn: 4.16,
- cu: 0.553,
- fl: null,
- mn: 3.012,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0.419,
- riboflavin: 0.121,
- niacin: 6.738,
- pantothenic: null,
- vitb6: 0.419,
- folate: 43,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'DURUM_WHEAT',
- },
- 89: {
- crop_id: 89,
- crop_common_name: 'Maize (grain)',
- crop_genus: 'Zea',
- crop_specie: 'mays ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 9.42,
- lipid: 4.74,
- energy: 365,
- ca: 7,
- fe: 2.71,
- mg: 127,
- ph: 210,
- k: 287,
- na: 35,
- zn: 2.21,
- cu: 0.314,
- fl: null,
- mn: 0.485,
- se: null,
- vita_rae: 11,
- vite: null,
- vitc: 0,
- thiamin: 0.385,
- riboflavin: 0.201,
- niacin: 3.627,
- pantothenic: null,
- vitb6: 0.622,
- folate: 19,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MAIZE_GRAIN',
- },
- 90: {
- crop_id: 90,
- crop_common_name: 'Maize (sweet corn)',
- crop_genus: 'Zea',
- crop_specie: 'mays ',
- crop_group: 'Cereals',
- crop_subgroup: 'Cereals',
- max_rooting_depth: 1.30333,
- depletion_fraction: 0.5072,
- is_avg_depth: true,
- initial_kc: 0.443333,
- mid_kc: 1.07333,
- end_kc: 0.433333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 64,
- refuse: null,
- protein: 3.27,
- lipid: 1.35,
- energy: 86,
- ca: 2,
- fe: 0.52,
- mg: 37,
- ph: 89,
- k: 270,
- na: 15,
- zn: 0.46,
- cu: 0.054,
- fl: null,
- mn: 0.163,
- se: null,
- vita_rae: 9,
- vite: null,
- vitc: 6.8,
- thiamin: 0.155,
- riboflavin: 0.055,
- niacin: 1.77,
- pantothenic: null,
- vitb6: 0.093,
- folate: 42,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MAIZE_SWEET_CORN',
- },
- 91: {
- crop_id: 91,
- crop_common_name: 'Sapodilla',
- crop_genus: 'Achras',
- crop_specie: 'sapota ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Other fruits',
- max_rooting_depth: 1.17188,
- depletion_fraction: 0.45,
- is_avg_depth: true,
- initial_kc: 0.509375,
- mid_kc: 0.865625,
- end_kc: 0.653687,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 20,
- refuse: null,
- protein: 0.44,
- lipid: 1.1,
- energy: 83,
- ca: 21,
- fe: 0.8,
- mg: 12,
- ph: 12,
- k: 193,
- na: 12,
- zn: 0.1,
- cu: 0.086,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 14.7,
- thiamin: 0,
- riboflavin: 0.02,
- niacin: 0.2,
- pantothenic: null,
- vitb6: 0.037,
- folate: 14,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SAPODILLA',
- },
- 92: {
- crop_id: 92,
- crop_common_name: 'Cashew nuts',
- crop_genus: 'Anacardium',
- crop_specie: 'occidentale ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 28,
- refuse: null,
- protein: 18.22,
- lipid: 43.85,
- energy: 553,
- ca: 37,
- fe: 6.68,
- mg: 292,
- ph: 593,
- k: 660,
- na: 12,
- zn: 5.78,
- cu: 2.195,
- fl: null,
- mn: 1.655,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0.5,
- thiamin: 0.423,
- riboflavin: 0.058,
- niacin: 1.062,
- pantothenic: null,
- vitb6: 0.417,
- folate: 25,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CASHEW_NUTS',
- },
- 93: {
- crop_id: 93,
- crop_common_name: 'Custard apple',
- crop_genus: 'Anno',
- crop_specie: 'reticulate ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 42,
- refuse: null,
- protein: 1.7,
- lipid: 0.6,
- energy: 101,
- ca: 30,
- fe: 0.71,
- mg: 18,
- ph: 21,
- k: 382,
- na: 4,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 19.2,
- thiamin: 0.08,
- riboflavin: 0.1,
- niacin: 0.5,
- pantothenic: null,
- vitb6: 0.221,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CUSTARD_APPLE',
- },
- 94: {
- crop_id: 94,
- crop_common_name: 'Breadfruit',
- crop_genus: 'Artocarpus',
- crop_specie: 'altilis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 22,
- refuse: null,
- protein: 1.07,
- lipid: 0.23,
- energy: 103,
- ca: 17,
- fe: 0.54,
- mg: 25,
- ph: 30,
- k: 490,
- na: 2,
- zn: 0.12,
- cu: 0.084,
- fl: null,
- mn: 0.06,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 29,
- thiamin: 0.11,
- riboflavin: 0.03,
- niacin: 0.9,
- pantothenic: null,
- vitb6: 0.1,
- folate: 14,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BREADFRUIT',
- },
- 95: {
- crop_id: 95,
- crop_common_name: 'Brazil nut',
- crop_genus: 'Bertholletia',
- crop_specie: 'excelsa ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 49,
- refuse: null,
- protein: 14.32,
- lipid: 67.1,
- energy: 659,
- ca: 160,
- fe: 2.43,
- mg: 376,
- ph: 725,
- k: 659,
- na: 3,
- zn: 4.06,
- cu: 1.743,
- fl: null,
- mn: 1.223,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0.7,
- thiamin: 0.617,
- riboflavin: 0.035,
- niacin: 0.295,
- pantothenic: null,
- vitb6: 0.101,
- folate: 22,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BRAZIL_NUT',
- },
- 96: {
- crop_id: 96,
- crop_common_name: 'Papaya (pawpaw)',
- crop_genus: 'Carica',
- crop_specie: 'papaya ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 38,
- refuse: null,
- protein: 0.47,
- lipid: 0.26,
- energy: 43,
- ca: 20,
- fe: 0.25,
- mg: 21,
- ph: 10,
- k: 182,
- na: 8,
- zn: 0.08,
- cu: 0.045,
- fl: null,
- mn: 0.04,
- se: null,
- vita_rae: 47,
- vite: null,
- vitc: 60.9,
- thiamin: 0.023,
- riboflavin: 0.027,
- niacin: 0.357,
- pantothenic: null,
- vitb6: 0.038,
- folate: 37,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PAPAYA_PAWPAW',
- },
- 97: {
- crop_id: 97,
- crop_common_name: 'Pecan nut',
- crop_genus: 'Carya',
- crop_specie: 'illinoensis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 47,
- refuse: null,
- protein: 9.17,
- lipid: 71.97,
- energy: 691,
- ca: 70,
- fe: 2.53,
- mg: 121,
- ph: 277,
- k: 410,
- na: 0,
- zn: 4.53,
- cu: 1.2,
- fl: null,
- mn: 4.5,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 1.1,
- thiamin: 0.66,
- riboflavin: 0.13,
- niacin: 1.167,
- pantothenic: null,
- vitb6: 0.21,
- folate: 22,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PECAN_NUT',
- },
- 98: {
- crop_id: 98,
- crop_common_name: 'Chestnut',
- crop_genus: 'Castanea',
- crop_specie: 'sativa ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 20,
- refuse: null,
- protein: 6.39,
- lipid: 4.45,
- energy: 374,
- ca: 67,
- fe: 2.38,
- mg: 74,
- ph: 175,
- k: 986,
- na: 37,
- zn: 0.35,
- cu: 0.65,
- fl: null,
- mn: 1.3,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 15,
- thiamin: 0.295,
- riboflavin: 0.36,
- niacin: 0.85,
- pantothenic: null,
- vitb6: 0.663,
- folate: 109,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CHESTNUT',
- },
- 99: {
- crop_id: 99,
- crop_common_name: 'Orange (bitter)',
- crop_genus: 'Citrus',
- crop_specie: 'aurantium ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 27,
- refuse: null,
- protein: 0.94,
- lipid: 0.12,
- energy: 47,
- ca: 40,
- fe: 0.1,
- mg: 10,
- ph: 14,
- k: 181,
- na: 0,
- zn: 0.07,
- cu: 0.045,
- fl: null,
- mn: 0.025,
- se: null,
- vita_rae: 11,
- vite: null,
- vitc: 53.2,
- thiamin: 0.087,
- riboflavin: 0.04,
- niacin: 0.282,
- pantothenic: null,
- vitb6: 0.06,
- folate: 30,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ORANGE_BITTER',
- },
- 100: {
- crop_id: 100,
- crop_common_name: 'Pomelo',
- crop_genus: 'Citrus',
- crop_specie: 'grandis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 44,
- refuse: null,
- protein: 0.76,
- lipid: 0.04,
- energy: 38,
- ca: 4,
- fe: 0.11,
- mg: 6,
- ph: 17,
- k: 216,
- na: 1,
- zn: 0.08,
- cu: 0.048,
- fl: null,
- mn: 0.017,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 61,
- thiamin: 0.034,
- riboflavin: 0.027,
- niacin: 0.22,
- pantothenic: null,
- vitb6: 0.036,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'POMELO',
- },
- 101: {
- crop_id: 101,
- crop_common_name: 'Lemon',
- crop_genus: 'Citrus',
- crop_specie: 'limon ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 47,
- refuse: null,
- protein: 1.1,
- lipid: 0.3,
- energy: 29,
- ca: 26,
- fe: 0.6,
- mg: 8,
- ph: 16,
- k: 138,
- na: 2,
- zn: 0.06,
- cu: 0.037,
- fl: null,
- mn: 0.03,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 53,
- thiamin: 0.04,
- riboflavin: 0.02,
- niacin: 0.1,
- pantothenic: null,
- vitb6: 0.08,
- folate: 11,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LEMON',
- },
- 102: {
- crop_id: 102,
- crop_common_name: 'Clementine',
- crop_genus: 'Citrus',
- crop_specie: 'reticulata ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 23,
- refuse: null,
- protein: 0.85,
- lipid: 0.15,
- energy: 47,
- ca: 30,
- fe: 0.14,
- mg: 10,
- ph: 21,
- k: 177,
- na: 1,
- zn: 0.06,
- cu: 0.043,
- fl: null,
- mn: 0.023,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: 48.8,
- thiamin: 0.086,
- riboflavin: 0.03,
- niacin: 0.636,
- pantothenic: null,
- vitb6: 0.075,
- folate: 24,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CLEMENTINE',
- },
- 103: {
- crop_id: 103,
- crop_common_name: 'Orange',
- crop_genus: 'Citrus',
- crop_specie: 'sinensis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 27,
- refuse: null,
- protein: 0.94,
- lipid: 0.12,
- energy: 47,
- ca: 40,
- fe: 0.1,
- mg: 10,
- ph: 14,
- k: 181,
- na: 0,
- zn: 0.07,
- cu: 0.045,
- fl: null,
- mn: 0.025,
- se: null,
- vita_rae: 11,
- vite: null,
- vitc: 53.2,
- thiamin: 0.087,
- riboflavin: 0.04,
- niacin: 0.282,
- pantothenic: null,
- vitb6: 0.06,
- folate: 30,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ORANGE',
- },
- 104: {
- crop_id: 104,
- crop_common_name: 'Lime',
- crop_genus: 'Citrus',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Citrus fruits',
- max_rooting_depth: 1.5,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.3,
- mid_kc: 0.85,
- end_kc: 0.45,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 16,
- refuse: null,
- protein: 0.7,
- lipid: 0.2,
- energy: 30,
- ca: 33,
- fe: 0.6,
- mg: 6,
- ph: 18,
- k: 102,
- na: 2,
- zn: 0.11,
- cu: 0.065,
- fl: null,
- mn: 0.008,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 29.1,
- thiamin: 0.03,
- riboflavin: 0.02,
- niacin: 0.2,
- pantothenic: null,
- vitb6: 0.043,
- folate: 8,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LIME',
- },
- 105: {
- crop_id: 105,
- crop_common_name: 'Hazelnut (filbert)',
- crop_genus: 'Corylus',
- crop_specie: 'avellana ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 59,
- refuse: null,
- protein: 14.95,
- lipid: 60.75,
- energy: 628,
- ca: 114,
- fe: 4.7,
- mg: 163,
- ph: 290,
- k: 680,
- na: 0,
- zn: 2.45,
- cu: 1.725,
- fl: null,
- mn: 6.175,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 6.3,
- thiamin: 0.643,
- riboflavin: 0.113,
- niacin: 1.8,
- pantothenic: null,
- vitb6: 0.563,
- folate: 113,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'HAZELNUT_FILBERT',
- },
- 106: {
- crop_id: 106,
- crop_common_name: 'Quince',
- crop_genus: 'Cydonia',
- crop_specie: 'oblonga ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.2375,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.55,
- mid_kc: 0.7625,
- end_kc: 0.58885,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 39,
- refuse: null,
- protein: 0.4,
- lipid: 0.1,
- energy: 57,
- ca: 11,
- fe: 0.7,
- mg: 8,
- ph: 17,
- k: 197,
- na: 4,
- zn: 0.04,
- cu: 0.13,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 15,
- thiamin: 0.02,
- riboflavin: 0.03,
- niacin: 0.2,
- pantothenic: null,
- vitb6: 0.04,
- folate: 3,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'QUINCE',
- },
- 107: {
- crop_id: 107,
- crop_common_name: 'Persimmon (kaki)',
- crop_genus: 'Diospyros',
- crop_specie: 'kaki ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 16,
- refuse: null,
- protein: 0.58,
- lipid: 0.19,
- energy: 70,
- ca: 8,
- fe: 0.15,
- mg: 9,
- ph: 17,
- k: 161,
- na: 1,
- zn: 0.11,
- cu: 0.113,
- fl: null,
- mn: 0.355,
- se: null,
- vita_rae: 81,
- vite: null,
- vitc: 7.5,
- thiamin: 0.03,
- riboflavin: 0.02,
- niacin: 0.1,
- pantothenic: null,
- vitb6: 0.1,
- folate: 8,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PERSIMMON_KAKI',
- },
- 108: {
- crop_id: 108,
- crop_common_name: 'Persimmon',
- crop_genus: 'Diospyros',
- crop_specie: 'virginiana ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 16,
- refuse: null,
- protein: 0.58,
- lipid: 0.19,
- energy: 70,
- ca: 8,
- fe: 0.15,
- mg: 9,
- ph: 17,
- k: 161,
- na: 1,
- zn: 0.11,
- cu: 0.113,
- fl: null,
- mn: 0.355,
- se: null,
- vita_rae: 81,
- vite: null,
- vitc: 7.5,
- thiamin: 0.03,
- riboflavin: 0.02,
- niacin: 0.1,
- pantothenic: null,
- vitb6: 0.1,
- folate: 8,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PERSIMMON',
- },
- 109: {
- crop_id: 109,
- crop_common_name: 'Fig',
- crop_genus: 'Ficus',
- crop_specie: 'carica ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 1,
- refuse: null,
- protein: 0.75,
- lipid: 0.3,
- energy: 74,
- ca: 35,
- fe: 0.37,
- mg: 17,
- ph: 14,
- k: 232,
- na: 1,
- zn: 0.15,
- cu: 0.07,
- fl: null,
- mn: 0.128,
- se: null,
- vita_rae: 7,
- vite: null,
- vitc: 2,
- thiamin: 0.06,
- riboflavin: 0.05,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.113,
- folate: 6,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'FIG',
- },
- 110: {
- crop_id: 110,
- crop_common_name: 'Litchi',
- crop_genus: 'Litchi',
- crop_specie: 'chinensis ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 40,
- refuse: null,
- protein: 0.83,
- lipid: 0.44,
- energy: 66,
- ca: 5,
- fe: 0.31,
- mg: 10,
- ph: 31,
- k: 171,
- na: 1,
- zn: 0.07,
- cu: 0.148,
- fl: null,
- mn: 0.055,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 71.5,
- thiamin: 0.011,
- riboflavin: 0.065,
- niacin: 0.603,
- pantothenic: null,
- vitb6: 0.1,
- folate: 14,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LITCHI',
- },
- 111: {
- crop_id: 111,
- crop_common_name: 'Macadamia nut',
- crop_genus: 'Macadamia',
- crop_specie: 'spp. ternifolia ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Nuts',
- max_rooting_depth: 1.6,
- depletion_fraction: 0.433333,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03333,
- end_kc: 0.584533,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 69,
- refuse: null,
- protein: 7.91,
- lipid: 75.77,
- energy: 718,
- ca: 85,
- fe: 3.69,
- mg: 130,
- ph: 188,
- k: 368,
- na: 5,
- zn: 1.3,
- cu: 0.756,
- fl: null,
- mn: 4.131,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 1.2,
- thiamin: 1.195,
- riboflavin: 0.162,
- niacin: 2.473,
- pantothenic: null,
- vitb6: 0.275,
- folate: 11,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MACADAMIA_NUT',
- },
- 112: {
- crop_id: 112,
- crop_common_name: 'Mango',
- crop_genus: 'Mangifera',
- crop_specie: 'indica ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 29,
- refuse: null,
- protein: 0.82,
- lipid: 0.38,
- energy: 60,
- ca: 11,
- fe: 0.16,
- mg: 10,
- ph: 14,
- k: 168,
- na: 1,
- zn: 0.09,
- cu: 0.111,
- fl: null,
- mn: 0.063,
- se: null,
- vita_rae: 54,
- vite: null,
- vitc: 36.4,
- thiamin: 0.028,
- riboflavin: 0.038,
- niacin: 0.669,
- pantothenic: null,
- vitb6: 0.119,
- folate: 43,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MANGO',
- },
- 113: {
- crop_id: 113,
- crop_common_name: 'Mulberry (all varieties)',
- crop_genus: 'Morus',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Other fruits',
- max_rooting_depth: 1.17188,
- depletion_fraction: 0.45,
- is_avg_depth: true,
- initial_kc: 0.509375,
- mid_kc: 0.865625,
- end_kc: 0.653687,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 1.44,
- lipid: 0.39,
- energy: 43,
- ca: 39,
- fe: 1.85,
- mg: 18,
- ph: 38,
- k: 194,
- na: 10,
- zn: 0.12,
- cu: 0.06,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 36.4,
- thiamin: 0.029,
- riboflavin: 0.101,
- niacin: 0.62,
- pantothenic: null,
- vitb6: 0.05,
- folate: 6,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MULBERRY_ALL_VARIETIES',
- },
- 114: {
- crop_id: 114,
- crop_common_name: 'Plum',
- crop_genus: 'Prunus',
- crop_specie: 'domestica ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.2375,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.55,
- mid_kc: 0.7625,
- end_kc: 0.58885,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 6,
- refuse: null,
- protein: 0.7,
- lipid: 0.28,
- energy: 46,
- ca: 6,
- fe: 0.17,
- mg: 7,
- ph: 16,
- k: 157,
- na: 0,
- zn: 0.1,
- cu: 0.057,
- fl: null,
- mn: 0.052,
- se: null,
- vita_rae: 17,
- vite: null,
- vitc: 9.5,
- thiamin: 0.028,
- riboflavin: 0.026,
- niacin: 0.417,
- pantothenic: null,
- vitb6: 0.029,
- folate: 5,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PLUM',
- },
- 115: {
- crop_id: 115,
- crop_common_name: 'Nectarine',
- crop_genus: 'Prunus',
- crop_specie: 'persica var. nectarina ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.2375,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.55,
- mid_kc: 0.7625,
- end_kc: 0.58885,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 9,
- refuse: null,
- protein: 1.06,
- lipid: 0.32,
- energy: 44,
- ca: 6,
- fe: 0.28,
- mg: 9,
- ph: 26,
- k: 201,
- na: 0,
- zn: 0.17,
- cu: 0.086,
- fl: null,
- mn: 0.054,
- se: null,
- vita_rae: 17,
- vite: null,
- vitc: 5.4,
- thiamin: 0.034,
- riboflavin: 0.027,
- niacin: 1.125,
- pantothenic: null,
- vitb6: 0.025,
- folate: 5,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'NECTARINE',
- },
- 116: {
- crop_id: 116,
- crop_common_name: 'Cherry (all varieties)',
- crop_genus: 'Prunus',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Pome fruits and stone fruits',
- max_rooting_depth: 1.2375,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.55,
- mid_kc: 0.7625,
- end_kc: 0.58885,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 10,
- refuse: null,
- protein: 1,
- lipid: 0.3,
- energy: 50,
- ca: 16,
- fe: 0.32,
- mg: 9,
- ph: 15,
- k: 173,
- na: 3,
- zn: 0.1,
- cu: 0.104,
- fl: null,
- mn: 0.112,
- se: null,
- vita_rae: 64,
- vite: null,
- vitc: 10,
- thiamin: 0.03,
- riboflavin: 0.04,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.044,
- folate: 8,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CHERRY_ALL_VARIETIES',
- },
- 117: {
- crop_id: 117,
- crop_common_name: 'Guava',
- crop_genus: 'Psidium',
- crop_specie: 'guajava ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Tropical and subtropical fruits',
- max_rooting_depth: 0.97,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.62,
- mid_kc: 0.85,
- end_kc: 0.78,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 22,
- refuse: null,
- protein: 2.55,
- lipid: 0.95,
- energy: 68,
- ca: 18,
- fe: 0.26,
- mg: 22,
- ph: 40,
- k: 417,
- na: 2,
- zn: 0.23,
- cu: 0.23,
- fl: null,
- mn: 0.15,
- se: null,
- vita_rae: 31,
- vite: null,
- vitc: 228.3,
- thiamin: 0.067,
- riboflavin: 0.04,
- niacin: 1.084,
- pantothenic: null,
- vitb6: 0.11,
- folate: 49,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GUAVA',
- },
- 118: {
- crop_id: 118,
- crop_common_name: 'Pomegranate',
- crop_genus: 'Punica',
- crop_specie: 'granatum ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Other fruits',
- max_rooting_depth: 1.17188,
- depletion_fraction: 0.45,
- is_avg_depth: true,
- initial_kc: 0.509375,
- mid_kc: 0.865625,
- end_kc: 0.653687,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 44,
- refuse: null,
- protein: 1.67,
- lipid: 1.17,
- energy: 83,
- ca: 10,
- fe: 0.3,
- mg: 12,
- ph: 36,
- k: 236,
- na: 3,
- zn: 0.35,
- cu: 0.158,
- fl: null,
- mn: 0.119,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 10.2,
- thiamin: 0.067,
- riboflavin: 0.053,
- niacin: 0.293,
- pantothenic: null,
- vitb6: 0.075,
- folate: 38,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'POMEGRANATE',
- },
- 119: {
- crop_id: 119,
- crop_common_name: 'Currants (all varieties)',
- crop_genus: 'Ribes',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 2,
- refuse: null,
- protein: 1.4,
- lipid: 0.41,
- energy: 63,
- ca: 55,
- fe: 1.54,
- mg: 24,
- ph: 59,
- k: 322,
- na: 2,
- zn: 0.27,
- cu: 0.086,
- fl: null,
- mn: 0.256,
- se: null,
- vita_rae: 12,
- vite: null,
- vitc: 181,
- thiamin: 0.05,
- riboflavin: 0.05,
- niacin: 0.3,
- pantothenic: null,
- vitb6: 0.066,
- folate: null,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CURRANTS_ALL_VARIETIES',
- },
- 120: {
- crop_id: 120,
- crop_common_name: 'Gooseberry (all varieties)',
- crop_genus: 'Ribes',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0.88,
- lipid: 0.58,
- energy: 44,
- ca: 25,
- fe: 0.31,
- mg: 10,
- ph: 27,
- k: 198,
- na: 1,
- zn: 0.12,
- cu: 0.07,
- fl: null,
- mn: 0.144,
- se: null,
- vita_rae: 15,
- vite: null,
- vitc: 27.7,
- thiamin: 0.04,
- riboflavin: 0.03,
- niacin: 0.3,
- pantothenic: null,
- vitb6: 0.08,
- folate: 6,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GOOSEBERRY_ALL_VARIETIES',
- },
- 121: {
- crop_id: 121,
- crop_common_name: 'Blackberries ',
- crop_genus: 'Rubus',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: false,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 4,
- refuse: null,
- protein: 1.39,
- lipid: 0.49,
- energy: 43,
- ca: 29,
- fe: 0.62,
- mg: 20,
- ph: 22,
- k: 162,
- na: 1,
- zn: 0.53,
- cu: 0.165,
- fl: null,
- mn: 0.646,
- se: null,
- vita_rae: 11,
- vite: null,
- vitc: 21,
- thiamin: 0.02,
- riboflavin: 0.026,
- niacin: 0.646,
- pantothenic: null,
- vitb6: 0.03,
- folate: 25,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BLACKBERRIES_',
- },
- 122: {
- crop_id: 122,
- crop_common_name: 'Raspberry (all varieties)',
- crop_genus: 'Rubus',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 4,
- refuse: null,
- protein: 1.2,
- lipid: 0.65,
- energy: 52,
- ca: 25,
- fe: 0.69,
- mg: 22,
- ph: 29,
- k: 151,
- na: 1,
- zn: 0.42,
- cu: 0.09,
- fl: null,
- mn: 0.67,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 26.2,
- thiamin: 0.032,
- riboflavin: 0.038,
- niacin: 0.598,
- pantothenic: null,
- vitb6: 0.055,
- folate: 21,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RASPBERRY_ALL_VARIETIES',
- },
- 123: {
- crop_id: 123,
- crop_common_name: 'Blueberry',
- crop_genus: 'Vaccinium',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 5,
- refuse: null,
- protein: 0.74,
- lipid: 0.33,
- energy: 57,
- ca: 6,
- fe: 0.28,
- mg: 6,
- ph: 12,
- k: 77,
- na: 1,
- zn: 0.16,
- cu: 0.057,
- fl: null,
- mn: 0.336,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 9.7,
- thiamin: 0.037,
- riboflavin: 0.041,
- niacin: 0.418,
- pantothenic: null,
- vitb6: 0.052,
- folate: 6,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BLUEBERRY',
- },
- 124: {
- crop_id: 124,
- crop_common_name: 'Cranberry',
- crop_genus: 'Vaccinium',
- crop_specie: 'spp. ',
- crop_group: 'Fruit and nuts',
- crop_subgroup: 'Berries',
- max_rooting_depth: 0.575,
- depletion_fraction: 0.35,
- is_avg_depth: true,
- initial_kc: 0.475,
- mid_kc: 0.875,
- end_kc: 0.775,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 2,
- refuse: null,
- protein: 0.39,
- lipid: 0.13,
- energy: 46,
- ca: 8,
- fe: 0.25,
- mg: 6,
- ph: 13,
- k: 85,
- na: 2,
- zn: 0.1,
- cu: 0.061,
- fl: null,
- mn: 0.36,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 13.3,
- thiamin: 0.012,
- riboflavin: 0.02,
- niacin: 0.101,
- pantothenic: null,
- vitb6: 0.057,
- folate: 1,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CRANBERRY',
- },
- 125: {
- crop_id: 125,
- crop_common_name: 'Pigeon pea',
- crop_genus: 'Cajanus',
- crop_specie: 'cajan ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 21.7,
- lipid: 1.49,
- energy: 343,
- ca: 130,
- fe: 5.23,
- mg: 183,
- ph: 367,
- k: 1392,
- na: 17,
- zn: 2.76,
- cu: 1.057,
- fl: null,
- mn: 1.791,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 0,
- thiamin: 0.643,
- riboflavin: 0.187,
- niacin: 2.965,
- pantothenic: null,
- vitb6: 0.283,
- folate: 456,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 60,
- crop_translation_key: 'PIGEON_PEA',
- },
- 126: {
- crop_id: 126,
- crop_common_name: 'Pea',
- crop_genus: 'Pisum',
- crop_specie: 'sativum ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 23.82,
- lipid: 1.16,
- energy: 352,
- ca: 37,
- fe: 4.82,
- mg: 49,
- ph: 321,
- k: 823,
- na: 15,
- zn: 3.55,
- cu: 0.815,
- fl: null,
- mn: 1.22,
- se: null,
- vita_rae: 7,
- vite: null,
- vitc: 1.8,
- thiamin: 0.726,
- riboflavin: 0.215,
- niacin: 2.889,
- pantothenic: null,
- vitb6: 0.174,
- folate: 274,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 60,
- crop_translation_key: 'PEA',
- },
- 127: {
- crop_id: 127,
- crop_common_name: 'Fenugreek',
- crop_genus: 'Trigonella',
- crop_specie: 'foenum-graecum ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 23,
- lipid: 6.41,
- energy: 323,
- ca: 176,
- fe: 33.53,
- mg: 191,
- ph: 296,
- k: 770,
- na: 67,
- zn: 2.5,
- cu: 1.11,
- fl: null,
- mn: 1.228,
- se: null,
- vita_rae: 3,
- vite: null,
- vitc: 3,
- thiamin: 0.322,
- riboflavin: 0.366,
- niacin: 1.64,
- pantothenic: null,
- vitb6: 0.6,
- folate: 57,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 40,
- crop_translation_key: 'FENUGREEK',
- },
- 128: {
- crop_id: 128,
- crop_common_name: 'Broad bean',
- crop_genus: 'Vicia',
- crop_specie: 'faba ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 23.58,
- lipid: 0.83,
- energy: 333,
- ca: 143,
- fe: 8.2,
- mg: 140,
- ph: 407,
- k: 1406,
- na: 24,
- zn: 2.79,
- cu: 0.958,
- fl: null,
- mn: 1.021,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 4.5,
- thiamin: 0.529,
- riboflavin: 0.219,
- niacin: 2.06,
- pantothenic: null,
- vitb6: 0.397,
- folate: 394,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 100,
- crop_translation_key: 'BROAD_BEAN',
- },
- 129: {
- crop_id: 129,
- crop_common_name: 'Beans',
- crop_genus: 'Vig',
- crop_specie: 'spp. ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 23.58,
- lipid: 0.83,
- energy: 333,
- ca: 143,
- fe: 8.2,
- mg: 140,
- ph: 407,
- k: 1406,
- na: 24,
- zn: 2.79,
- cu: 0.958,
- fl: null,
- mn: 1.021,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 4.5,
- thiamin: 0.529,
- riboflavin: 0.219,
- niacin: 2.06,
- pantothenic: null,
- vitb6: 0.397,
- folate: 394,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 40,
- crop_translation_key: 'BEANS',
- },
- 130: {
- crop_id: 130,
- crop_common_name: 'Cowpea',
- crop_genus: 'Vig',
- crop_specie: 'unguiculata ',
- crop_group: 'Leguminous crops',
- crop_subgroup: 'Legumes',
- max_rooting_depth: 0.75,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.05,
- end_kc: 0.325,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 23.85,
- lipid: 2.07,
- energy: 343,
- ca: 85,
- fe: 9.95,
- mg: 333,
- ph: 438,
- k: 1375,
- na: 58,
- zn: 6.11,
- cu: 1.059,
- fl: null,
- mn: 1.544,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 1.5,
- thiamin: 0.68,
- riboflavin: 0.17,
- niacin: 2.795,
- pantothenic: null,
- vitb6: 0.361,
- folate: 639,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 60,
- crop_translation_key: 'COWPEA',
- },
- 131: {
- crop_id: 131,
- crop_common_name: 'Rapeseed (colza)',
- crop_genus: 'Brassica',
- crop_specie: 'napus ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.19,
- depletion_fraction: 0.56,
- is_avg_depth: true,
- initial_kc: 0.37,
- mid_kc: 1.14,
- end_kc: 0.37,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0,
- lipid: 100,
- energy: 884,
- ca: 0,
- fe: 0,
- mg: 0,
- ph: 0,
- k: 0,
- na: 0,
- zn: 0,
- cu: 0,
- fl: null,
- mn: 0,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0,
- riboflavin: 0,
- niacin: 0,
- pantothenic: null,
- vitb6: 0,
- folate: 0,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RAPESEED_COLZA',
- },
- 132: {
- crop_id: 132,
- crop_common_name: 'Mustard',
- crop_genus: 'Brassica',
- crop_specie: 'nigra ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.19,
- depletion_fraction: 0.56,
- is_avg_depth: true,
- initial_kc: 0.37,
- mid_kc: 1.14,
- end_kc: 0.37,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 7,
- refuse: null,
- protein: 2.86,
- lipid: 0.42,
- energy: 27,
- ca: 115,
- fe: 1.64,
- mg: 32,
- ph: 58,
- k: 384,
- na: 20,
- zn: 0.25,
- cu: 0.165,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 151,
- vite: null,
- vitc: 70,
- thiamin: 0.08,
- riboflavin: 0.11,
- niacin: 0.8,
- pantothenic: null,
- vitb6: 0.18,
- folate: 12,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MUSTARD',
- },
- 133: {
- crop_id: 133,
- crop_common_name: 'Coconut',
- crop_genus: 'Cocos',
- crop_specie: 'nucifera ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Permanent oilseed crops',
- max_rooting_depth: 1.45,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.65,
- mid_kc: 0.7,
- end_kc: 0.7,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 48,
- refuse: null,
- protein: 3.33,
- lipid: 33.49,
- energy: 354,
- ca: 14,
- fe: 2.43,
- mg: 32,
- ph: 113,
- k: 356,
- na: 20,
- zn: 1.1,
- cu: 0.435,
- fl: null,
- mn: 1.5,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 3.3,
- thiamin: 0.066,
- riboflavin: 0.02,
- niacin: 0.54,
- pantothenic: null,
- vitb6: 0.054,
- folate: 26,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'COCONUT',
- },
- 134: {
- crop_id: 134,
- crop_common_name: 'Oil palm',
- crop_genus: 'Elaeis',
- crop_specie: 'guineensis ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Permanent oilseed crops',
- max_rooting_depth: 1.45,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.65,
- mid_kc: 0.7,
- end_kc: 0.7,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0,
- lipid: 100,
- energy: 884,
- ca: 0,
- fe: 0.01,
- mg: 0,
- ph: 0,
- k: 0,
- na: 0,
- zn: 0,
- cu: 0,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0,
- riboflavin: 0,
- niacin: 0,
- pantothenic: null,
- vitb6: 0,
- folate: 0,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'OIL_PALM',
- },
- 135: {
- crop_id: 135,
- crop_common_name: 'Palm oil',
- crop_genus: 'Elaeis',
- crop_specie: 'guineensis ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Permanent oilseed crops',
- max_rooting_depth: 1.45,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.65,
- mid_kc: 0.7,
- end_kc: 0.7,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 0,
- lipid: 100,
- energy: 884,
- ca: 0,
- fe: 0.01,
- mg: 0,
- ph: 0,
- k: 0,
- na: 0,
- zn: 0,
- cu: 0,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 0,
- thiamin: 0,
- riboflavin: 0,
- niacin: 0,
- pantothenic: null,
- vitb6: 0,
- folate: 0,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PALM_OIL',
- },
- 136: {
- crop_id: 136,
- crop_common_name: 'Poppy seed',
- crop_genus: 'Papaver',
- crop_specie: 'somniferum ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.19,
- depletion_fraction: 0.56,
- is_avg_depth: true,
- initial_kc: 0.37,
- mid_kc: 1.14,
- end_kc: 0.37,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 0,
- refuse: null,
- protein: 17.99,
- lipid: 41.56,
- energy: 525,
- ca: 1438,
- fe: 9.76,
- mg: 347,
- ph: 870,
- k: 719,
- na: 26,
- zn: 7.9,
- cu: 1.627,
- fl: null,
- mn: 6.707,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 1,
- thiamin: 0.854,
- riboflavin: 0.1,
- niacin: 0.896,
- pantothenic: null,
- vitb6: 0.247,
- folate: 82,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'POPPY_SEED',
- },
- 137: {
- crop_id: 137,
- crop_common_name: 'Mustard',
- crop_genus: 'Sinapis',
- crop_specie: 'alba ',
- crop_group: 'Oilseed crops',
- crop_subgroup: 'Temporary oilseed crops',
- max_rooting_depth: 1.19,
- depletion_fraction: 0.56,
- is_avg_depth: true,
- initial_kc: 0.37,
- mid_kc: 1.14,
- end_kc: 0.37,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 7,
- refuse: null,
- protein: 2.86,
- lipid: 0.42,
- energy: 27,
- ca: 115,
- fe: 1.64,
- mg: 32,
- ph: 58,
- k: 384,
- na: 20,
- zn: 0.25,
- cu: 0.165,
- fl: null,
- mn: null,
- se: null,
- vita_rae: 151,
- vite: null,
- vitc: 70,
- thiamin: 0.08,
- riboflavin: 0.11,
- niacin: 0.8,
- pantothenic: null,
- vitb6: 0.18,
- folate: 12,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MUSTARD',
- },
- 138: {
- crop_id: 138,
- crop_common_name: 'Hemp ',
- crop_genus: 'Cannabis',
- crop_specie: 'sativa ssp. indica ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 1.11667,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.35,
- mid_kc: 0.95,
- end_kc: 0.483333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'HEMP_',
- },
- 139: {
- crop_id: 139,
- crop_common_name: 'Jute',
- crop_genus: 'Corchorus',
- crop_specie: 'spp. ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 1.11667,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.35,
- mid_kc: 0.95,
- end_kc: 0.483333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 38,
- refuse: null,
- protein: 4.65,
- lipid: 0.25,
- energy: 34,
- ca: 208,
- fe: 4.76,
- mg: 64,
- ph: 83,
- k: 559,
- na: 8,
- zn: 0.79,
- cu: 0.255,
- fl: null,
- mn: 0.123,
- se: null,
- vita_rae: 278,
- vite: null,
- vitc: 37,
- thiamin: 0.133,
- riboflavin: 0.546,
- niacin: 1.26,
- pantothenic: null,
- vitb6: 0.6,
- folate: 123,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'JUTE',
- },
- 140: {
- crop_id: 140,
- crop_common_name: 'Lemon grass',
- crop_genus: 'Cymbopogon',
- crop_specie: 'citratus ',
- crop_group: 'Other crops',
- crop_subgroup: 'Fibre crops',
- max_rooting_depth: 1.11667,
- depletion_fraction: 0.65,
- is_avg_depth: true,
- initial_kc: 0.35,
- mid_kc: 0.95,
- end_kc: 0.483333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 35,
- refuse: null,
- protein: 1.82,
- lipid: 0.49,
- energy: 99,
- ca: 65,
- fe: 8.17,
- mg: 60,
- ph: 101,
- k: 723,
- na: 6,
- zn: 2.23,
- cu: 0.266,
- fl: null,
- mn: 5.224,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 2.6,
- thiamin: 0.065,
- riboflavin: 0.135,
- niacin: 1.101,
- pantothenic: null,
- vitb6: 0.08,
- folate: 75,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LEMON_GRASS',
- },
- 141: {
- crop_id: 141,
- crop_common_name: 'Ryegrass ',
- crop_genus: 'Lolium',
- crop_specie: 'spp. ',
- crop_group: 'Other crops',
- crop_subgroup: 'Other crops',
- max_rooting_depth: 1.32,
- depletion_fraction: 0.58,
- is_avg_depth: true,
- initial_kc: 0.52,
- mid_kc: 0.94,
- end_kc: 0.66,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RYEGRASS_',
- },
- 142: {
- crop_id: 142,
- crop_common_name: 'Alfalfa for fodder',
- crop_genus: 'Medicago',
- crop_specie: 'sativa ',
- crop_group: 'Other crops',
- crop_subgroup: 'Grasses and other fodder crops',
- max_rooting_depth: 2,
- depletion_fraction: 0.55,
- is_avg_depth: true,
- initial_kc: 0.6,
- mid_kc: 0.85,
- end_kc: 0.85,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 200,
- crop_translation_key: 'ALFALFA_FOR_FODDER',
- },
- 143: {
- crop_id: 143,
- crop_common_name: 'Tobacco',
- crop_genus: 'Nicotia',
- crop_specie: 'tabacum ',
- crop_group: 'Other crops',
- crop_subgroup: 'Tobacco',
- max_rooting_depth: 1.32,
- depletion_fraction: 0.58,
- is_avg_depth: true,
- initial_kc: 0.52,
- mid_kc: 0.94,
- end_kc: 0.66,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TOBACCO',
- },
- 144: {
- crop_id: 144,
- crop_common_name: 'Clover',
- crop_genus: 'Trifolium',
- crop_specie: 'spp. ',
- crop_group: 'Other crops',
- crop_subgroup: 'Grasses and other fodder crops',
- max_rooting_depth: 2,
- depletion_fraction: 0.55,
- is_avg_depth: true,
- initial_kc: 0.6,
- mid_kc: 0.85,
- end_kc: 0.85,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: null,
- refuse: null,
- protein: null,
- lipid: null,
- energy: null,
- ca: null,
- fe: null,
- mg: null,
- ph: null,
- k: null,
- na: null,
- zn: null,
- cu: null,
- fl: null,
- mn: null,
- se: null,
- vita_rae: null,
- vite: null,
- vitc: null,
- thiamin: null,
- riboflavin: null,
- niacin: null,
- pantothenic: null,
- vitb6: null,
- folate: null,
- vitb12: null,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: 150,
- crop_translation_key: 'CLOVER',
- },
- 145: {
- crop_id: 145,
- crop_common_name: 'Taro',
- crop_genus: 'Colocasia',
- crop_specie: 'esculenta ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.583333,
- depletion_fraction: 0.36,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03433,
- end_kc: 0.602667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 14,
- refuse: null,
- protein: 1.5,
- lipid: 0.2,
- energy: 112,
- ca: 43,
- fe: 0.55,
- mg: 33,
- ph: 84,
- k: 591,
- na: 11,
- zn: 0.23,
- cu: 0.172,
- fl: null,
- mn: 0.383,
- se: null,
- vita_rae: 4,
- vite: null,
- vitc: 4.5,
- thiamin: 0.095,
- riboflavin: 0.025,
- niacin: 0.6,
- pantothenic: null,
- vitb6: 0.283,
- folate: 22,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TARO',
- },
- 146: {
- crop_id: 146,
- crop_common_name: 'Yam',
- crop_genus: 'Dioscorea',
- crop_specie: 'spp. ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.583333,
- depletion_fraction: 0.36,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03433,
- end_kc: 0.602667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 14,
- refuse: null,
- protein: 1.53,
- lipid: 0.17,
- energy: 118,
- ca: 17,
- fe: 0.54,
- mg: 21,
- ph: 55,
- k: 816,
- na: 9,
- zn: 0.24,
- cu: 0.178,
- fl: null,
- mn: 0.397,
- se: null,
- vita_rae: 7,
- vite: null,
- vitc: 17.1,
- thiamin: 0.112,
- riboflavin: 0.032,
- niacin: 0.552,
- pantothenic: null,
- vitb6: 0.293,
- folate: 23,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'YAM',
- },
- 147: {
- crop_id: 147,
- crop_common_name: 'Arrowroot',
- crop_genus: 'Maranta',
- crop_specie: 'arundinacea ',
- crop_group: 'Potatoes and yams',
- crop_subgroup: 'High starch Root/tuber crops',
- max_rooting_depth: 0.583333,
- depletion_fraction: 0.36,
- is_avg_depth: true,
- initial_kc: 0.433333,
- mid_kc: 1.03433,
- end_kc: 0.602667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 15,
- refuse: null,
- protein: 4.24,
- lipid: 0.2,
- energy: 65,
- ca: 6,
- fe: 2.22,
- mg: 25,
- ph: 98,
- k: 454,
- na: 26,
- zn: 0.63,
- cu: 0.121,
- fl: null,
- mn: 0.174,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 1.9,
- thiamin: 0.143,
- riboflavin: 0.059,
- niacin: 1.693,
- pantothenic: null,
- vitb6: 0.266,
- folate: 338,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ARROWROOT',
- },
- 148: {
- crop_id: 148,
- crop_common_name: 'Beet',
- crop_genus: 'Beta',
- crop_specie: 'vulgaris ',
- crop_group: 'Sugar crops',
- crop_subgroup: 'Sugar crops (root)',
- max_rooting_depth: 0.8,
- depletion_fraction: 0.5,
- is_avg_depth: true,
- initial_kc: 0.4,
- mid_kc: 1.25,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 33,
- refuse: null,
- protein: 1.61,
- lipid: 0.17,
- energy: 43,
- ca: 16,
- fe: 0.8,
- mg: 23,
- ph: 40,
- k: 325,
- na: 78,
- zn: 0.35,
- cu: 0.075,
- fl: null,
- mn: 0.329,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 4.9,
- thiamin: 0.031,
- riboflavin: 0.04,
- niacin: 0.334,
- pantothenic: null,
- vitb6: 0.067,
- folate: 109,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'BEET',
- },
- 149: {
- crop_id: 149,
- crop_common_name: 'Okra',
- crop_genus: 'Abelmoschus',
- crop_specie: 'esculentus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 14,
- refuse: null,
- protein: 1.93,
- lipid: 0.19,
- energy: 33,
- ca: 82,
- fe: 0.62,
- mg: 57,
- ph: 61,
- k: 299,
- na: 7,
- zn: 0.58,
- cu: 0.109,
- fl: null,
- mn: 0.788,
- se: null,
- vita_rae: 36,
- vite: null,
- vitc: 23,
- thiamin: 0.2,
- riboflavin: 0.06,
- niacin: 1,
- pantothenic: null,
- vitb6: 0.215,
- folate: 60,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'OKRA',
- },
- 150: {
- crop_id: 150,
- crop_common_name: 'Mushrooms',
- crop_genus: 'Agaricus',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Mushrooms and truffles',
- max_rooting_depth: 0.720455,
- depletion_fraction: 0.375,
- is_avg_depth: true,
- initial_kc: 0.643182,
- mid_kc: 1.01632,
- end_kc: 0.854545,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 3,
- refuse: null,
- protein: 3.09,
- lipid: 0.34,
- energy: 22,
- ca: 3,
- fe: 0.5,
- mg: 9,
- ph: 86,
- k: 318,
- na: 5,
- zn: 0.52,
- cu: 0.318,
- fl: null,
- mn: 0.047,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 2.1,
- thiamin: 0.081,
- riboflavin: 0.402,
- niacin: 3.607,
- pantothenic: null,
- vitb6: 0.104,
- folate: 17,
- vitb12: 0.04,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MUSHROOMS',
- },
- 151: {
- crop_id: 151,
- crop_common_name: 'Leek',
- crop_genus: 'Allium',
- crop_specie: 'porrum ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.525,
- depletion_fraction: 0.308333,
- is_avg_depth: true,
- initial_kc: 0.725,
- mid_kc: 1.01667,
- end_kc: 0.866667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 56,
- refuse: null,
- protein: 1.5,
- lipid: 0.3,
- energy: 61,
- ca: 59,
- fe: 2.1,
- mg: 28,
- ph: 35,
- k: 180,
- na: 20,
- zn: 0.12,
- cu: 0.12,
- fl: null,
- mn: 0.481,
- se: null,
- vita_rae: 83,
- vite: null,
- vitc: 12,
- thiamin: 0.06,
- riboflavin: 0.03,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.233,
- folate: 64,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'LEEK',
- },
- 152: {
- crop_id: 152,
- crop_common_name: 'Rutabaga (swede)',
- crop_genus: 'Brassica',
- crop_specie: 'napus var. napobrassica ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.525,
- depletion_fraction: 0.308333,
- is_avg_depth: true,
- initial_kc: 0.725,
- mid_kc: 1.01667,
- end_kc: 0.866667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 15,
- refuse: null,
- protein: 1.08,
- lipid: 0.16,
- energy: 37,
- ca: 43,
- fe: 0.44,
- mg: 20,
- ph: 53,
- k: 305,
- na: 12,
- zn: 0.24,
- cu: 0.032,
- fl: null,
- mn: 0.131,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 25,
- thiamin: 0.09,
- riboflavin: 0.04,
- niacin: 0.7,
- pantothenic: null,
- vitb6: 0.1,
- folate: 21,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RUTABAGA_SWEDE',
- },
- 153: {
- crop_id: 153,
- crop_common_name: 'Kale',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea var. acephala ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 28,
- refuse: null,
- protein: 4.28,
- lipid: 0.93,
- energy: 49,
- ca: 150,
- fe: 1.47,
- mg: 47,
- ph: 92,
- k: 491,
- na: 38,
- zn: 0.56,
- cu: 1.499,
- fl: null,
- mn: 0.659,
- se: null,
- vita_rae: 500,
- vite: null,
- vitc: 120,
- thiamin: 0.11,
- riboflavin: 0.13,
- niacin: 1,
- pantothenic: null,
- vitb6: 0.271,
- folate: 141,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'KALE',
- },
- 154: {
- crop_id: 154,
- crop_common_name: 'Kohlrabi',
- crop_genus: 'Brassica',
- crop_specie: 'oleracea var. gongylodes ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.525,
- depletion_fraction: 0.308333,
- is_avg_depth: true,
- initial_kc: 0.725,
- mid_kc: 1.01667,
- end_kc: 0.866667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 54,
- refuse: null,
- protein: 1.7,
- lipid: 0.1,
- energy: 27,
- ca: 24,
- fe: 0.4,
- mg: 19,
- ph: 46,
- k: 350,
- na: 20,
- zn: 0.03,
- cu: 0.129,
- fl: null,
- mn: 0.139,
- se: null,
- vita_rae: 2,
- vite: null,
- vitc: 62,
- thiamin: 0.05,
- riboflavin: 0.02,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.15,
- folate: 16,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'KOHLRABI',
- },
- 155: {
- crop_id: 155,
- crop_common_name: 'Turnip',
- crop_genus: 'Brassica',
- crop_specie: 'rapa ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.525,
- depletion_fraction: 0.308333,
- is_avg_depth: true,
- initial_kc: 0.725,
- mid_kc: 1.01667,
- end_kc: 0.866667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 19,
- refuse: null,
- protein: 0.9,
- lipid: 0.1,
- energy: 28,
- ca: 30,
- fe: 0.3,
- mg: 11,
- ph: 27,
- k: 191,
- na: 67,
- zn: 0.27,
- cu: 0.085,
- fl: null,
- mn: 0.134,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 21,
- thiamin: 0.04,
- riboflavin: 0.03,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.09,
- folate: 15,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'TURNIP',
- },
- 156: {
- crop_id: 156,
- crop_common_name: 'Endive',
- crop_genus: 'Cichorium',
- crop_specie: 'endivia ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 14,
- refuse: null,
- protein: 1.25,
- lipid: 0.2,
- energy: 17,
- ca: 52,
- fe: 0.83,
- mg: 15,
- ph: 28,
- k: 314,
- na: 22,
- zn: 0.79,
- cu: 0.099,
- fl: null,
- mn: 0.42,
- se: null,
- vita_rae: 108,
- vite: null,
- vitc: 6.5,
- thiamin: 0.08,
- riboflavin: 0.075,
- niacin: 0.4,
- pantothenic: null,
- vitb6: 0.02,
- folate: 142,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'ENDIVE',
- },
- 157: {
- crop_id: 157,
- crop_common_name: 'Chicory',
- crop_genus: 'Cichorium',
- crop_specie: 'intybus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 11,
- refuse: null,
- protein: 0.9,
- lipid: 0.1,
- energy: 17,
- ca: 19,
- fe: 0.24,
- mg: 10,
- ph: 26,
- k: 211,
- na: 2,
- zn: 0.16,
- cu: 0.051,
- fl: null,
- mn: 0.1,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 2.8,
- thiamin: 0.062,
- riboflavin: 0.027,
- niacin: 0.16,
- pantothenic: null,
- vitb6: 0.042,
- folate: 37,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CHICORY',
- },
- 158: {
- crop_id: 158,
- crop_common_name: 'Melon ',
- crop_genus: 'Cucumis',
- crop_specie: 'melo ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: 0.4,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 49,
- refuse: null,
- protein: 0.84,
- lipid: 0.19,
- energy: 34,
- ca: 9,
- fe: 0.21,
- mg: 12,
- ph: 15,
- k: 267,
- na: 16,
- zn: 0.18,
- cu: 0.041,
- fl: null,
- mn: 0.041,
- se: null,
- vita_rae: 169,
- vite: null,
- vitc: 36.7,
- thiamin: 0.041,
- riboflavin: 0.019,
- niacin: 0.734,
- pantothenic: null,
- vitb6: 0.072,
- folate: 21,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'MELON_',
- },
- 159: {
- crop_id: 159,
- crop_common_name: 'Gourd (American)',
- crop_genus: 'Cucurbita',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 30,
- refuse: null,
- protein: 1,
- lipid: 0.1,
- energy: 26,
- ca: 21,
- fe: 0.8,
- mg: 12,
- ph: 44,
- k: 340,
- na: 1,
- zn: 0.32,
- cu: 0.127,
- fl: null,
- mn: 0.125,
- se: null,
- vita_rae: 426,
- vite: null,
- vitc: 9,
- thiamin: 0.05,
- riboflavin: 0.11,
- niacin: 0.6,
- pantothenic: null,
- vitb6: 0.061,
- folate: 16,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GOURD_AMERICAN',
- },
- 160: {
- crop_id: 160,
- crop_common_name: 'Pumpkin',
- crop_genus: 'Cucurbita',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 30,
- refuse: null,
- protein: 1,
- lipid: 0.1,
- energy: 26,
- ca: 21,
- fe: 0.8,
- mg: 12,
- ph: 44,
- k: 340,
- na: 1,
- zn: 0.32,
- cu: 0.127,
- fl: null,
- mn: 0.125,
- se: null,
- vita_rae: 426,
- vite: null,
- vitc: 9,
- thiamin: 0.05,
- riboflavin: 0.11,
- niacin: 0.6,
- pantothenic: null,
- vitb6: 0.061,
- folate: 16,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'PUMPKIN',
- },
- 161: {
- crop_id: 161,
- crop_common_name: 'Cardoon',
- crop_genus: 'Cynara',
- crop_specie: 'cardunculus ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 51,
- refuse: null,
- protein: 0.7,
- lipid: 0.1,
- energy: 17,
- ca: 70,
- fe: 0.7,
- mg: 42,
- ph: 23,
- k: 400,
- na: 170,
- zn: 0.17,
- cu: 0.231,
- fl: null,
- mn: 0.256,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 2,
- thiamin: 0.02,
- riboflavin: 0.03,
- niacin: 0.3,
- pantothenic: null,
- vitb6: 0.116,
- folate: 68,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CARDOON',
- },
- 162: {
- crop_id: 162,
- crop_common_name: 'Fennel',
- crop_genus: 'Foeniculum',
- crop_specie: 'vulgare ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 28,
- refuse: null,
- protein: 1.24,
- lipid: 0.2,
- energy: 31,
- ca: 49,
- fe: 0.73,
- mg: 17,
- ph: 50,
- k: 414,
- na: 52,
- zn: 0.2,
- cu: 0.066,
- fl: null,
- mn: 0.191,
- se: null,
- vita_rae: 48,
- vite: null,
- vitc: 12,
- thiamin: 0.01,
- riboflavin: 0.032,
- niacin: 0.64,
- pantothenic: null,
- vitb6: 0.047,
- folate: 27,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'FENNEL',
- },
- 163: {
- crop_id: 163,
- crop_common_name: 'Gourd (African)',
- crop_genus: 'Lagenaria',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 30,
- refuse: null,
- protein: 1,
- lipid: 0.1,
- energy: 26,
- ca: 21,
- fe: 0.8,
- mg: 12,
- ph: 44,
- k: 340,
- na: 1,
- zn: 0.32,
- cu: 0.127,
- fl: null,
- mn: 0.125,
- se: null,
- vita_rae: 426,
- vite: null,
- vitc: 9,
- thiamin: 0.05,
- riboflavin: 0.11,
- niacin: 0.6,
- pantothenic: null,
- vitb6: 0.061,
- folate: 16,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'GOURD_AFRICAN',
- },
- 164: {
- crop_id: 164,
- crop_common_name: 'Cress',
- crop_genus: 'Lepidium',
- crop_specie: 'sativum ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 29,
- refuse: null,
- protein: 2.6,
- lipid: 0.7,
- energy: 32,
- ca: 81,
- fe: 1.3,
- mg: 38,
- ph: 76,
- k: 606,
- na: 14,
- zn: 0.23,
- cu: 0.17,
- fl: null,
- mn: 0.553,
- se: null,
- vita_rae: 346,
- vite: null,
- vitc: 69,
- thiamin: 0.08,
- riboflavin: 0.26,
- niacin: 1,
- pantothenic: null,
- vitb6: 0.247,
- folate: 80,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'CRESS',
- },
- 165: {
- crop_id: 165,
- crop_common_name: 'Rhubarb',
- crop_genus: 'Rheum',
- crop_specie: 'spp. ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Leafy or stem vegetables',
- max_rooting_depth: 0.76,
- depletion_fraction: 0.393333,
- is_avg_depth: true,
- initial_kc: 0.683333,
- mid_kc: 1.02047,
- end_kc: 0.913333,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 25,
- refuse: null,
- protein: 0.9,
- lipid: 0.2,
- energy: 21,
- ca: 86,
- fe: 0.22,
- mg: 12,
- ph: 14,
- k: 288,
- na: 4,
- zn: 0.1,
- cu: 0.021,
- fl: null,
- mn: 0.196,
- se: null,
- vita_rae: 5,
- vite: null,
- vitc: 8,
- thiamin: 0.02,
- riboflavin: 0.03,
- niacin: 0.3,
- pantothenic: null,
- vitb6: 0.024,
- folate: 7,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'RHUBARB',
- },
- 166: {
- crop_id: 166,
- crop_common_name: 'Eggplant',
- crop_genus: 'Solanum',
- crop_specie: 'melongena ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Fruit-bearing vegetables',
- max_rooting_depth: 1.13,
- depletion_fraction: 0.42,
- is_avg_depth: true,
- initial_kc: 0.54,
- mid_kc: 1.0004,
- end_kc: 0.75,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 19,
- refuse: null,
- protein: 0.98,
- lipid: 0.18,
- energy: 25,
- ca: 9,
- fe: 0.23,
- mg: 14,
- ph: 24,
- k: 229,
- na: 2,
- zn: 0.16,
- cu: 0.081,
- fl: null,
- mn: 0.232,
- se: null,
- vita_rae: 1,
- vite: null,
- vitc: 2.2,
- thiamin: 0.039,
- riboflavin: 0.037,
- niacin: 0.649,
- pantothenic: null,
- vitb6: 0.084,
- folate: 22,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'EGGPLANT',
- },
- 167: {
- crop_id: 167,
- crop_common_name: 'Salsify',
- crop_genus: 'Tragopogon',
- crop_specie: 'porrifolius ',
- crop_group: 'Vegetables and melons',
- crop_subgroup: 'Root, bulb, or tuberous vegetables',
- max_rooting_depth: 0.525,
- depletion_fraction: 0.308333,
- is_avg_depth: true,
- initial_kc: 0.725,
- mid_kc: 1.01667,
- end_kc: 0.866667,
- max_height: null,
- is_avg_kc: true,
- nutrient_notes: null,
- percentrefuse: 13,
- refuse: null,
- protein: 3.3,
- lipid: 0.2,
- energy: 82,
- ca: 60,
- fe: 0.7,
- mg: 23,
- ph: 75,
- k: 380,
- na: 20,
- zn: 0.38,
- cu: 0.089,
- fl: null,
- mn: 0.268,
- se: null,
- vita_rae: 0,
- vite: null,
- vitc: 8,
- thiamin: 0.08,
- riboflavin: 0.22,
- niacin: 0.5,
- pantothenic: null,
- vitb6: 0.277,
- folate: 26,
- vitb12: 0,
- vitk: null,
- is_avg_nutrient: false,
- farm_id: null,
- user_added: false,
- nutrient_credits: null,
- crop_translation_key: 'SALSIFY',
- },
- },
- loading: false,
- error: null,
- loaded: true,
- },
- managementPlanReducer: {
- ids: [145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134],
- entities: {
- 134: {
- management_plan_id: 134,
- crop_id: 167,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 158154,
- estimated_production: 158154,
- variety: null,
- estimated_revenue: 158154,
- is_by_bed: false,
- bed_config: null,
- },
- 135: {
- management_plan_id: 135,
- crop_id: 142,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 136: {
- management_plan_id: 136,
- crop_id: 142,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-13T07:00:00.000Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 137: {
- management_plan_id: 137,
- crop_id: 81,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 138: {
- management_plan_id: 138,
- crop_id: 25,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 139: {
- management_plan_id: 139,
- crop_id: 31,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 140: {
- management_plan_id: 140,
- crop_id: 147,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 141: {
- management_plan_id: 141,
- crop_id: 147,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 142: {
- management_plan_id: 142,
- crop_id: 66,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 143: {
- management_plan_id: 143,
- crop_id: 82,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2021-04-14T17:10:00.145Z',
- harvest_date: '2021-05-14T17:10:00.144Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 144: {
- management_plan_id: 144,
- crop_id: 82,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2020-04-14T07:00:00.000Z',
- harvest_date: '2020-05-14T07:00:00.000Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- 145: {
- management_plan_id: 145,
- crop_id: 82,
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- seed_date: '2025-04-28T07:00:00.000Z',
- harvest_date: '2026-01-14T08:00:00.000Z',
- area_used: 1582,
- estimated_production: 1582,
- variety: null,
- estimated_revenue: 1582,
- is_by_bed: false,
- bed_config: null,
- },
- },
- loading: false,
- error: null,
- loaded: true,
- },
- weatherReducer: {
- ids: ['cebbe678-5f88-11eb-89a9-31fa75807a90'],
- entities: {
- 'cebbe678-5f88-11eb-89a9-31fa75807a90': {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- loading: false,
- city: 'Vancouver',
- date: 1620248233,
- humidity: '67%',
- iconName: 'wi-cloudy',
- temperature: '14',
- wind: '3.6',
- measurement: 'metric',
- lastActiveDatetime: 1620248233388,
- error: null,
- loaded: true,
- },
- },
- },
- barnReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- ceremonialReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- farmSiteBoundaryReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- fieldReducer: {
- ids: ['3da7abb4-9d44-11eb-bbf7-1bc17302df43'],
- entities: {
- '3da7abb4-9d44-11eb-bbf7-1bc17302df43': {
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- name: 'Field one',
- notes: '',
- location_id: '3da7abb4-9d44-11eb-bbf7-1bc17302df43',
- figure_id: '3da7abb5-9d44-11eb-bbf7-1bc17302df43',
- type: 'field',
- total_area: 158154,
- total_area_unit: 'ha',
- grid_points: [
- {
- lat: 49.26822337992714,
- lng: -123.2591160736328,
- },
- {
- lat: 49.2656190259034,
- lng: -123.25606908419188,
- },
- {
- lat: 49.267131248202105,
- lng: -123.25177754976805,
- },
- {
- lat: 49.27068758833716,
- lng: -123.25430955507811,
- },
- ],
- perimeter: 1600,
- perimeter_unit: 'km',
- station_id: null,
- organic_status: 'Transitional',
- transition_date: '2021-04-14T07:00:00.000Z',
- },
- },
- loading: false,
- error: null,
- loaded: true,
- },
- gardenReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- greenhouseReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- surfaceWaterReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- naturalAreaReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- residenceReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- bufferZoneReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- watercourseReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- fenceReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- gateReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- waterValveReducer: {
- ids: [],
- entities: {},
- loading: false,
- error: null,
- loaded: true,
- },
- showedSpotlightReducer: {
- loaded: true,
- loading: false,
- map: true,
- draw_area: true,
- draw_line: false,
- drop_point: false,
- adjust_area: true,
- adjust_line: false,
- navigation: true,
- introduce_map: true,
- documents: true,
- compliance_docs_and_certification: true,
- transplant: true,
- management_plan_creation: true,
- },
- },
- persistedStateReducer: {
- userLogReducer: {
- lastActiveDatetime: 1620248232594,
- farm_id: 'cebbe678-5f88-11eb-89a9-31fa75807a90',
- },
- chooseFarmFlowReducer: {
- ids: [],
- entities: {},
- },
- mapFilterSettingReducer: {
- ids: [],
- entities: {},
- },
- },
- tempStateReducer: {
- homeReducer: {
- loading: false,
- },
- shiftStepReducer: {
- worker: null,
- shift_date: '2021-05-05T20:26:07.495Z',
- selectedTasks: [],
- },
- logSliceReducer: {
- defaultDate: '2021-05-05T20:26:07.166Z',
- date: '2021-05-05T20:26:07.167Z',
- defaultField: null,
- defaultCrop: null,
- defaultQuantity: null,
- defaultNotes: null,
- activity_kind: null,
- activity_id: null,
- selectedUseTypes: [],
- crops: null,
- locations: null,
- notes: null,
- quantity_kg: null,
- validQuantity: true,
- isEditStepOne: false,
- isEditStepTwo: false,
- isEditStepThree: false,
- isEdit: false,
- convertQuantity: false,
- resetCrop: false,
- filteredCropOptions: [],
- },
- mapLocationReducer: {
- successMessage: null,
- canShowSuccessHeader: false,
- canShowSelection: false,
- locations: [],
- zoomLevel: null,
- position: null,
- },
- hookFormPersistReducer: {
- formData: {},
- shouldUpdateFormData: true,
- },
- navbarReducer: {
- introducingCertifications: false,
- },
- },
- baseReducer: {},
- logReducer: {
- forms: {
- fertLog: {
- fert_id: null,
- quantity_kg: 0,
- notes: '',
- moisture_percentage: 0,
- n_percentage: 0,
- nh4_n_ppm: 0,
- p_percentage: 0,
- k_percentage: 0,
- field: null,
- },
- fieldWorkLog: {
- type: null,
- notes: '',
- field: null,
- },
- harvestLog: {
- notes: '',
- field: null,
- },
- irrigationLog: {
- activity_kind: 'irrigation',
- type: '',
- notes: '',
- flow_rate: null,
- unit: 'l/min',
- hours: null,
- field: null,
- },
- otherLog: {
- notes: '',
- field: null,
- },
- pestControlLog: {
- quantity: 0,
- notes: '',
- custom_pesticide_name: '',
- custom_disease_scientific_name: '',
- custom_disease_common_name: '',
- custom_disease_group: 'Other',
- crop: null,
- pesticide_id: null,
- disease_id: 1,
- type: '',
- entry_interval: 0,
- harvest_interval: 0,
- active_ingredients: '',
- concentration: 0,
- field: null,
- },
- scoutingLog: {
- activity_kind: 'scouting',
- type: '',
- notes: '',
- action_needed: false,
- field: null,
- },
- seedLog: {
- space_length: null,
- space_width: null,
- space_unit: null,
- rate: null,
- rate_unit: null,
- field: null,
- },
- soilDataLog: {},
- harvestAllocation: {},
- forms: {
- $form: {
- initialValue: {
- fertLog: {
- fert_id: null,
- quantity_kg: 0,
- notes: '',
- moisture_percentage: 0,
- n_percentage: 0,
- nh4_n_ppm: 0,
- p_percentage: 0,
- k_percentage: 0,
- field: null,
- },
- fieldWorkLog: {
- type: null,
- notes: '',
- field: null,
- },
- harvestLog: {
- notes: '',
- field: null,
- },
- irrigationLog: {
- activity_kind: 'irrigation',
- type: '',
- notes: '',
- flow_rate: null,
- unit: 'l/min',
- hours: null,
- field: null,
- },
- otherLog: {
- notes: '',
- field: null,
- },
- pestControlLog: {
- quantity: 0,
- notes: '',
- custom_pesticide_name: '',
- custom_disease_scientific_name: '',
- custom_disease_common_name: '',
- custom_disease_group: 'Other',
- crop: null,
- pesticide_id: null,
- disease_id: 1,
- type: '',
- entry_interval: 0,
- harvest_interval: 0,
- active_ingredients: '',
- concentration: 0,
- field: null,
- },
- scoutingLog: {
- activity_kind: 'scouting',
- type: '',
- notes: '',
- action_needed: false,
- field: null,
- },
- seedLog: {
- space_length: null,
- space_width: null,
- space_unit: null,
- rate: null,
- rate_unit: null,
- field: null,
- },
- soilDataLog: {},
- harvestAllocation: {},
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms',
- value: {
- fertLog: {
- fert_id: null,
- quantity_kg: 0,
- notes: '',
- moisture_percentage: 0,
- n_percentage: 0,
- nh4_n_ppm: 0,
- p_percentage: 0,
- k_percentage: 0,
- field: null,
- },
- fieldWorkLog: {
- type: null,
- notes: '',
- field: null,
- },
- harvestLog: {
- notes: '',
- field: null,
- },
- irrigationLog: {
- activity_kind: 'irrigation',
- type: '',
- notes: '',
- flow_rate: null,
- unit: 'l/min',
- hours: null,
- field: null,
- },
- otherLog: {
- notes: '',
- field: null,
- },
- pestControlLog: {
- quantity: 0,
- notes: '',
- custom_pesticide_name: '',
- custom_disease_scientific_name: '',
- custom_disease_common_name: '',
- custom_disease_group: 'Other',
- crop: null,
- pesticide_id: null,
- disease_id: 1,
- type: '',
- entry_interval: 0,
- harvest_interval: 0,
- active_ingredients: '',
- concentration: 0,
- field: null,
- },
- scoutingLog: {
- activity_kind: 'scouting',
- type: '',
- notes: '',
- action_needed: false,
- field: null,
- },
- seedLog: {
- space_length: null,
- space_width: null,
- space_unit: null,
- rate: null,
- rate_unit: null,
- field: null,
- },
- soilDataLog: {},
- harvestAllocation: {},
- },
- },
- fertLog: {
- $form: {
- initialValue: {
- fert_id: null,
- quantity_kg: 0,
- notes: '',
- moisture_percentage: 0,
- n_percentage: 0,
- nh4_n_ppm: 0,
- p_percentage: 0,
- k_percentage: 0,
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog',
- value: {
- fert_id: null,
- quantity_kg: 0,
- notes: '',
- moisture_percentage: 0,
- n_percentage: 0,
- nh4_n_ppm: 0,
- p_percentage: 0,
- k_percentage: 0,
- field: null,
- },
- },
- fert_id: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.fert_id',
- value: null,
- },
- quantity_kg: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.quantity_kg',
- value: 0,
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.notes',
- value: '',
- },
- moisture_percentage: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.moisture_percentage',
- value: 0,
- },
- n_percentage: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.n_percentage',
- value: 0,
- },
- nh4_n_ppm: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.nh4_n_ppm',
- value: 0,
- },
- p_percentage: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.p_percentage',
- value: 0,
- },
- k_percentage: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.k_percentage',
- value: 0,
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fertLog.field',
- value: null,
- },
- },
- fieldWorkLog: {
- $form: {
- initialValue: {
- type: null,
- notes: '',
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fieldWorkLog',
- value: {
- type: null,
- notes: '',
- field: null,
- },
- },
- type: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fieldWorkLog.type',
- value: null,
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fieldWorkLog.notes',
- value: '',
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.fieldWorkLog.field',
- value: null,
- },
- },
- harvestLog: {
- $form: {
- initialValue: {
- notes: '',
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.harvestLog',
- value: {
- notes: '',
- field: null,
- },
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.harvestLog.notes',
- value: '',
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.harvestLog.field',
- value: null,
- },
- },
- irrigationLog: {
- $form: {
- initialValue: {
- activity_kind: 'irrigation',
- type: '',
- notes: '',
- flow_rate: null,
- unit: 'l/min',
- hours: null,
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog',
- value: {
- activity_kind: 'irrigation',
- type: '',
- notes: '',
- flow_rate: null,
- unit: 'l/min',
- hours: null,
- field: null,
- },
- },
- activity_kind: {
- initialValue: 'irrigation',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.activity_kind',
- value: 'irrigation',
- },
- type: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.type',
- value: '',
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.notes',
- value: '',
- },
- flow_rate: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.flow_rate',
- value: null,
- },
- unit: {
- initialValue: 'l/min',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.unit',
- value: 'l/min',
- },
- hours: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.hours',
- value: null,
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.irrigationLog.field',
- value: null,
- },
- },
- otherLog: {
- $form: {
- initialValue: {
- notes: '',
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.otherLog',
- value: {
- notes: '',
- field: null,
- },
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.otherLog.notes',
- value: '',
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.otherLog.field',
- value: null,
- },
- },
- pestControlLog: {
- $form: {
- initialValue: {
- quantity: 0,
- notes: '',
- custom_pesticide_name: '',
- custom_disease_scientific_name: '',
- custom_disease_common_name: '',
- custom_disease_group: 'Other',
- crop: null,
- pesticide_id: null,
- disease_id: 1,
- type: '',
- entry_interval: 0,
- harvest_interval: 0,
- active_ingredients: '',
- concentration: 0,
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog',
- value: {
- quantity: 0,
- notes: '',
- custom_pesticide_name: '',
- custom_disease_scientific_name: '',
- custom_disease_common_name: '',
- custom_disease_group: 'Other',
- crop: null,
- pesticide_id: null,
- disease_id: 1,
- type: '',
- entry_interval: 0,
- harvest_interval: 0,
- active_ingredients: '',
- concentration: 0,
- field: null,
- },
- },
- quantity: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.quantity',
- value: 0,
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.notes',
- value: '',
- },
- custom_pesticide_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.custom_pesticide_name',
- value: '',
- },
- custom_disease_scientific_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.custom_disease_scientific_name',
- value: '',
- },
- custom_disease_common_name: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.custom_disease_common_name',
- value: '',
- },
- custom_disease_group: {
- initialValue: 'Other',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.custom_disease_group',
- value: 'Other',
- },
- crop: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.crop',
- value: null,
- },
- pesticide_id: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.pesticide_id',
- value: null,
- },
- disease_id: {
- initialValue: 1,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.disease_id',
- value: 1,
- },
- type: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.type',
- value: '',
- },
- entry_interval: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.entry_interval',
- value: 0,
- },
- harvest_interval: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.harvest_interval',
- value: 0,
- },
- active_ingredients: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.active_ingredients',
- value: '',
- },
- concentration: {
- initialValue: 0,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.concentration',
- value: 0,
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.pestControlLog.field',
- value: null,
- },
- },
- scoutingLog: {
- $form: {
- initialValue: {
- activity_kind: 'scouting',
- type: '',
- notes: '',
- action_needed: false,
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog',
- value: {
- activity_kind: 'scouting',
- type: '',
- notes: '',
- action_needed: false,
- field: null,
- },
- },
- activity_kind: {
- initialValue: 'scouting',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog.activity_kind',
- value: 'scouting',
- },
- type: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog.type',
- value: '',
- },
- notes: {
- initialValue: '',
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog.notes',
- value: '',
- },
- action_needed: {
- initialValue: false,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog.action_needed',
- value: false,
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.scoutingLog.field',
- value: null,
- },
- },
- seedLog: {
- $form: {
- initialValue: {
- space_length: null,
- space_width: null,
- space_unit: null,
- rate: null,
- rate_unit: null,
- field: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog',
- value: {
- space_length: null,
- space_width: null,
- space_unit: null,
- rate: null,
- rate_unit: null,
- field: null,
- },
- },
- space_length: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.space_length',
- value: null,
- },
- space_width: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.space_width',
- value: null,
- },
- space_unit: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.space_unit',
- value: null,
- },
- rate: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.rate',
- value: null,
- },
- rate_unit: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.rate_unit',
- value: null,
- },
- field: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.seedLog.field',
- value: null,
- },
- },
- soilDataLog: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.soilDataLog',
- value: {},
- },
- },
- harvestAllocation: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'logReducer.forms.harvestAllocation',
- value: {},
- },
- },
- },
- },
- logReducer: {
- logs: [],
- startDate: '2021-01-01T08:00:00.000Z',
- endDate: '2022-01-01T07:59:59.999Z',
- allUseType: [],
- },
- fertReducer: {
- fertilizers: null,
- },
- pestControlReducer: {
- pesticides: null,
- diseases: null,
- },
- },
- shiftReducer: {
- taskTypes: [],
- selectedTasks: [],
- availableDuration: 0,
- shifts: [],
- selectedShift: {},
- startDate: '2021-01-01T08:00:00.000Z',
- endDate: '2022-01-01T07:59:59.999Z',
- },
- insightReducer: {
- cropNutritionData: {
- preview: 0,
- data: [],
- },
- soilOMData: {
- preview: 0,
- data: [],
- },
- labourHappinessData: {
- preview: 0,
- data: [],
- },
- biodiversityData: {
- preview: 0,
- data: [],
- },
- pricesData: {
- preview: 0,
- amountOfFarms: 0,
- data: [],
- },
- waterBalanceData: {
- preview: 0,
- data: [],
- },
- waterBalanceSchedule: {},
- nitrogenBalanceData: {
- preview: 0,
- data: [],
- },
- nitrogenFrequencyData: {},
- pricesDistance: 5,
- },
- financeReducer: {
- forms: {
- addSale: {},
- editSale: {},
- expenseDetail: {},
- date_range: null,
- forms: {
- $form: {
- initialValue: {
- addSale: {},
- editSale: {},
- expenseDetail: {},
- date_range: null,
- },
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'financeReducer.forms',
- value: {
- addSale: {},
- editSale: {},
- expenseDetail: {},
- date_range: null,
- },
- },
- addSale: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'financeReducer.forms.addSale',
- value: {},
- },
- },
- editSale: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'financeReducer.forms.editSale',
- value: {},
- },
- },
- expenseDetail: {
- $form: {
- initialValue: {},
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'financeReducer.forms.expenseDetail',
- value: {},
- },
- },
- date_range: {
- initialValue: null,
- focus: false,
- pending: false,
- pristine: true,
- submitted: false,
- submitFailed: false,
- retouched: false,
- touched: false,
- valid: true,
- validating: false,
- validated: false,
- validity: {},
- errors: {},
- intents: [],
- model: 'financeReducer.forms.date_range',
- value: null,
- },
- },
- },
- financeReducer: {
- sales: [],
- cropSales: null,
- shifts: null,
- expenses: [],
- },
- },
- farmReducer: {
- farm_data_schedule: null,
- },
- documentReducer: {
- ids: ['51a5sd1a1sd'],
- entities: {
- '51a5sd1a1sd': {
- document_id: '',
- name: 'doc name',
- valid_until: new Date(),
- type: null,
- thumbnail_url: null,
- notes: null,
- farm_id: null,
- },
- },
- },
- _persist: {
- version: -1,
- rehydrated: true,
- },
-};
diff --git a/packages/webapp/src/stories/PriceCharts/CropStatusInfoBox.stories.jsx b/packages/webapp/src/stories/PriceCharts/CropStatusInfoBox.stories.jsx
new file mode 100644
index 0000000000..2a6f8029db
--- /dev/null
+++ b/packages/webapp/src/stories/PriceCharts/CropStatusInfoBox.stories.jsx
@@ -0,0 +1,126 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { PriceCropCharts } from '../../components/Insights/PriceCropCharts/PriceCropCharts';
+
+export default {
+ title: 'Components/PriceCropCharts',
+ component: PriceCropCharts,
+ decorators: componentDecorators,
+};
+
+const cropsWithPriceInfo = [
+ {
+ ALFALFA_FOR_FODDER: [
+ {
+ crop_date: '2022-01',
+ crop_price: 0,
+ network_price: 2,
+ },
+ {
+ crop_date: '2022-02',
+ crop_price: 5,
+ network_price: 6,
+ },
+ {
+ crop_date: '2022-03',
+ crop_price: 0,
+ network_price: 9,
+ },
+ {
+ crop_date: '2022-04',
+ crop_price: 0,
+ network_price: 3,
+ },
+ {
+ crop_date: '2022-05',
+ crop_price: 0,
+ network_price: 10,
+ },
+ {
+ crop_date: '2022-06',
+ crop_price: 0,
+ network_price: 6,
+ },
+ {
+ crop_date: '2022-07',
+ crop_price: 0,
+ network_price: 4,
+ },
+ {
+ crop_date: '2022-08',
+ crop_price: 0,
+ network_price: 9,
+ },
+ {
+ crop_date: '2022-09',
+ crop_price: 0,
+ network_price: 2,
+ },
+ {
+ crop_date: '2022-10',
+ crop_price: 0,
+ network_price: 0.21428571428571427,
+ },
+ {
+ crop_date: '2022-11',
+ crop_price: 0,
+ network_price: 27.66666666666667,
+ },
+ {
+ crop_date: '2022-12',
+ crop_price: 2.572063713692564,
+ network_price: 4.11457020742577,
+ },
+ {
+ crop_date: '2021-01',
+ crop_price: 4.409235879422096,
+ network_price: 11.841000480816383,
+ },
+ {
+ crop_date: '2021-02',
+ crop_price: 305.89130111278297,
+ network_price: 131.06595463165482,
+ },
+ ],
+ },
+ {
+ ALMOND: [
+ {
+ crop_date: '2022-12',
+ crop_price: 3.00630723257394,
+ network_price: 3.00630723257394,
+ },
+ {
+ crop_date: '2022-01',
+ crop_price: 3.00630723257394,
+ network_price: 3.00630723257394,
+ },
+ ],
+ },
+];
+
+const Template = (args) => ;
+export const Default = Template.bind({});
+Default.args = {
+ cropsWithPriceInfo,
+ currencySymbol: '$',
+ unit: 'mi',
+ isImperial: true,
+};
+
+export const OneYear = Template.bind({});
+OneYear.args = {
+ cropsWithPriceInfo: [
+ {
+ ALMOND: [
+ {
+ crop_date: '2022-01',
+ crop_price: 3.00630723257394,
+ network_price: 3.00630723257394,
+ },
+ ],
+ },
+ ],
+ currencySymbol: '$',
+ isImperial: false,
+};
diff --git a/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.js b/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.js
deleted file mode 100644
index d2c92117a0..0000000000
--- a/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import React from 'react';
-import ProgressBar from '../../components/ProgressBar';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/ProgressBar',
- component: ProgressBar,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const One_third = Template.bind({});
-One_third.args = {
- label: 'progress',
- value: 33,
-};
-
-export const Two_third = Template.bind({});
-Two_third.args = {
- label: 'progress',
- value: 66,
-};
-
-export const Full = Template.bind({});
-Full.args = {
- label: 'progress',
- value: 100,
-};
diff --git a/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.jsx b/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.jsx
new file mode 100644
index 0000000000..99d1297929
--- /dev/null
+++ b/packages/webapp/src/stories/ProgressBar/ProgressBar.stories.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import ProgressBar from '../../components/ProgressBar';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/ProgressBar',
+ component: ProgressBar,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const One_third = Template.bind({});
+One_third.args = {
+ label: 'progress',
+ value: 33,
+};
+
+export const Two_third = Template.bind({});
+Two_third.args = {
+ label: 'progress',
+ value: 66,
+};
+
+export const Full = Template.bind({});
+Full.args = {
+ label: 'progress',
+ value: 100,
+};
diff --git a/packages/webapp/src/stories/Rating/Rating.stories.js b/packages/webapp/src/stories/Rating/Rating.stories.js
deleted file mode 100644
index 70596f9c27..0000000000
--- a/packages/webapp/src/stories/Rating/Rating.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import Rating from '../../components/Rating';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/Rating',
- component: Rating,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const ZeroStar = Template.bind({});
-ZeroStar.args = {
- stars: 0,
-};
-
-export const ThreeStar = Template.bind({});
-ThreeStar.args = {
- stars: 3,
-};
-
-export const FiveStar = Template.bind({});
-FiveStar.args = {
- stars: 5,
-};
diff --git a/packages/webapp/src/stories/Rating/Rating.stories.jsx b/packages/webapp/src/stories/Rating/Rating.stories.jsx
new file mode 100644
index 0000000000..506aed0057
--- /dev/null
+++ b/packages/webapp/src/stories/Rating/Rating.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import Rating from '../../components/Rating';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/Rating',
+ component: Rating,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const ZeroStar = Template.bind({});
+ZeroStar.args = {
+ stars: 0,
+};
+
+export const ThreeStar = Template.bind({});
+ThreeStar.args = {
+ stars: 3,
+};
+
+export const FiveStar = Template.bind({});
+FiveStar.args = {
+ stars: 5,
+};
diff --git a/packages/webapp/src/stories/RouterTab/RouterTab.stories.js b/packages/webapp/src/stories/RouterTab/RouterTab.stories.js
deleted file mode 100644
index 490537e6b9..0000000000
--- a/packages/webapp/src/stories/RouterTab/RouterTab.stories.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import React from 'react';
-import RouterTab from '../../components/RouterTab';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/RouterTab',
- component: RouterTab,
- decorators: componentDecorators,
-};
-
-const tabs = [
- { label: 'Detail', path: '/detail' },
- { label: 'Crop', path: '/crop' },
- { label: 'User', path: '/user' },
-];
-
-const Template = (args) => ;
-export const Left = Template.bind({});
-Left.args = {
- tabs,
- history: { location: { pathname: '/detail' } },
-};
-
-export const Middle = Template.bind({});
-Middle.args = {
- tabs,
- history: { location: { pathname: '/crop' } },
-};
diff --git a/packages/webapp/src/stories/RouterTab/RouterTab.stories.jsx b/packages/webapp/src/stories/RouterTab/RouterTab.stories.jsx
new file mode 100644
index 0000000000..8e77665b0b
--- /dev/null
+++ b/packages/webapp/src/stories/RouterTab/RouterTab.stories.jsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import RouterTab from '../../components/RouterTab';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/RouterTab',
+ component: RouterTab,
+ decorators: componentDecorators,
+};
+
+const tabs = [
+ { label: 'Detail', path: '/detail' },
+ { label: 'Crop', path: '/crop' },
+ { label: 'User', path: '/user' },
+];
+
+const Template = (args) => ;
+export const Left = Template.bind({});
+Left.args = {
+ tabs,
+ history: { location: { pathname: '/detail' } },
+};
+
+export const Middle = Template.bind({});
+Middle.args = {
+ tabs,
+ history: { location: { pathname: '/crop' } },
+};
diff --git a/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.js b/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.js
deleted file mode 100644
index c99fbd6ed0..0000000000
--- a/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
-
-export default {
- title: 'Components/PureSearchbarAndFilter',
- component: PureSearchbarAndFilter,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const InActive = Template.bind({});
-InActive.args = {};
-
-export const Active = Template.bind({});
-Active.args = {
- filterOptions: ['Active', 'Planned', 'Complete', 'Abandoned', 'Needs Plan'],
-};
diff --git a/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.jsx b/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.jsx
new file mode 100644
index 0000000000..f6688d46ee
--- /dev/null
+++ b/packages/webapp/src/stories/SearchbarAndFilter/PureSearchbarAndFilter.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import PureSearchbarAndFilter from '../../components/PopupFilter/PureSearchbarAndFilter';
+
+export default {
+ title: 'Components/PureSearchbarAndFilter',
+ component: PureSearchbarAndFilter,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const InActive = Template.bind({});
+InActive.args = {};
+
+export const Active = Template.bind({});
+Active.args = {
+ filterOptions: ['Active', 'Planned', 'Complete', 'Abandoned', 'Needs Plan'],
+};
diff --git a/packages/webapp/src/stories/SnackBar/Snackbar.stories.js b/packages/webapp/src/stories/SnackBar/Snackbar.stories.js
deleted file mode 100644
index 3403381d8d..0000000000
--- a/packages/webapp/src/stories/SnackBar/Snackbar.stories.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import { NotistackSnackbar } from '../../containers/Snackbar/NotistackSnackbar';
-import decorator from '../Pages/config/decorators';
-import { SnackbarProvider, useSnackbar } from 'notistack';
-import Layout from '../../components/Layout';
-import PageTitle from '../../components/PageTitle/v2';
-import Button from '../../components/Form/Button';
-import { PureSnackbar } from '../../components/PureSnackbar';
-import styles from './styles.module.scss';
-
-export default {
- title: 'Components/Snackbar',
- component: NotistackSnackbar,
- decorators: decorator,
-};
-
-function Page() {
- const { enqueueSnackbar } = useSnackbar();
- return (
- Dismiss}>
-
-
- enqueueSnackbar('Upload success', {
- persist: true,
- key: `success-${new Date().getTime()}`,
- })
- }
- >
- Success
-
-
- enqueueSnackbar('Upload success', {
- persist: true,
- key: `error-${new Date().getTime()}`,
- })
- }
- >
- Error
-
-
- );
-}
-
-const Template = (args) => {
- return (
- }
- >
-
-
- );
-};
-export const Primary = Template.bind({});
-Primary.args = {};
-const SnackBarTemplate = (args) => ;
-export const Success = SnackBarTemplate.bind({});
-Success.args = {
- type: 'success',
- message: 'success',
- onDismiss: () => {},
-};
-
-export const Error = SnackBarTemplate.bind({});
-Error.args = {
- type: 'error',
- message: 'error',
- onDismiss: () => {},
-};
diff --git a/packages/webapp/src/stories/SnackBar/Snackbar.stories.jsx b/packages/webapp/src/stories/SnackBar/Snackbar.stories.jsx
new file mode 100644
index 0000000000..c1aad5a7fa
--- /dev/null
+++ b/packages/webapp/src/stories/SnackBar/Snackbar.stories.jsx
@@ -0,0 +1,76 @@
+import React from 'react';
+import { NotistackSnackbar } from '../../containers/Snackbar/NotistackSnackbar';
+import decorator from '../Pages/config/Decorators';
+import { SnackbarProvider, useSnackbar } from 'notistack';
+import Layout from '../../components/Layout';
+import PageTitle from '../../components/PageTitle/v2';
+import Button from '../../components/Form/Button';
+import { PureSnackbar } from '../../components/PureSnackbar';
+import styles from './styles.module.scss';
+
+export default {
+ title: 'Components/Snackbar',
+ component: NotistackSnackbar,
+ decorators: decorator,
+};
+
+function Page() {
+ const { enqueueSnackbar } = useSnackbar();
+ return (
+ Dismiss}>
+
+
+ enqueueSnackbar('Upload success', {
+ persist: true,
+ key: `success-${new Date().getTime()}`,
+ })
+ }
+ >
+ Success
+
+
+ enqueueSnackbar('Upload success', {
+ persist: true,
+ key: `error-${new Date().getTime()}`,
+ })
+ }
+ >
+ Error
+
+
+ );
+}
+
+const Template = (args) => {
+ return (
+ }
+ >
+
+
+ );
+};
+export const Primary = Template.bind({});
+Primary.args = {};
+const SnackBarTemplate = (args) => ;
+export const Success = SnackBarTemplate.bind({});
+Success.args = {
+ type: 'success',
+ message: 'success',
+ onDismiss: () => {},
+};
+
+export const Error = SnackBarTemplate.bind({});
+Error.args = {
+ type: 'error',
+ message: 'error',
+ onDismiss: () => {},
+};
diff --git a/packages/webapp/src/stories/Square/Square.stories.js b/packages/webapp/src/stories/Square/Square.stories.js
deleted file mode 100644
index f749704a28..0000000000
--- a/packages/webapp/src/stories/Square/Square.stories.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import { componentDecorators } from '../Pages/config/decorators';
-import Square from '../../components/Square';
-
-export default {
- title: 'Components/Square',
- component: Square,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Active = Template.bind({});
-Active.args = {
- color: 'active',
- children: 8,
-};
-
-export const Planned = Template.bind({});
-Planned.args = {
- color: 'planned',
- children: 88,
-};
-
-export const Past = Template.bind({});
-Past.args = {
- color: 'past',
- children: 888,
-};
-
-export const NeedsPlan = Template.bind({});
-NeedsPlan.args = {
- color: 'needsPlan',
-};
-
-export const CropTileActive = Template.bind({});
-CropTileActive.args = {
- color: 'active',
- children: 8,
- isCropTile: true,
-};
-
-export const CropTilePlanned = Template.bind({});
-CropTilePlanned.args = {
- color: 'planned',
- children: 88,
- isCropTile: true,
-};
-
-export const CropTilePast = Template.bind({});
-CropTilePast.args = {
- color: 'past',
- children: 888,
- isCropTile: true,
-};
-
-export const CropTileNeedsPlan = Template.bind({});
-CropTileNeedsPlan.args = {
- color: 'needsPlan',
- isCropTile: true,
-};
-
-export const CropTileCounter = Template.bind({});
-CropTileCounter.args = {
- color: 'counter',
- children: 0,
- isCropTile: true,
-};
diff --git a/packages/webapp/src/stories/Square/Square.stories.jsx b/packages/webapp/src/stories/Square/Square.stories.jsx
new file mode 100644
index 0000000000..9f42a1917d
--- /dev/null
+++ b/packages/webapp/src/stories/Square/Square.stories.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import { componentDecorators } from '../Pages/config/Decorators';
+import Square from '../../components/Square';
+
+export default {
+ title: 'Components/Square',
+ component: Square,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Active = Template.bind({});
+Active.args = {
+ color: 'active',
+ children: 8,
+};
+
+export const Planned = Template.bind({});
+Planned.args = {
+ color: 'planned',
+ children: 88,
+};
+
+export const Past = Template.bind({});
+Past.args = {
+ color: 'past',
+ children: 888,
+};
+
+export const NeedsPlan = Template.bind({});
+NeedsPlan.args = {
+ color: 'needsPlan',
+};
+
+export const CropTileActive = Template.bind({});
+CropTileActive.args = {
+ color: 'active',
+ children: 8,
+ isCropTile: true,
+};
+
+export const CropTilePlanned = Template.bind({});
+CropTilePlanned.args = {
+ color: 'planned',
+ children: 88,
+ isCropTile: true,
+};
+
+export const CropTilePast = Template.bind({});
+CropTilePast.args = {
+ color: 'past',
+ children: 888,
+ isCropTile: true,
+};
+
+export const CropTileNeedsPlan = Template.bind({});
+CropTileNeedsPlan.args = {
+ color: 'needsPlan',
+ isCropTile: true,
+};
+
+export const CropTileCounter = Template.bind({});
+CropTileCounter.args = {
+ color: 'counter',
+ children: 0,
+ isCropTile: true,
+};
diff --git a/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.js b/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.js
deleted file mode 100644
index 1132621c28..0000000000
--- a/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import React from 'react';
-import RenderSurvey from '../../containers/RenderSurvey/RenderSurvey';
-import decorators from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Components/Modals/RenderSurvey',
- decorators,
- component: RenderSurvey,
-};
-
-const PrimaryTemplate = (args) => {
- window.data = {
- questionAnswerMap: {
- 'sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
- '2sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
- },
- certifier: { certifier_name: 'certifier_name' },
- certification: { certification_translation_key: 'ORGANIC' },
- organicCertifierSurvey: {
- requested_certification: 'requested_certification',
- requested_certifier: 'requested_certifier',
- },
- };
- return ;
-};
-
-export const Primary = PrimaryTemplate.bind({});
-Primary.args = {};
-
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
-
-const SecondaryTemplate = (args) => {
- window.data = {
- questionAnswerMap: {
- 'sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
- '2sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
- },
- organicCertifierSurvey: {
- requested_certification: 'requested_certification',
- requested_certifier: 'requested_certifier',
- },
- };
- return ;
-};
-
-export const Secondary = SecondaryTemplate.bind({});
-Secondary.args = {};
-
-Secondary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.jsx b/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.jsx
new file mode 100644
index 0000000000..0a0fd6de4c
--- /dev/null
+++ b/packages/webapp/src/stories/SurveyExport/SurveyExport.stories.jsx
@@ -0,0 +1,54 @@
+import React from 'react';
+import RenderSurvey from '../../containers/RenderSurvey/RenderSurvey';
+import decorators from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Components/Modals/RenderSurvey',
+ decorators,
+ component: RenderSurvey,
+};
+
+const PrimaryTemplate = (args) => {
+ window.data = {
+ questionAnswerMap: {
+ 'sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
+ '2sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
+ },
+ certifier: { certifier_name: 'certifier_name' },
+ certification: { certification_translation_key: 'ORGANIC' },
+ organicCertifierSurvey: {
+ requested_certification: 'requested_certification',
+ requested_certifier: 'requested_certifier',
+ },
+ };
+ return ;
+};
+
+export const Primary = PrimaryTemplate.bind({});
+Primary.args = {};
+
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
+
+const SecondaryTemplate = (args) => {
+ window.data = {
+ questionAnswerMap: {
+ 'sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
+ '2sinetgubg ksiafuaisasd asidufhsdg asdfuhsdg asdfuhsdg safusdag': 'ASjj AOSIDJ woeitj aoij ASF ASOIj aetA SOifAJET OAISJF oqwjroG AEOtjwoeitj ASF oijweto jSF OWIEJToi wjsDF',
+ },
+ organicCertifierSurvey: {
+ requested_certification: 'requested_certification',
+ requested_certifier: 'requested_certifier',
+ },
+ };
+ return ;
+};
+
+export const Secondary = SecondaryTemplate.bind({});
+Secondary.args = {};
+
+Secondary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/TaskCard/TaskCard.stories.js b/packages/webapp/src/stories/TaskCard/TaskCard.stories.js
deleted file mode 100644
index e85ca3114d..0000000000
--- a/packages/webapp/src/stories/TaskCard/TaskCard.stories.js
+++ /dev/null
@@ -1,112 +0,0 @@
-import React from 'react';
-import { PureTaskCard } from '../../components/CardWithStatus/TaskCard/TaskCard';
-import { componentDecorators } from '../Pages/config/decorators';
-import { getTaskCardDate } from '../../util/moment';
-
-export default {
- title: 'Components/TaskCard',
- component: PureTaskCard,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-const templateData = {
- taskType: {
- task_name: 'Transport',
- task_translation_key: 'TRANSPORT_TASK',
- },
- status: 'planned',
- locationName: 'Location 1',
- completeOrDueDate: getTaskCardDate('2021-04-20T16:22:41.108Z'),
- assignee: {
- first_name: 'First',
- last_name: 'Last',
- },
- cropVarietyName: 'Carrot',
- onClick: null,
- onClickAssignee: (e) => {
- e.stopPropagation();
- console.log('clicked assignee');
- },
- selected: false,
- happiness: null,
-};
-
-export const Planned = Template.bind({});
-Planned.args = {
- ...templateData,
-};
-
-export const Unassigned = Template.bind({});
-Unassigned.args = {
- ...templateData,
- assignee: null,
-};
-
-export const Late = Template.bind({});
-Late.args = {
- ...templateData,
- status: 'late',
-};
-
-export const Completed = Template.bind({});
-Completed.args = {
- ...templateData,
- status: 'completed',
-};
-
-export const CompletedWithRating = Template.bind({});
-CompletedWithRating.args = {
- ...templateData,
- status: 'completed',
- happiness: 4,
-};
-
-export const Abandoned = Template.bind({});
-Abandoned.args = {
- ...templateData,
- status: 'abandoned',
-};
-
-export const ClickableCard = Template.bind({});
-ClickableCard.args = {
- ...templateData,
- onClick: () => {
- console.log('clicked card');
- },
-};
-
-export const PlannedSelected = Template.bind({});
-PlannedSelected.args = {
- ...templateData,
- selected: true,
-};
-
-export const LateSelected = Template.bind({});
-LateSelected.args = {
- ...templateData,
- status: 'late',
- selected: true,
-};
-
-export const CompletedSelected = Template.bind({});
-CompletedSelected.args = {
- ...templateData,
- status: 'completed',
- selected: true,
-};
-
-export const CompletedSelectedWithSadRating = Template.bind({});
-CompletedSelectedWithSadRating.args = {
- ...templateData,
- status: 'completed',
- selected: true,
- happiness: 0,
-};
-
-export const AbandonedSelected = Template.bind({});
-AbandonedSelected.args = {
- ...templateData,
- status: 'abandoned',
- selected: true,
-};
diff --git a/packages/webapp/src/stories/TaskCard/TaskCard.stories.jsx b/packages/webapp/src/stories/TaskCard/TaskCard.stories.jsx
new file mode 100644
index 0000000000..9f87fd5ca4
--- /dev/null
+++ b/packages/webapp/src/stories/TaskCard/TaskCard.stories.jsx
@@ -0,0 +1,112 @@
+import React from 'react';
+import { PureTaskCard } from '../../components/CardWithStatus/TaskCard/TaskCard';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { getTaskCardDate } from '../../util/moment';
+
+export default {
+ title: 'Components/TaskCard',
+ component: PureTaskCard,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+const templateData = {
+ taskType: {
+ task_name: 'Transport',
+ task_translation_key: 'TRANSPORT_TASK',
+ },
+ status: 'planned',
+ locationName: 'Location 1',
+ completeOrDueDate: getTaskCardDate('2021-04-20T16:22:41.108Z'),
+ assignee: {
+ first_name: 'First',
+ last_name: 'Last',
+ },
+ cropVarietyName: 'Carrot',
+ onClick: null,
+ onClickAssignee: (e) => {
+ e.stopPropagation();
+ console.log('clicked assignee');
+ },
+ selected: false,
+ happiness: null,
+};
+
+export const Planned = Template.bind({});
+Planned.args = {
+ ...templateData,
+};
+
+export const Unassigned = Template.bind({});
+Unassigned.args = {
+ ...templateData,
+ assignee: null,
+};
+
+export const Late = Template.bind({});
+Late.args = {
+ ...templateData,
+ status: 'late',
+};
+
+export const Completed = Template.bind({});
+Completed.args = {
+ ...templateData,
+ status: 'completed',
+};
+
+export const CompletedWithRating = Template.bind({});
+CompletedWithRating.args = {
+ ...templateData,
+ status: 'completed',
+ happiness: 4,
+};
+
+export const Abandoned = Template.bind({});
+Abandoned.args = {
+ ...templateData,
+ status: 'abandoned',
+};
+
+export const ClickableCard = Template.bind({});
+ClickableCard.args = {
+ ...templateData,
+ onClick: () => {
+ console.log('clicked card');
+ },
+};
+
+export const PlannedSelected = Template.bind({});
+PlannedSelected.args = {
+ ...templateData,
+ selected: true,
+};
+
+export const LateSelected = Template.bind({});
+LateSelected.args = {
+ ...templateData,
+ status: 'late',
+ selected: true,
+};
+
+export const CompletedSelected = Template.bind({});
+CompletedSelected.args = {
+ ...templateData,
+ status: 'completed',
+ selected: true,
+};
+
+export const CompletedSelectedWithSadRating = Template.bind({});
+CompletedSelectedWithSadRating.args = {
+ ...templateData,
+ status: 'completed',
+ selected: true,
+ happiness: 0,
+};
+
+export const AbandonedSelected = Template.bind({});
+AbandonedSelected.args = {
+ ...templateData,
+ status: 'abandoned',
+ selected: true,
+};
diff --git a/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.js b/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.js
deleted file mode 100644
index b1cf37b3cc..0000000000
--- a/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import TitleLayout from '../../components/Layout/TitleLayout';
-import decorator from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Layout/TitleLayout',
- decorators: decorator,
- component: TitleLayout,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = { title: 'Dummy header' };
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.jsx b/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.jsx
new file mode 100644
index 0000000000..11cff54c81
--- /dev/null
+++ b/packages/webapp/src/stories/TitleLayout/TitleLayout.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import TitleLayout from '../../components/Layout/TitleLayout';
+import decorator from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Layout/TitleLayout',
+ decorators: decorator,
+ component: TitleLayout,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = { title: 'Dummy header' };
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.js b/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.js
deleted file mode 100644
index 5faed40264..0000000000
--- a/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import React from 'react';
-import TitleLayout from '../../components/Layout/TitleLayout';
-import decorator from '../Pages/config/decorators';
-import { chromaticSmallScreen } from '../Pages/config/chromatic';
-
-export default {
- title: 'Layout/TitleLayoutWithCancel',
- decorators: decorator,
- component: TitleLayout,
-};
-
-const Template = (args) => ;
-
-export const Primary = Template.bind({});
-Primary.args = { title: 'Dummy header', onCancel: true };
-Primary.parameters = {
- ...chromaticSmallScreen,
-};
diff --git a/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.jsx b/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.jsx
new file mode 100644
index 0000000000..6e96735ba2
--- /dev/null
+++ b/packages/webapp/src/stories/TitleLayout/TitleLayoutWithCancel.stories.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import TitleLayout from '../../components/Layout/TitleLayout';
+import decorator from '../Pages/config/Decorators';
+import { chromaticSmallScreen } from '../Pages/config/chromatic';
+
+export default {
+ title: 'Layout/TitleLayoutWithCancel',
+ decorators: decorator,
+ component: TitleLayout,
+};
+
+const Template = (args) => ;
+
+export const Primary = Template.bind({});
+Primary.args = { title: 'Dummy header', onCancel: true };
+Primary.parameters = {
+ ...chromaticSmallScreen,
+};
diff --git a/packages/webapp/src/stories/Tooltip/Tooltip.stories.js b/packages/webapp/src/stories/Tooltip/Tooltip.stories.js
deleted file mode 100644
index 4b8934a656..0000000000
--- a/packages/webapp/src/stories/Tooltip/Tooltip.stories.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import React from 'react';
-import { Underlined } from '../../components/Typography';
-import OverlayTooltip from '../../components/Tooltip';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/OverlayTooltip',
- component: OverlayTooltip,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-
-export const Tooltip = Template.bind({});
-const underlined = `Why are we asking this?`;
-Tooltip.args = {
- children: (
-
- {underlined}
-
- ),
- content:
- 'LiteFarm generates forms required for organic certification. Some information will be mandatory.',
- arrowOffset: 8,
- placement: 'bottom-start',
- autoOpen: true,
-};
diff --git a/packages/webapp/src/stories/Tooltip/Tooltip.stories.jsx b/packages/webapp/src/stories/Tooltip/Tooltip.stories.jsx
new file mode 100644
index 0000000000..b6a1d0fcf7
--- /dev/null
+++ b/packages/webapp/src/stories/Tooltip/Tooltip.stories.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import { Underlined } from '../../components/Typography';
+import OverlayTooltip from '../../components/Tooltip';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/OverlayTooltip',
+ component: OverlayTooltip,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+
+export const Tooltip = Template.bind({});
+const underlined = `Why are we asking this?`;
+Tooltip.args = {
+ children: (
+
+ {underlined}
+
+ ),
+ content:
+ 'LiteFarm generates forms required for organic certification. Some information will be mandatory.',
+ arrowOffset: 8,
+ placement: 'bottom-start',
+ autoOpen: true,
+};
diff --git a/packages/webapp/src/stories/Typography/Typography.stories.js b/packages/webapp/src/stories/Typography/Typography.stories.js
deleted file mode 100644
index a5fa095305..0000000000
--- a/packages/webapp/src/stories/Typography/Typography.stories.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import React from 'react';
-import {
- AddLink,
- EditLink,
- Error,
- IconLink,
- Info,
- Label,
- Main,
- Semibold,
- Text,
- Title,
- Underlined,
-} from '../../components/Typography';
-import { componentDecorators } from '../Pages/config/decorators';
-import { FiSlash } from 'react-icons/all';
-
-export default {
- title: 'Components/Typography',
- component: Underlined,
- decorators: componentDecorators,
-};
-
-const Template = (args) => (
- <>
-
- It is preferred to use style prop to override css styles such as margin. If you pass in style
- from a stylesheet using css loader, it is not guaranteed to work as stylesheet loading order
- is unpredictable
-
- {AllFontTemplate(args)}
- >
-);
-
-const AllFontTemplate = (args) => (
- <>
-
-
-
- sm Semibold
-
-
-
- Label with sm as prop
-
-
-
-
-
-
-
-
-
-
-
-
- } />
- >
-);
-
-export const Override = Template.bind({});
-Override.args = {
- style: { marginBottom: 0, display: 'block' },
-};
-
-export const Primary = AllFontTemplate.bind({});
-Primary.args = {};
diff --git a/packages/webapp/src/stories/Typography/Typography.stories.jsx b/packages/webapp/src/stories/Typography/Typography.stories.jsx
new file mode 100644
index 0000000000..5d995a549b
--- /dev/null
+++ b/packages/webapp/src/stories/Typography/Typography.stories.jsx
@@ -0,0 +1,67 @@
+import React from 'react';
+import {
+ AddLink,
+ EditLink,
+ Error,
+ IconLink,
+ Info,
+ Label,
+ Main,
+ Semibold,
+ Text,
+ Title,
+ Underlined,
+} from '../../components/Typography';
+import { componentDecorators } from '../Pages/config/Decorators';
+import { FiSlash } from 'react-icons/all';
+
+export default {
+ title: 'Components/Typography',
+ component: Underlined,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => (
+ <>
+
+ It is preferred to use style prop to override css styles such as margin. If you pass in style
+ from a stylesheet using css loader, it is not guaranteed to work as stylesheet loading order
+ is unpredictable
+
+ {AllFontTemplate(args)}
+ >
+);
+
+const AllFontTemplate = (args) => (
+ <>
+
+
+
+ sm Semibold
+
+
+
+ Label with sm as prop
+
+
+
+
+
+
+
+
+
+
+
+
+ } />
+ >
+);
+
+export const Override = Template.bind({});
+Override.args = {
+ style: { marginBottom: 0, display: 'block' },
+};
+
+export const Primary = AllFontTemplate.bind({});
+Primary.args = {};
diff --git a/packages/webapp/src/stories/WarningBox/WarningBox.stories.js b/packages/webapp/src/stories/WarningBox/WarningBox.stories.js
deleted file mode 100644
index 928e64077d..0000000000
--- a/packages/webapp/src/stories/WarningBox/WarningBox.stories.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import PureWarningBox from '../../components/WarningBox';
-import { componentDecorators } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/WarningBox',
- component: PureWarningBox,
- decorators: componentDecorators,
-};
-
-const Template = (args) => ;
-export const Primary = Template.bind({});
-Primary.args = {
- text:
- "This feature is currently under development and may not be ready this season. However, clicking 'Yes' will turn it on for your farm when it is ready.",
-};
diff --git a/packages/webapp/src/stories/WarningBox/WarningBox.stories.jsx b/packages/webapp/src/stories/WarningBox/WarningBox.stories.jsx
new file mode 100644
index 0000000000..6b2d2f0a74
--- /dev/null
+++ b/packages/webapp/src/stories/WarningBox/WarningBox.stories.jsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import PureWarningBox from '../../components/WarningBox';
+import { componentDecorators } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/WarningBox',
+ component: PureWarningBox,
+ decorators: componentDecorators,
+};
+
+const Template = (args) => ;
+export const Primary = Template.bind({});
+Primary.args = {
+ text:
+ "This feature is currently under development and may not be ready this season. However, clicking 'Yes' will turn it on for your farm when it is ready.",
+};
diff --git a/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.js b/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.js
deleted file mode 100644
index 577a88b8bf..0000000000
--- a/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import PureWeatherBoard from '../../components/WeatherBoard';
-import { componentDecoratorsWithoutPadding } from '../Pages/config/decorators';
-
-export default {
- title: 'Components/WeatherBoard/PureWeatherBoard',
- component: PureWeatherBoard,
- decorators: componentDecoratorsWithoutPadding,
-};
-
-const Template = (args) => ;
-
-export const Rain = Template.bind({});
-
-Rain.args = {
- city: 'Vancouver',
- date: 'Wed 16 September',
- temperature: '15ºC',
- iconName: 'wi-day-rain',
- wind: 'Wind: 2 km/h',
- humidity: 'Humidity: 31%',
-};
-
-export const Sunny = Template.bind({});
-
-Sunny.args = {
- city: 'Vancouver',
- date: 'Wed 16 September',
- temperature: '15ºC',
- iconName: 'wi-day-sunny',
- wind: 'Wind: 2 km/h',
- humidity: 'Humidity: 31%',
-};
diff --git a/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.jsx b/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.jsx
new file mode 100644
index 0000000000..16cf55d1f4
--- /dev/null
+++ b/packages/webapp/src/stories/WeatherBoard/PureWeather.stories.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import PureWeatherBoard from '../../components/WeatherBoard';
+import { componentDecoratorsWithoutPadding } from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/WeatherBoard/PureWeatherBoard',
+ component: PureWeatherBoard,
+ decorators: componentDecoratorsWithoutPadding,
+};
+
+const Template = (args) => ;
+
+export const Rain = Template.bind({});
+
+Rain.args = {
+ city: 'Vancouver',
+ date: 'Wed 16 September',
+ temperature: '15ºC',
+ iconName: 'wi-day-rain',
+ wind: 'Wind: 2 km/h',
+ humidity: 'Humidity: 31%',
+};
+
+export const Sunny = Template.bind({});
+
+Sunny.args = {
+ city: 'Vancouver',
+ date: 'Wed 16 September',
+ temperature: '15ºC',
+ iconName: 'wi-day-sunny',
+ wind: 'Wind: 2 km/h',
+ humidity: 'Humidity: 31%',
+};
diff --git a/packages/webapp/src/stories/WeatherBoard/Weather.stories.js b/packages/webapp/src/stories/WeatherBoard/Weather.stories.js
deleted file mode 100644
index ae6d698f7d..0000000000
--- a/packages/webapp/src/stories/WeatherBoard/Weather.stories.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react';
-import WeatherBoard from '../../containers/WeatherBoard';
-import decorators from '../Pages/config/decorators';
-
-export default {
- title: 'Components/WeatherBoard/WeatherBoardWrapper',
- component: WeatherBoard,
- decorators,
-};
-
-const Template = (args) => ;
-
-export const English = Template.bind({});
-
-English.args = {};
-
-export const Espanol = Template.bind({});
-Espanol.args = {};
-
-English.parameters = {
- chromatic: { disable: true },
-};
-Espanol.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/WeatherBoard/Weather.stories.jsx b/packages/webapp/src/stories/WeatherBoard/Weather.stories.jsx
new file mode 100644
index 0000000000..88734fec72
--- /dev/null
+++ b/packages/webapp/src/stories/WeatherBoard/Weather.stories.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import WeatherBoard from '../../containers/WeatherBoard';
+import decorators from '../Pages/config/Decorators';
+
+export default {
+ title: 'Components/WeatherBoard/WeatherBoardWrapper',
+ component: WeatherBoard,
+ decorators,
+};
+
+const Template = (args) => ;
+
+export const English = Template.bind({});
+
+English.args = {};
+
+export const Espanol = Template.bind({});
+Espanol.args = {};
+
+English.parameters = {
+ chromatic: { disable: true },
+};
+Espanol.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.js b/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.js
deleted file mode 100644
index 193d32f890..0000000000
--- a/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React, { lazy, Suspense } from 'react';
-import text from '../../containers/Consent/locales/en/Owner.Consent.md';
-
-const Button = lazy(() => import('../../components/Form/Button'));
-const PureConsent = lazy(() => import('../../components/Consent'));
-export default {
- title: 'Bugs/suspenseTypeError',
- decorators: [(story) => {story()} ],
- component: Button,
-};
-
-const Template = (args) => ;
-
-export const LazyLoadedButton = Template.bind({});
-LazyLoadedButton.args = {
- children: 'Lazy loaded',
-};
-
-export const I18Lazyload = ({ ...args }) => (
-
-
-
-);
-
-I18Lazyload.args = {
- onSubmit: () => {},
- onGoBack: () => {},
- checkboxArgs: { label: 'I Agree' },
- text: text,
-};
-I18Lazyload.parameters = {
- chromatic: { disable: true },
-};
-LazyLoadedButton.parameters = {
- chromatic: { disable: true },
-};
diff --git a/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.jsx b/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.jsx
new file mode 100644
index 0000000000..6bb1c41190
--- /dev/null
+++ b/packages/webapp/src/stories/bugs/SuspenseTypeError.stories.jsx
@@ -0,0 +1,38 @@
+import React, { lazy, Suspense } from 'react';
+import ConsentEnglish from '../../containers/Consent/locales/en/Owner.Consent.md';
+
+const Button = lazy(() => import('../../components/Form/Button'));
+const PureConsent = lazy(() => import('../../components/Consent'));
+export default {
+ title: 'Bugs/suspenseTypeError',
+ decorators: [(story) => {story()} ],
+ component: Button,
+};
+
+const Template = (args) => ;
+
+export const LazyLoadedButton = Template.bind({});
+LazyLoadedButton.args = {
+ children: 'Lazy loaded',
+};
+
+export const I18Lazyload = ({ ...args }) => (
+
+
+
+);
+
+I18Lazyload.args = {
+ onSubmit: () => {
+ },
+ onGoBack: () => {
+ },
+ checkboxArgs: { label: 'I Agree' },
+ consent: ,
+};
+I18Lazyload.parameters = {
+ chromatic: { disable: true },
+};
+LazyLoadedButton.parameters = {
+ chromatic: { disable: true },
+};
diff --git a/packages/webapp/src/stories/docs/DocCard.js b/packages/webapp/src/stories/docs/DocCard.jsx
similarity index 100%
rename from packages/webapp/src/stories/docs/DocCard.js
rename to packages/webapp/src/stories/docs/DocCard.jsx
diff --git a/packages/webapp/src/stories/docs/DocLink.js b/packages/webapp/src/stories/docs/DocLink.jsx
similarity index 100%
rename from packages/webapp/src/stories/docs/DocLink.js
rename to packages/webapp/src/stories/docs/DocLink.jsx
diff --git a/packages/webapp/src/stories/docs/componentsToDeprecate.stories.mdx b/packages/webapp/src/stories/docs/componentsToDeprecate.stories.mdx
index fc0582af5d..39e6b91390 100644
--- a/packages/webapp/src/stories/docs/componentsToDeprecate.stories.mdx
+++ b/packages/webapp/src/stories/docs/componentsToDeprecate.stories.mdx
@@ -19,7 +19,3 @@ import { Meta } from '@storybook/addon-docs/blocks';
- BalanceBarComponent
- BiodiversitySpecies
-### Disabled components.
-
-- EditAddExpense
-- EditExpenseCategories
diff --git a/packages/webapp/src/stories/docs/teckStackNavigation.js b/packages/webapp/src/stories/docs/teckStackNavigation.jsx
similarity index 100%
rename from packages/webapp/src/stories/docs/teckStackNavigation.js
rename to packages/webapp/src/stories/docs/teckStackNavigation.jsx
diff --git a/packages/webapp/src/stories/docs/tutorial/backendUnitTest.stories.mdx b/packages/webapp/src/stories/docs/tutorial/backendUnitTest.stories.mdx
index d9775e39e0..00717cc9dc 100644
--- a/packages/webapp/src/stories/docs/tutorial/backendUnitTest.stories.mdx
+++ b/packages/webapp/src/stories/docs/tutorial/backendUnitTest.stories.mdx
@@ -85,7 +85,7 @@ async function fieldFactory({
function fakeField() {
return {
- organic_status: faker.random.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
+ organic_status: faker.helpers.arrayElement(['Non-Organic', 'Transitional', 'Organic']),
transition_date: faker.date.future(),
};
}
diff --git a/packages/webapp/src/tests/Insights/components.test.js b/packages/webapp/src/tests/Insights/components.test.js
deleted file mode 100644
index c00f9f7703..0000000000
--- a/packages/webapp/src/tests/Insights/components.test.js
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (components.test.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import React from 'react';
-import Enzyme, { shallow } from 'enzyme';
-import Adapter from 'enzyme-adapter-react-16';
-
-import { Button } from 'react-bootstrap';
-import InfoBoxComponent from '../../components/InfoBoxComponent';
-import InsightsInfoComponent from '../../components/Insights/InsightsInfoComponent';
-import { ProgressBar } from 'react-bootstrap';
-
-Enzyme.configure({ adapter: new Adapter() });
-
-describe('Info Box Component Tests', () => {
- const showSave = true;
- const saveHandler = jest.fn();
-
- const showDelete = true;
- const deleteHandler = jest.fn();
- let wrapper;
-
- beforeEach(() => {
- wrapper = shallow(
- ,
- );
- });
-
- afterEach(() => {
- saveHandler.mockReset();
- deleteHandler.mockReset();
- });
-
- it('Info Box With No Save Button Shown', () => {
- wrapper.setProps({ showSave: false });
- expect(wrapper.find(Button).length).toBe(2);
- });
-
- it('Info Box with No Delete Button Shown', () => {
- wrapper.setProps({ showDelete: false });
- expect(wrapper.find(Button).length).toBe(2);
- });
-
- it('Info Box with Both Save and Delete Shown', () => {
- expect(wrapper.find(Button).length).toBe(3);
- });
-
- it('Info Box Save Handler Simulate Function', () => {
- const x = saveHandler();
- expect(x).toBeUndefined();
- expect(saveHandler).toHaveBeenCalledTimes(1);
- });
-
- it('Info Box Delete Handler Simulate Function', () => {
- const x = deleteHandler();
- expect(x).toBeUndefined();
- expect(deleteHandler).toHaveBeenCalledTimes(1);
- });
-});
-
-describe('People Fed Info Component Tests', () => {
- let wrapper;
- beforeEach(() => {
- wrapper = shallow( );
- });
-
- it('Feeding in Percent Should display it in my ProgressBar Props', () => {
- const progress = 12;
- wrapper.setProps({ percent: progress });
- expect(wrapper.find(ProgressBar).prop('now')).toBe(12);
- });
-});
diff --git a/packages/webapp/src/tests/outro.test.js b/packages/webapp/src/tests/outro.test.js
deleted file mode 100644
index 3f49ec2816..0000000000
--- a/packages/webapp/src/tests/outro.test.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (components.test.js) is part of LiteFarm.
- *
- * LiteFarm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * LiteFarm is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details, see .
- */
-
-import { takeEvery } from 'redux-saga/effects';
-import { patchOutroStepSaga } from '../containers/Outro/saga';
-
-describe('patchOutroStep', () => {
- const genObject = patchOutroStepSaga();
-
- it('should wait for FINISH_ONBOARDING action and call patchOutroStepSaga', () => {
- expect(genObject.next().value).toEqual(takeEvery('FINISH_ONBOARDING', patchOutroStepSaga));
- });
-});
diff --git a/packages/webapp/src/tests/utils.js b/packages/webapp/src/tests/utils.js
deleted file mode 100644
index 6ae18caed0..0000000000
--- a/packages/webapp/src/tests/utils.js
+++ /dev/null
@@ -1,21 +0,0 @@
-// FROM: https://redux.js.org/recipes/writing-tests#connected-components
-import React from 'react';
-import { render as rtlRender } from '@testing-library/react';
-import { createStore } from 'redux';
-import { Provider } from 'react-redux';
-import reducer from '../reducer';
-
-function render(
- ui,
- { initialState, store = createStore(reducer, initialState), ...renderOptions } = {},
-) {
- function Wrapper({ children }) {
- return {children} ;
- }
- return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
-}
-
-// re-export everything
-export * from '@testing-library/react';
-// override render method
-export { render };
diff --git a/packages/webapp/src/util/constants.js b/packages/webapp/src/util/constants.js
index c9478cc127..6b6cd12e8b 100644
--- a/packages/webapp/src/util/constants.js
+++ b/packages/webapp/src/util/constants.js
@@ -1,4 +1,8 @@
export const DO_URI = 'nyc3.digitaloceanspaces.com';
-export const DO_ORIGIN_URL = `https://${process.env.REACT_APP_DO_BUCKET_NAME}.nyc3.digitaloceanspaces.com`;
-export const DO_CDN_URL = `https://${process.env.REACT_APP_DO_BUCKET_NAME}.nyc3.cdn.digitaloceanspaces.com`;
-export const APP_VERSION = '3.1.1';
+export const DO_ORIGIN_URL = `https://${
+ import.meta.env.VITE_DO_BUCKET_NAME
+}.nyc3.digitaloceanspaces.com`;
+export const DO_CDN_URL = `https://${
+ import.meta.env.VITE_DO_BUCKET_NAME
+}.nyc3.cdn.digitaloceanspaces.com`;
+export const APP_VERSION = '3.2.0';
diff --git a/packages/webapp/src/util/convert-units/convert.ts b/packages/webapp/src/util/convert-units/convert.ts
new file mode 100644
index 0000000000..b8f8387444
--- /dev/null
+++ b/packages/webapp/src/util/convert-units/convert.ts
@@ -0,0 +1,3 @@
+import configureMeasurements, { allMeasures } from 'convert-units';
+
+export const convert = (number: number) => configureMeasurements(allMeasures)(Number(number) || undefined);
diff --git a/packages/webapp/src/util/unit.js b/packages/webapp/src/util/convert-units/unit.js
similarity index 98%
rename from packages/webapp/src/util/unit.js
rename to packages/webapp/src/util/convert-units/unit.js
index c6d2f2069a..9c3e64900b 100644
--- a/packages/webapp/src/util/unit.js
+++ b/packages/webapp/src/util/convert-units/unit.js
@@ -1,5 +1,5 @@
-import convert from 'convert-units';
-import { getUnitOptionMap } from '../components/Form/Unit';
+import { getUnitOptionMap } from '../../components/Form/Unit';
+import { convert } from './convert';
const METRIC = 'metric';
const IMPERIAL = 'imperial';
@@ -173,7 +173,7 @@ export const soilAmounts = {
metric: {
units: ['g', 'kg', 'mt'],
defaultUnit: 'kg',
- breakpoints: [1000],
+ breakpoints: [1, 1000],
},
imperial: {
units: ['oz', 'lb', 't'],
diff --git a/packages/webapp/src/util/grabCurrencySymbol.js b/packages/webapp/src/util/grabCurrencySymbol.js
index 740b1a87a5..17eefac7e1 100644
--- a/packages/webapp/src/util/grabCurrencySymbol.js
+++ b/packages/webapp/src/util/grabCurrencySymbol.js
@@ -1,4 +1,4 @@
-import { getCurrencyFromStore } from './getFromReduxStore';
+import { getCurrencyFromStore } from '../store/getFromReduxStore';
import commonCurrency from '../containers/AddFarm/currency/commonCurrency.json';
export default function grabCurrencySymbol(currency = getCurrencyFromStore()) {
diff --git a/packages/webapp/src/util/index.js b/packages/webapp/src/util/index.js
index cdab637999..c7eb9f98a0 100644
--- a/packages/webapp/src/util/index.js
+++ b/packages/webapp/src/util/index.js
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2007 Free Software Foundation, Inc.
- * This file (index.js) is part of LiteFarm.
+ * Copyright 2019-2022 LiteFarm.org
+ * This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -13,8 +13,8 @@
* GNU General Public License for more details, see .
*/
-import convert from 'convert-units';
-import { getMeasurementFromStore } from './getFromReduxStore';
+import { convert } from './convert-units/convert';
+import { getMeasurementFromStore } from '../store/getFromReduxStore';
const METRIC = 'metric';
// const IMPERIAL = 'IMPERIAL';
@@ -52,7 +52,7 @@ export const roundToFourDecimal = (value) => {
};
export const roundToTwoDecimal = (value) => {
- return Math.floor(value * 100) / 100;
+ return Math.round(value * 100) / 100;
};
const getConvertedString = (
@@ -65,9 +65,8 @@ const getConvertedString = (
) => {
return measurement === METRIC
? `${value} ${metricSymbol ? metricSymbol : convertUnitMetric}`
- : `${Math.round(convert(value).from(convertUnitMetric).to(convertUnitImperial))} ${
- imperialSymbol ? imperialSymbol : convertUnitImperial
- }`;
+ : `${Math.round(convert(value).from(convertUnitMetric).to(convertUnitImperial))} ${imperialSymbol ? imperialSymbol : convertUnitImperial
+ }`;
};
export const getFirstNameLastName = (fullName) => {
diff --git a/packages/webapp/src/util/jwt.js b/packages/webapp/src/util/jwt.js
index dd4a254457..9f74f68a26 100644
--- a/packages/webapp/src/util/jwt.js
+++ b/packages/webapp/src/util/jwt.js
@@ -1,5 +1,5 @@
-import { purgeState } from '../index';
import history from '../history';
+import { purgeState } from '../store/store';
export const getAccessToken = () => {
return localStorage.getItem('id_token');
diff --git a/packages/webapp/src/util/moment.js b/packages/webapp/src/util/moment.js
index d875fcee02..d57424f6f0 100644
--- a/packages/webapp/src/util/moment.js
+++ b/packages/webapp/src/util/moment.js
@@ -6,7 +6,14 @@ import { getLanguageFromLocalStorage } from './getLanguageFromLocalStorage';
* @param date
* @return {string}
*/
-export const getDateInputFormat = (date) => moment(date).utc().format('YYYY-MM-DD');
+export const getDateInputFormat = (date) => moment(date).format('YYYY-MM-DD');
+
+/**
+ *
+ * @param date{string}
+ * @return {string}
+ */
+export const getDateFromDateTimeString = (date) => date.split('T')[0];
/**
*
@@ -45,18 +52,22 @@ export const addDaysToDate = (date, days, { toUTC = true } = {}) => {
*/
export const getLocalizedDateString = (date, format = 'MMMM DD, YYYY') =>
moment(date).locale(getLanguageFromLocalStorage()).format(format);
+
/**
*
* @param date
* @returns {string}
*/
export const getManagementPlanCardDate = (date) =>
- moment(date).locale(getLanguageFromLocalStorage()).utc().format(`MMM DD,'YY`);
+ moment(date).locale(getLanguageFromLocalStorage()).format(`MMM DD,'YY`);
export const getManagementPlanTileDate = (date) =>
- moment(date).locale(getLanguageFromLocalStorage()).utc().format(`MMM DD,'YY`);
+ moment(date).locale(getLanguageFromLocalStorage()).format(`MMM DD,'YY`);
export const getTaskCardDate = (date) =>
- moment(date).locale(getLanguageFromLocalStorage()).utc().format('MMM D, YYYY');
+ moment(date).locale(getLanguageFromLocalStorage()).format('MMM D, YYYY');
+
+export const getNotificationCardDate = (date) =>
+ moment(date).locale(getLanguageFromLocalStorage()).format('MM/DD/YY');
-export const getCurrentDateLong = (date) => moment().utc().format('L');
+export const getCurrentDateLong = (date) => moment().format('L');
diff --git a/packages/webapp/src/util/pick.js b/packages/webapp/src/util/pick.ts
similarity index 100%
rename from packages/webapp/src/util/pick.js
rename to packages/webapp/src/util/pick.ts
diff --git a/packages/webapp/src/vite-env.d.ts b/packages/webapp/src/vite-env.d.ts
new file mode 100644
index 0000000000..11f02fe2a0
--- /dev/null
+++ b/packages/webapp/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/packages/webapp/tsconfig.json b/packages/webapp/tsconfig.json
new file mode 100644
index 0000000000..35906f09c5
--- /dev/null
+++ b/packages/webapp/tsconfig.json
@@ -0,0 +1,31 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "useDefineForClassFields": true,
+ "lib": [
+ "DOM",
+ "DOM.Iterable",
+ "ESNext"
+ ],
+ "allowJs": false,
+ "skipLibCheck": false,
+ "esModuleInterop": false,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "module": "ESNext",
+ "moduleResolution": "Node",
+ "resolveJsonModule": true,
+ "isolatedModules": false,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "types": [
+ "vite/client",
+ "vite-plugin-svgr/client",
+ "@emotion/react/types/css-prop"
+ ]
+ },
+ "include": [
+ "./src"
+ ]
+}
diff --git a/packages/webapp/vite.config.ts b/packages/webapp/vite.config.ts
new file mode 100644
index 0000000000..84d914c023
--- /dev/null
+++ b/packages/webapp/vite.config.ts
@@ -0,0 +1,34 @@
+import { defineConfig } from 'vite';
+import react from '@vitejs/plugin-react';
+import mdx from 'vite-plugin-mdx';
+// @ts-ignore
+import svgrPlugin from 'vite-plugin-svgr';
+import IstanbulPlugin from 'vite-plugin-istanbul';
+
+// https://vitejs.dev/config/
+export default defineConfig(({ mode }) => ({
+ plugins: [
+ react({
+ babel: {
+ plugins: ['@emotion/babel-plugin'],
+ },
+ jsxRuntime: mode === 'development' ? 'automatic' : 'classic',
+ }),
+ mdx(),
+ svgrPlugin({
+ svgrOptions: {
+ icon: false,
+ },
+ }),
+ IstanbulPlugin({
+ include: 'src/*',
+ exclude: ['node_modules', 'tests/'],
+ extension: [ '.js', '.ts', '.jsx' ],
+ requireEnv: true,
+ cypress: true,
+ }),
+ ],
+ build: {
+ sourcemap: true,
+ },
+}));