diff --git a/.circleci/config.yml b/.circleci/config.yml index ed03863f..89b6efa1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -77,6 +77,7 @@ workflows: branches: only: - dev + - dev-1_5 # Production builds are exectuted only on tagged commits to the # master branch. diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..ea4cddfc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "javascript.preferences.quoteStyle": "double", + "typescript.preferences.quoteStyle": "double", + "prettier.jsxSingleQuote": false +} diff --git a/README.md b/README.md index aa44f185..4a827f43 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ This is a [single-spa](https://single-spa.js.org/) example React microapp. ## Config -For available variables config which depend on the running environment (`development` or `production`), please refer to `config/development.js` and `config/production.js`. +For available variables config which depend on the running environment (`APPENV=dev` or `APPENV=prod`), please refer to `config/dev.js` and `config/prod.js`. For application constants which don't depend on the running environment use `src/constants/index.js`. diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..07815e13 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,59 @@ +module.exports = function (api) { + const isProd = process.env.APPMODE === "production"; + api.cache(!isProd); + + const generateScopedName = isProd + ? "[hash:base64:6]" + : "teams_[path][name]___[local]___[hash:base64:6]"; + return { + presets: ["@babel/preset-env", "@babel/preset-react"], + plugins: [ + [ + "@babel/plugin-transform-runtime", + { + useESModules: true, + regenerator: false, + }, + ], + [ + "react-css-modules", + { + filetypes: { + ".scss": { + syntax: "postcss-scss", + }, + }, + generateScopedName, + }, + ], + "inline-react-svg", + ], + env: { + test: { + presets: [ + [ + "@babel/preset-env", + { + targets: "current node", + }, + ], + ], + plugins: [ + [ + "module-resolver", + { + alias: { + styles: "./src/styles", + components: "./src/components", + hooks: "./src/hooks", + utils: "./src/utils", + constants: "./src/constants", + services: "./src/services", + }, + }, + ], + ], + }, + }, + }; +}; diff --git a/babel.config.json b/babel.config.json deleted file mode 100644 index 00432fb5..00000000 --- a/babel.config.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "plugins": [ - [ - "@babel/plugin-transform-runtime", - { - "useESModules": true, - "regenerator": false - } - ], - [ - "react-css-modules", - { - "filetypes": { - ".scss": { - "syntax": "postcss-scss" - } - }, - "generateScopedName": "teams_[path][name]___[local]___[hash:base64:6]" - } - ], - "inline-react-svg" - ], - "env": { - "test": { - "presets": [ - [ - "@babel/preset-env", - { - "targets": "current node" - } - ] - ], - "plugins": [ - ["module-resolver", { - "alias": { - "styles": "./src/styles", - "components": "./src/components", - "hooks": "./src/hooks", - "utils": "./src/utils", - "constants": "./src/constants", - "services": "./src/services" - } - }] - ] - } - } -} diff --git a/config/development.js b/config/dev.js similarity index 79% rename from config/development.js rename to config/dev.js index a7ba676c..54870756 100644 --- a/config/development.js +++ b/config/dev.js @@ -9,11 +9,6 @@ module.exports = { */ CONNECT_WEBSITE_URL: "https://connect.topcoder-dev.com", - /** - * Email to report issues to - */ - EMAIL_REPORT_ISSUE: "support+team-issue@topcoder-dev.com", - /** * Email to request extension */ @@ -21,5 +16,6 @@ module.exports = { API: { V5: "https://api.topcoder-dev.com/v5", + V3: "https://api.topcoder-dev.com/v3", }, }; diff --git a/config/index.js b/config/index.js index d89d9220..4cbf464b 100644 --- a/config/index.js +++ b/config/index.js @@ -1,11 +1,13 @@ /* global process */ module.exports = (() => { - const env = process.env.NODE_ENV || "development"; + const env = process.env.APPENV || "dev"; + + console.info(`APPENV: "${env}"`); // for security reason don't let to require any arbitrary file defined in process.env - if (["production", "development"].indexOf(env) < 0) { - return require("./development"); + if (["prod", "dev"].indexOf(env) < 0) { + return require("./dev"); } return require("./" + env); diff --git a/config/production.js b/config/prod.js similarity index 79% rename from config/production.js rename to config/prod.js index a37c8a33..e2069074 100644 --- a/config/production.js +++ b/config/prod.js @@ -9,11 +9,6 @@ module.exports = { */ CONNECT_WEBSITE_URL: "https://connect.topcoder.com", - /** - * Email to report issues to - */ - EMAIL_REPORT_ISSUE: "support+team-issue@topcoder.com", - /** * Email to request extension */ @@ -21,5 +16,6 @@ module.exports = { API: { V5: "https://api.topcoder.com/v5", + V3: "https://api.topcoder.com/v3", }, }; diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 775da25a..0affbdfc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: "3" services: taas-app: image: taas-app:latest diff --git a/package-lock.json b/package-lock.json index 422e1d0a..84f77334 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1174,6 +1174,81 @@ "minimist": "^1.2.0" } }, + "@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" + }, + "dependencies": { + "stylis": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.7.tgz", + "integrity": "sha512-OFFeUXFgwnGOKvEXaSv0D0KQ5ADP0n6g3SVONx6I/85JzNZ3u50FRwB3lVIk1QO2HNdI75tbVzc4Z66Gdp9voA==" + } + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "@emotion/react": { + "version": "11.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" + } + }, + "@emotion/serialize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.0.tgz", + "integrity": "sha512-zt1gm4rhdo5Sry8QpCOpopIUIKU+mUSpV9WNmFILUraatm5dttNEaYzUWWSboSMUE6PtN2j1cAsuvcugfdI3mw==", + "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/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@emotion/utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz", + "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2725,6 +2800,15 @@ "@types/testing-library__react": "^9.1.2" } }, + "@toast-ui/editor": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@toast-ui/editor/-/editor-2.5.1.tgz", + "integrity": "sha512-LVNo/YaNItUemEaRFvFAVn7w/0U7yxEheMdn6GEGxqo727rRZD1MH7OTDVq6NeQ+P93VwFpa0i9GGRBhNNEbPQ==", + "requires": { + "@types/codemirror": "0.0.71", + "codemirror": "^5.48.4" + } + }, "@types/anymatch": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", @@ -2772,6 +2856,19 @@ "@babel/types": "^7.3.0" } }, + "@types/codemirror": { + "version": "0.0.71", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-0.0.71.tgz", + "integrity": "sha512-b2oEEnno1LIGKMR7uBEsr40al1UijF1HEpRn0+Yf1xOLl24iQgB7DBpZVMM7y54G5wCNoclDrRO65E6KHPNO2w==", + "requires": { + "@types/tern": "*" + } + }, + "@types/estree": { + "version": "0.0.46", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz", + "integrity": "sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==" + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -2916,6 +3013,14 @@ "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", "dev": true }, + "@types/tern": { + "version": "0.23.3", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.3.tgz", + "integrity": "sha512-imDtS4TAoTcXk0g7u4kkWqedB3E4qpjXzCpD2LU5M5NAXHzCDsypyvXSaG7mM8DKYkCRa7tFp4tS/lp/Wo7Q3w==", + "requires": { + "@types/estree": "*" + } + }, "@types/testing-library__dom": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/testing-library__dom-6.14.0.tgz", @@ -4239,6 +4344,11 @@ } } }, + "body-scroll-lock": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/body-scroll-lock/-/body-scroll-lock-3.1.5.tgz", + "integrity": "sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg==" + }, "bonjour": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", @@ -4680,7 +4790,8 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "dev": true, + "optional": true }, "to-regex-range": { "version": "5.0.1", @@ -4861,6 +4972,11 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "codemirror": { + "version": "5.59.3", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.59.3.tgz", + "integrity": "sha512-p1d4BjmBBssgnEGtQeWvE5PdiDffqZjiJ77h2FZ2J2BpW9qdOzf6v7IQscyE+TgyKBQS3PpsYimfEDNgcNRZGQ==" + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -5626,8 +5742,7 @@ "csstype": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz", - "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==", - "dev": true + "integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==" }, "currently-unhandled": { "version": "0.4.1", @@ -5683,8 +5798,7 @@ "date-fns": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", - "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", - "dev": true + "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==" }, "debug": { "version": "4.2.0", @@ -5716,7 +5830,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, "requires": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -5943,6 +6056,15 @@ "integrity": "sha512-PzwHEmsRP3IGY4gv/Ug+rMeaTIyTJvadCb+ujYXYeIylbHJezIyNToe8KfEgHTCEYyC+/bUghYOGg8yMGlZ6vA==", "dev": true }, + "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" + } + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -6983,6 +7105,14 @@ } } }, + "final-form": { + "version": "4.20.1", + "resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.1.tgz", + "integrity": "sha512-IIsOK3JRxJrN72OBj7vFWZxtGt3xc1bYwJVPchjVWmDol9DlzMSAOPB+vwe75TUYsw1JaH0fTQnIgwSQZQ9Acg==", + "requires": { + "@babel/runtime": "^7.10.0" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -8265,8 +8395,7 @@ "is-arguments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", - "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", - "dev": true + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==" }, "is-arrayish": { "version": "0.2.1", @@ -12157,6 +12286,11 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, "memory-fs": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", @@ -12509,6 +12643,14 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, + "moment-timezone": { + "version": "0.5.33", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.33.tgz", + "integrity": "sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==", + "requires": { + "moment": ">= 2.9.0" + } + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -13542,6 +13684,11 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -14255,6 +14402,42 @@ } } }, + "react-datepicker": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-3.4.1.tgz", + "integrity": "sha512-ASyVb7UmVx1vzeITidD7Cr/EXRXhKyjjbSkBndPc1MipYq4rqQ3eMFgvRQzpsXc3JmIMFgICm7nmN6Otc1GE/Q==", + "requires": { + "classnames": "^2.2.6", + "date-fns": "^2.0.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.9.0", + "react-popper": "^1.3.4" + }, + "dependencies": { + "react-popper": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz", + "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==", + "requires": { + "@babel/runtime": "^7.1.2", + "create-react-context": "^0.3.0", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + } + }, + "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" + } + } + } + }, "react-dom": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", @@ -14271,6 +14454,32 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, + "react-final-form": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.2.tgz", + "integrity": "sha512-c5l45FYOoxtfpvsvMFh3w2WW8KNxbuebBUrM16rUrooQkewTs0Zahmv0TuKFX5jsC9BKn5Fo84j3ZVXQdURS4w==", + "requires": { + "@babel/runtime": "^7.12.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.13.tgz", + "integrity": "sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "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-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -14281,6 +14490,19 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-loader-spinner": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/react-loader-spinner/-/react-loader-spinner-4.0.0.tgz", + "integrity": "sha512-RU2vpEej6G4ECei0h3q6bgLU10of9Lw5O+4AwF/mtkrX5oY20Sh/AxoPJ7etbrs/7Q3u4jN5qwCwGLRKCHpk6g==", + "requires": { + "prop-types": "^15.7.2" + } + }, + "react-onclickoutside": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.10.0.tgz", + "integrity": "sha512-7i2L3ef+0ILXpL6P+Hg304eCQswh4jl3ynwR71BSlMU49PE2uk31k8B2GkP6yE9s2D4jTGKnzuSpzWxu4YxfQQ==" + }, "react-outside-click-handler": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz", @@ -14350,6 +14572,50 @@ } } }, + "react-responsive-modal": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/react-responsive-modal/-/react-responsive-modal-6.0.1.tgz", + "integrity": "sha512-9p1qPhs9C3G3l3zA2E9yCImZ/99AmdQu0WIbiE6/rLehsdiPsMQP7RyhySy7RHanTbpPZp5dRQt7iEJMFk5z6Q==", + "requires": { + "body-scroll-lock": "^3.1.5", + "classnames": "^2.2.6" + } + }, + "react-select": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-4.1.0.tgz", + "integrity": "sha512-OYn+jL8TXMMaZtosErpkdvoI1UWN4ZqMFulIRp5r5bbuqe4OaZN7yv1BNq7PdAJgRu2E19ODFiV1SgJ6wPUaeA==", + "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": { + "@babel/runtime": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.13.tgz", + "integrity": "sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, + "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" + } + }, "react-universal-interface": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/react-universal-interface/-/react-universal-interface-0.6.2.tgz", @@ -14529,7 +14795,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -14539,7 +14804,6 @@ "version": "1.17.7", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, "requires": { "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", @@ -16193,6 +16457,13 @@ } } }, + "tc-auth-lib": { + "version": "github:topcoder-platform/tc-auth-lib#68fdc22464810c51b703a33e529cdbd6d09437de", + "from": "github:topcoder-platform/tc-auth-lib#1.0.4", + "requires": { + "lodash": "^4.17.19" + } + }, "terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -16507,6 +16778,11 @@ "mime-types": "~2.1.24" } }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package.json b/package.json index 3a16e2cc..cf19d263 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "start": "node server.js", "dev": "webpack-dev-server --port 8501 --host 0.0.0.0", "dev-https": "webpack-dev-server --https --port 8501 --host 0.0.0.0", - "build": "webpack --mode=${APPMODE:-development} --env.config=${APPENV:-dev}", + "build": "webpack --mode=${APPMODE:-production} --env.config=${APPENV:-prod}", "analyze": "webpack --mode=production --env.analyze=true", "lint": "eslint src --ext js", "format": "prettier --write \"./**\"", @@ -56,25 +56,34 @@ "dependencies": { "@popperjs/core": "^2.5.4", "@reach/router": "^1.3.4", + "@toast-ui/editor": "^2.5.1", "axios": "^0.21.0", "classnames": "^2.2.6", "express": "^4.17.1", + "final-form": "^4.20.1", "immutability-helper": "^3.1.1", "lodash": "^4.17.20", "moment": "^2.29.1", + "moment-timezone": "^0.5.33", "prop-types": "^15.7.2", "react": "^16.12.0", "react-avatar": "^3.9.7", + "react-datepicker": "^3.4.1", "react-dom": "^16.12.0", + "react-final-form": "^6.5.2", + "react-loader-spinner": "^4.0.0", "react-outside-click-handler": "^1.3.0", "react-popper": "^2.2.3", "react-redux": "^7.2.2", "react-redux-toastr": "^7.6.5", + "react-responsive-modal": "^6.0.1", + "react-select": "^4.0.2", "react-use": "^15.3.4", "redux": "^4.0.5", "redux-logger": "^3.0.6", "redux-promise-middleware": "^6.1.2", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.4" }, "browserslist": [ "last 1 version", diff --git a/server.js b/server.js index 81f5c040..0753bddd 100644 --- a/server.js +++ b/server.js @@ -4,7 +4,8 @@ const express = require("express"); const app = express(); -app.use('/taas-app', +app.use( + "/taas-app", express.static("./dist", { setHeaders: function setHeaders(res) { res.header("Access-Control-Allow-Origin", "*"); @@ -17,9 +18,9 @@ app.use('/taas-app', }) ); -app.get('/', function (req, res) { - res.send('alive') -}) +app.get("/", function (req, res) { + res.send("alive"); +}); const PORT = process.env.PORT || 8501; app.listen(PORT); diff --git a/src/assets/images/icon-bag.svg b/src/assets/images/icon-bag.svg new file mode 100644 index 00000000..b15a9ec3 --- /dev/null +++ b/src/assets/images/icon-bag.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-computer.svg b/src/assets/images/icon-computer.svg new file mode 100644 index 00000000..2ac66471 --- /dev/null +++ b/src/assets/images/icon-computer.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-cross-light.svg b/src/assets/images/icon-cross-light.svg new file mode 100644 index 00000000..8f9ee96f --- /dev/null +++ b/src/assets/images/icon-cross-light.svg @@ -0,0 +1,16 @@ + + + D450CF0B-B6EF-4991-8E48-E34846C2F842 + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-description.svg b/src/assets/images/icon-description.svg new file mode 100644 index 00000000..185971e0 --- /dev/null +++ b/src/assets/images/icon-description.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-direct-arrow.svg b/src/assets/images/icon-direct-arrow.svg new file mode 100644 index 00000000..ec13f0d0 --- /dev/null +++ b/src/assets/images/icon-direct-arrow.svg @@ -0,0 +1,11 @@ + + + + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-money.svg b/src/assets/images/icon-money.svg index 198a0932..8e1fa9b5 100644 --- a/src/assets/images/icon-money.svg +++ b/src/assets/images/icon-money.svg @@ -1,9 +1,9 @@ - - - + + + @@ -12,4 +12,4 @@ - + \ No newline at end of file diff --git a/src/assets/images/icon-moon.svg b/src/assets/images/icon-moon.svg new file mode 100644 index 00000000..12cc3e46 --- /dev/null +++ b/src/assets/images/icon-moon.svg @@ -0,0 +1,13 @@ + + + + moon + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-openings.svg b/src/assets/images/icon-openings.svg new file mode 100644 index 00000000..f713e013 --- /dev/null +++ b/src/assets/images/icon-openings.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-skill.svg b/src/assets/images/icon-skill.svg new file mode 100644 index 00000000..9b79ee65 --- /dev/null +++ b/src/assets/images/icon-skill.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/icon-sun.svg b/src/assets/images/icon-sun.svg new file mode 100644 index 00000000..f2f3a517 --- /dev/null +++ b/src/assets/images/icon-sun.svg @@ -0,0 +1,13 @@ + + + + daylight + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/src/components/ActionsMenu/index.jsx b/src/components/ActionsMenu/index.jsx index 5100d570..b888ade0 100644 --- a/src/components/ActionsMenu/index.jsx +++ b/src/components/ActionsMenu/index.jsx @@ -4,6 +4,7 @@ * Shows dropdown menu with actions. */ import React, { useState, useCallback } from "react"; +import _ from "lodash"; import PT from "prop-types"; import "./styles.module.scss"; import OutsideClickHandler from "react-outside-click-handler"; @@ -89,7 +90,7 @@ const ActionsMenu = ({ options = [] }) => { {...attributes.popper} >
- {options.map((option, index) => { + {_.reject(options, "hidden").map((option, index) => { if (option.separator) { return
; } else { @@ -124,6 +125,7 @@ ActionsMenu.propTypes = { label: PT.string, action: PT.func, separator: PT.bool, + hidden: PT.bool, }) ), }; diff --git a/src/components/ActionsMenu/styles.module.scss b/src/components/ActionsMenu/styles.module.scss index e0024961..c9556de7 100644 --- a/src/components/ActionsMenu/styles.module.scss +++ b/src/components/ActionsMenu/styles.module.scss @@ -39,7 +39,7 @@ } .option { - color: #0D61BF; + color: #0d61bf; cursor: pointer; font-size: 14px; line-height: 20px; diff --git a/src/components/AsyncSelect/index.jsx b/src/components/AsyncSelect/index.jsx new file mode 100644 index 00000000..269ad803 --- /dev/null +++ b/src/components/AsyncSelect/index.jsx @@ -0,0 +1,111 @@ +/** + * AsyncSelect + * + * A wrapper for react-select's AsyncCreatableSelect. + */ +import React from "react"; +import PT from "prop-types"; +import AsyncCreatableSelect from "react-select/async-creatable"; +import "./styles.module.scss"; + +const AsyncSelect = (props) => { + const customStyles = { + control: (provided, state) => ({ + ...provided, + minHeight: "40px", + border: "1px solid #aaaaab", + borderColor: state.isFocused ? "#55a5ff" : "#aaaaab", + boxShadow: state.isFocused ? "0 0 2px 1px #cee6ff" : provided.boxShadow, + }), + menu: (provided) => ({ + ...provided, + minHeight: "40px", + zIndex: 10, + }), + valueContainer: (provided) => ({ + ...provided, + padding: "2px 6px", + }), + input: (provided) => ({ + ...provided, + margin: "0px", + height: "auto", + padding: "0", + }), + indicatorSeparator: () => ({ + display: "none", + }), + indicatorsContainer: (provided) => ({ + ...provided, + height: "auto", + }), + option: (provided) => ({ + ...provided, + minHeight: "32px", + }), + placeholder: (provided) => ({ + ...provided, + color: "#AAAAAA", + fontFamily: "Roboto", + fontSize: "14px", + lineHeight: "22px", + textAlign: "left", + fontWeight: "400", + }), + multiValue: (provided) => ({ + ...provided, + margin: "3px 3px", + color: "#AAAAAA", + fontFamily: "Roboto", + fontSize: "14px", + lineHeight: "22px", + textAlign: "left", + borderRadius: "5px", + }), + dropdownIndicator: () => ({ + display: "none", + }), + }; + + return ( +
+ props.noOptionsText} + loadingMessage={() => props.loadingText} + isDisabled={props.disabled} + cacheOptions={props.cacheOptions} + loadOptions={props.loadOptions} + defaultOptions={props.defaultOptions} + /> +
+ ) +} + +AsyncSelect.propTypes = { + value: PT.string, + onChange: PT.func, + placeholder: PT.string, + error: PT.string, + isMulti: PT.bool, + onBlur: PT.func, + onFocus: PT.func, + onInputChange: PT.func, + cacheOptions: PT.bool, + onInputChange: PT.func, + noOptionsText: PT.string, + loadingText: PT.string, + loadOptions: PT.func, + defaultOptions: PT.bool || PT.array, + disabled: PT.bool, +} + +export default AsyncSelect; \ No newline at end of file diff --git a/src/components/AsyncSelect/styles.module.scss b/src/components/AsyncSelect/styles.module.scss new file mode 100644 index 00000000..96ffd0d3 --- /dev/null +++ b/src/components/AsyncSelect/styles.module.scss @@ -0,0 +1,18 @@ +.error { + :first-child { + border-color: #ff5b52; + } +} + +.select-wrapper { + input { + border: none !important; + box-shadow: none !important; + transition: none !important; + height: 28px; + } +} + +.react-select__option { + min-height: 32px; +} diff --git a/src/components/AvatarGroup/styles.module.scss b/src/components/AvatarGroup/styles.module.scss index d9d5aa2e..54d41108 100644 --- a/src/components/AvatarGroup/styles.module.scss +++ b/src/components/AvatarGroup/styles.module.scss @@ -14,10 +14,10 @@ .rest-count { align-items: center; - border: 1px solid #0D61BF; + border: 1px solid #0d61bf; border-radius: 100%; box-sizing: border-box; - color: #0D61BF; + color: #0d61bf; display: flex; font-size: 14px; height: 40px; diff --git a/src/components/Badge/index.jsx b/src/components/Badge/index.jsx new file mode 100644 index 00000000..a97a6bc7 --- /dev/null +++ b/src/components/Badge/index.jsx @@ -0,0 +1,22 @@ +/** + * Badge + * + * - type - see BADGE_TYPE values + * + */ +import React from "react"; +import PT from "prop-types"; +import cn from "classnames"; +import { BADGE_TYPE } from "constants"; +import "./styles.module.scss"; + +const Badge = ({ children, type = BADGE_TYPE.PRIMARY }) => { + return {children}; +}; + +Badge.propTypes = { + children: PT.node, + type: PT.oneOf(Object.values(BADGE_TYPE)), +}; + +export default Badge; diff --git a/src/components/Badge/styles.module.scss b/src/components/Badge/styles.module.scss new file mode 100644 index 00000000..0c12a55b --- /dev/null +++ b/src/components/Badge/styles.module.scss @@ -0,0 +1,21 @@ +@import "styles/include"; + +.badge { + @include font-roboto; + padding: 0 8px; + line-height: 20px; + border-radius: 5px; + height: 20px; + color: #ffffff; + font-size: 12px; + letter-spacing: 0.5px; + text-align: left; +} + +.type-primary { + background-color: #0ab88a; +} + +.type-danger { + background-color: #ef476f; +} diff --git a/src/components/BaseModal/index.jsx b/src/components/BaseModal/index.jsx new file mode 100644 index 00000000..e0bf5a83 --- /dev/null +++ b/src/components/BaseModal/index.jsx @@ -0,0 +1,77 @@ +/** + * BaseModal + * + * Wraps the react-responsive-modal + * and adds the app's style + * + * Supports title and action button + * children are displayed as modal content + */ + +import React from "react"; +import PT from "prop-types"; +import { Modal } from "react-responsive-modal"; +import Button from "../Button"; +import IconCross from "../../assets/images/icon-cross-light.svg"; +import "./styles.module.scss"; + +const modalStyle = { + borderRadius: "8px", + padding: "32px 32px 22px 32px", + maxWidth: "640px", + width: "100%", + margin: 0, +}; + +const containerStyle = { + padding: "10px", +}; + +function BaseModal({ + open, + onClose, + children, + title, + button, + disabled, + extraModalStyle, +}) { + return ( + } + styles={{ + modal: { ...modalStyle, ...extraModalStyle }, + modalContainer: containerStyle, + }} + center={true} + > + {title &&

{title}

} +
{children}
+
+ {button && button} + +
+
+ ); +} + +BaseModal.propTypes = { + open: PT.bool.isRequired, + onClose: PT.func.isRequired, + children: PT.node, + title: PT.string, + button: PT.element, + disabled: PT.bool, + extraModalStyle: PT.object, +}; + +export default BaseModal; diff --git a/src/components/BaseModal/styles.module.scss b/src/components/BaseModal/styles.module.scss new file mode 100644 index 00000000..e1c1d36c --- /dev/null +++ b/src/components/BaseModal/styles.module.scss @@ -0,0 +1,28 @@ +@import "styles/include"; + +.title { + @include font-barlow-condensed; + font-weight: normal; + font-size: 34px; + line-height: 40px; + margin: 0 0 24px 0; + overflow-wrap: anywhere; + padding: 0; + text-transform: uppercase; +} + +.content { + @include font-roboto; + line-height: 140%; +} + +.button-group { + margin: 24px 0 0 0; + display: flex; + flex-direction: row; + flex-wrap: wrap; + button { + margin-right: 10px; + margin-bottom: 10px; + } +} diff --git a/src/components/Button/index.jsx b/src/components/Button/index.jsx index 7264af96..77edd3e7 100644 --- a/src/components/Button/index.jsx +++ b/src/components/Button/index.jsx @@ -27,6 +27,7 @@ const Button = ({ routeTo, href, target, + isSubmit, }) => { if (href) { return ( @@ -49,6 +50,7 @@ const Button = ({ className={className} ref={innerRef} disabled={disabled} + type={isSubmit ? "submit" : "button"} > {children} @@ -68,6 +70,7 @@ Button.propTypes = { disabled: PT.bool, routeTo: PT.string, href: PT.string, + isSubmit: PT.bool, }; export default Button; diff --git a/src/components/Button/styles.module.scss b/src/components/Button/styles.module.scss index 91dc4bb7..7302f649 100644 --- a/src/components/Button/styles.module.scss +++ b/src/components/Button/styles.module.scss @@ -42,51 +42,51 @@ } .type-primary { - border: 1px solid #137D60; - background-color: #137D60; + border: 1px solid #137d60; + background-color: #137d60; color: #fff; } .type-warning { - border: 1px solid #EF476F; - background-color: #EF476F; + border: 1px solid #ef476f; + background-color: #ef476f; color: #fff; } .type-secondary { background-color: #fff; - border: 1px solid #137D60; + border: 1px solid #137d60; color: #229174; } .type-secondary[disabled] { - border-color: #E9E9E9; - color: #E9E9E9; + border-color: #e9e9e9; + color: #e9e9e9; } .type-segment { background-color: transparent; border: 1px solid transparent; - color: #2A2A2A; + color: #2a2a2a; font-size: 12px; font-weight: normal; } .type-segment-selected { - border: 1px solid #7F7F7F; - background-color: #7F7F7F; + border: 1px solid #7f7f7f; + background-color: #7f7f7f; color: #fff; font-size: 12px; font-weight: normal; } .type-segment[disabled] { - color: #E9E9E9; + color: #e9e9e9; } .type-primary[disabled], .type-warning[disabled], .type-segment-selected[disabled] { - background-color: #E9E9E9; - border-color: #E9E9E9; + background-color: #e9e9e9; + border-color: #e9e9e9; } diff --git a/src/components/CenteredSpinner/index.jsx b/src/components/CenteredSpinner/index.jsx new file mode 100644 index 00000000..3d7f7529 --- /dev/null +++ b/src/components/CenteredSpinner/index.jsx @@ -0,0 +1,32 @@ +/** + * A centered spinner used to indicate loading in modals + */ + +import React from "react"; +import PT from "prop-types"; +import Loader from "react-loader-spinner"; +import "./styles.module.scss"; + +function CenteredSpinner(props) { + const { + type = "TailSpin", + color = "#00BFFF", + height = 80, + width = 80, + } = props; + + return ( +
+ +
+ ); +} + +CenteredSpinner.propTypes = { + type: PT.string, + color: PT.string, + height: PT.number, + width: PT.number, +}; + +export default CenteredSpinner; diff --git a/src/components/CenteredSpinner/styles.module.scss b/src/components/CenteredSpinner/styles.module.scss new file mode 100644 index 00000000..c4914bcc --- /dev/null +++ b/src/components/CenteredSpinner/styles.module.scss @@ -0,0 +1,5 @@ +.loader-container { + display: flex; + align-items: center; + flex-direction: column; +} diff --git a/src/components/DataItem/index.jsx b/src/components/DataItem/index.jsx index 22c76601..fec0067a 100644 --- a/src/components/DataItem/index.jsx +++ b/src/components/DataItem/index.jsx @@ -13,7 +13,13 @@ const DataItem = ({ icon, title, children }) => { {icon}
{title}
-
{children}
+ {/* if `children` is pure text, then we apply styling to it + but otherwise with don't apply styling */} + {_.isString(children) ? ( +
{children}
+ ) : ( +
{children}
+ )}
); diff --git a/src/components/DataItem/styles.module.scss b/src/components/DataItem/styles.module.scss index 78b71dc9..c13303f8 100644 --- a/src/components/DataItem/styles.module.scss +++ b/src/components/DataItem/styles.module.scss @@ -1,13 +1,19 @@ @import "styles/include"; .data-item { - align-items: center; + align-items: flex-start; display: flex; flex-direction: row; + svg { + margin-top: 4px; + } } .data { margin-left: 16px; + display: flex; + flex-direction: column; + flex-basis: 90%; } .title { @@ -16,7 +22,6 @@ letter-spacing: 0.5px; line-height: 16px; text-align: left; - white-space: nowrap; } .value { @@ -25,5 +30,9 @@ font-weight: 500; margin-top: 2px; text-align: left; - white-space: nowrap; + word-break: break-all; +} + +.value-component { + margin-top: 2px; } diff --git a/src/components/DateInput/index.jsx b/src/components/DateInput/index.jsx new file mode 100644 index 00000000..3bb3c89e --- /dev/null +++ b/src/components/DateInput/index.jsx @@ -0,0 +1,37 @@ +/** + * DateInput + * + * Date Input control. + */ +import React from "react"; +import PT from "prop-types"; +import DatePicker from "react-datepicker"; +import cn from "classnames"; +import "./styles.module.scss"; + +const DateInput = (props) => { + return ( +
+ +
+ ); +}; + +DateInput.propTypes = { + value: PT.string, + onChange: PT.func.isRequired, + placeholder: PT.string, + onBlur: PT.func, + onFocus: PT.func, + className: PT.string, +}; + +export default DateInput; diff --git a/src/components/DateInput/styles.module.scss b/src/components/DateInput/styles.module.scss new file mode 100644 index 00000000..10670205 --- /dev/null +++ b/src/components/DateInput/styles.module.scss @@ -0,0 +1,16 @@ +@import "styles/include"; + +.datepicker-wrapper { + & > div { + width: 100%; + } + &.error { + input { + border-color: #fe665d; + } + } +} + +.datepicker-wrapper > div:nth-child(2) > div:nth-child(2) { + z-index: 100; +} diff --git a/src/components/FormField/index.jsx b/src/components/FormField/index.jsx new file mode 100644 index 00000000..21d4f3e0 --- /dev/null +++ b/src/components/FormField/index.jsx @@ -0,0 +1,137 @@ +/** + * FormField + * + * FormField Component. + */ +import React from "react"; +import PT from "prop-types"; +import { Field } from "react-final-form"; +import { FORM_FIELD_TYPE } from "../../constants"; +import TextInput from "../../components/TextInput"; +import TextArea from "../../components/TextArea"; +import MarkdownEditor from "../../components/MarkdownEditor"; +import ReactSelect from "../../components/ReactSelect"; +import DateInput from "../../components/DateInput"; +import "./styles.module.scss"; + +const FormField = ({ field }) => { + return ( + + {({ input, meta }) => ( +
+ {!field.readonly && ( + + )} + {field.type === FORM_FIELD_TYPE.TEXT && ( + + )} + {field.type === FORM_FIELD_TYPE.NUMBER && ( + + )} + {field.type === FORM_FIELD_TYPE.MARKDOWNEDITOR && ( + + )} + {field.type === FORM_FIELD_TYPE.TEXTAREA && ( +