From 0f328dfe03b8e4e6ac2a832abde5d9d3cbe3c3c3 Mon Sep 17 00:00:00 2001
From: Albin Henriksson <albhe428@student.liu.se>
Date: Thu, 25 Feb 2021 11:10:17 +0100
Subject: [PATCH] Resolve "Add styling"

---
 client/.eslintrc                |   2 +
 client/coverage_report.py       |  12 +-
 client/package-lock.json        | 253 +++++++++++++++++++++++++++++++-
 client/package.json             |   3 +-
 client/src/App.tsx              |   4 +
 client/src/components/Login.css |  10 ++
 client/src/components/Login.tsx | 135 ++++++++++-------
 client/src/index.tsx            |   1 -
 package-lock.json               |   3 -
 9 files changed, 355 insertions(+), 68 deletions(-)
 create mode 100644 client/src/components/Login.css
 delete mode 100644 package-lock.json

diff --git a/client/.eslintrc b/client/.eslintrc
index c0c40d69..46369ae6 100644
--- a/client/.eslintrc
+++ b/client/.eslintrc
@@ -28,8 +28,10 @@
         "plugin:prettier/recommended"
     ],
     "rules": {
+        
         "semi": "off",
         "react/jsx-one-expression-per-line": "off",
+
         "prettier/prettier": [
             "error",
             {
diff --git a/client/coverage_report.py b/client/coverage_report.py
index c6cd3763..a464ba75 100644
--- a/client/coverage_report.py
+++ b/client/coverage_report.py
@@ -1,8 +1,10 @@
 import xml.etree.ElementTree as et
 
-tree = et.parse('output/coverage/jest/cobertura-coverage.xml')
+tree = et.parse("output/coverage/jest/cobertura-coverage.xml")
 root = tree.getroot()
-for package_class in tree.find('.//packages'):
-  package_class.set('name', 'client.' + package_class.attrib.get('name'))
-  package_class.set('filename', 'client/' + package_class.attrib.get('filename'))
-tree.write('output/coverage/jest/cobertura-coverage.xml')
+for package in tree.find(".//packages"):
+    package.set("name", "client." + package.attrib.get("name"))
+    for package_class in package.find("classes"):
+        package_class.set("name", "client." + package_class.attrib.get("name"))
+        package_class.set("filename", "client/" + package_class.attrib.get("filename"))
+tree.write("output/coverage/jest/cobertura-coverage.xml")
diff --git a/client/package-lock.json b/client/package-lock.json
index ce26473a..67ccc686 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -1125,6 +1125,11 @@
       "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
       "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
     },
+    "@emotion/hash": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
+      "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
+    },
     "@eslint/eslintrc": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.3.0.tgz",
@@ -1729,6 +1734,100 @@
         }
       }
     },
+    "@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/lab": {
+      "version": "4.0.0-alpha.57",
+      "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.57.tgz",
+      "integrity": "sha512-qo/IuIQOmEKtzmRD2E4Aa6DB4A87kmY6h0uYhjUmrrgmEAgbbw9etXpWPVXuRK6AGIQCjFzV6WO2i21m1R4FCw==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/utils": "^4.11.2",
+        "clsx": "^1.0.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0"
+      }
+    },
+    "@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"
+      },
+      "dependencies": {
+        "csstype": {
+          "version": "2.6.15",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.15.tgz",
+          "integrity": "sha512-FNeiVKudquehtR3t9TRRnsHL+lJhuHF5Zn9dt01jpojlurLEPDhhEtUkWmAUJ7/fOLaLG4dCDEnUsR0N1rZSsg=="
+        }
+      }
+    },
+    "@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"
+      },
+      "dependencies": {
+        "csstype": {
+          "version": "2.6.15",
+          "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.15.tgz",
+          "integrity": "sha512-FNeiVKudquehtR3t9TRRnsHL+lJhuHF5Zn9dt01jpojlurLEPDhhEtUkWmAUJ7/fOLaLG4dCDEnUsR0N1rZSsg=="
+        }
+      }
+    },
+    "@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"
+      }
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.4",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz",
@@ -2328,6 +2427,14 @@
         "@types/react-router": "*"
       }
     },
+    "@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",
@@ -3741,11 +3848,6 @@
       "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=="
-    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -4165,6 +4267,11 @@
         "wrap-ansi": "^6.2.0"
       }
     },
+    "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",
@@ -4678,6 +4785,15 @@
         }
       }
     },
+    "css-vendor": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
+      "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
+      "requires": {
+        "@babel/runtime": "^7.8.3",
+        "is-in-browser": "^1.0.2"
+      }
+    },
     "css-what": {
       "version": "3.4.2",
       "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
@@ -5188,6 +5304,15 @@
         "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"
+      }
+    },
     "dom-serializer": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
@@ -7666,6 +7791,11 @@
       "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=="
+    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -7766,6 +7896,14 @@
       "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",
@@ -7996,6 +8134,11 @@
         "is-extglob": "^2.1.1"
       }
     },
+    "is-in-browser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz",
+      "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU="
+    },
     "is-module": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
@@ -9810,6 +9953,85 @@
         "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"
+      }
+    },
+    "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",
@@ -11206,6 +11428,11 @@
         "ts-pnp": "^1.1.6"
       }
     },
+    "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",
@@ -12862,6 +13089,17 @@
         }
       }
     },
+    "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": "2.0.0",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
@@ -14613,6 +14851,11 @@
         "util.promisify": "~1.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",
diff --git a/client/package.json b/client/package.json
index a882fac0..4fcc3e71 100644
--- a/client/package.json
+++ b/client/package.json
@@ -3,6 +3,8 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@material-ui/core": "^4.11.3",
+    "@material-ui/lab": "^4.0.0-alpha.57",
     "@testing-library/jest-dom": "^5.11.9",
     "@testing-library/react": "^11.2.5",
     "@testing-library/user-event": "^12.6.3",
@@ -11,7 +13,6 @@
     "@types/react": "^17.0.1",
     "@types/react-dom": "^17.0.0",
     "axios": "^0.21.1",
-    "bootstrap": "^4.6.0",
     "formik": "^2.2.6",
     "react": "^17.0.1",
     "react-dom": "^17.0.1",
diff --git a/client/src/App.tsx b/client/src/App.tsx
index a48b2037..2df0f43f 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -7,6 +7,10 @@ import TestConnection from './components/TestConnection'
 const App: React.FC = () => {
   return (
     <div className="wrapper">
+      <link
+        rel="stylesheet"
+        href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
+      />
       <h1>Application</h1>
       <TestConnection />
       <BrowserRouter>
diff --git a/client/src/components/Login.css b/client/src/components/Login.css
new file mode 100644
index 00000000..5a01047d
--- /dev/null
+++ b/client/src/components/Login.css
@@ -0,0 +1,10 @@
+.login-page {
+  display: flex;
+  justify-content: center;
+}
+
+.login-form {
+  display: flex;
+  flex-direction: column;
+  width: 250px;
+}
diff --git a/client/src/components/Login.tsx b/client/src/components/Login.tsx
index 0cf6a02c..75123ff3 100644
--- a/client/src/components/Login.tsx
+++ b/client/src/components/Login.tsx
@@ -1,9 +1,14 @@
+import { Button, TextField } from '@material-ui/core'
+import { withStyles } from '@material-ui/core/styles'
+import { Alert, AlertTitle } from '@material-ui/lab'
 import axios from 'axios'
-import 'bootstrap/dist/css/bootstrap.min.css'
-import { ErrorMessage, Field, Form, Formik } from 'formik'
+import { Formik, FormikHelpers } from 'formik'
 import React, { useState } from 'react'
 import * as Yup from 'yup'
 import { LoginModel } from '../interfaces/models'
+import './Login.css'
+
+const styles = {}
 
 interface LoginState {
   status: number
@@ -15,6 +20,11 @@ interface LoginFormModel {
   error?: string
 }
 
+interface ServerResponse {
+  code: number
+  message: string
+}
+
 const schema: Yup.SchemaOf<LoginFormModel> = Yup.object({
   model: Yup.object()
     .shape({
@@ -29,63 +39,82 @@ const schema: Yup.SchemaOf<LoginFormModel> = Yup.object({
   error: Yup.string().optional()
 })
 
-const LoginForm: React.FC = () => {
+const handleSubmit = async (
+  values: LoginFormModel,
+  actions: FormikHelpers<LoginFormModel>
+) => {
+  await axios
+    .post<ServerResponse>(`users/login`, values.model)
+    .then((res) => {
+      actions.resetForm()
+    })
+    .catch(({ response }) => {
+      actions.setFieldError('error', response.data.message)
+    })
+    .finally(() => {
+      actions.setSubmitting(false)
+    })
+}
+
+const LoginForm: React.FC = (props) => {
   const [serverState, setServerState] = useState<LoginFormModel>()
   const initialValues: LoginFormModel = { model: { email: '', password: '' } }
   return (
-    <Formik
-      initialValues={initialValues}
-      validationSchema={schema}
-      onSubmit={async (values, actions) => {
-        await axios
-          .post(`users/login`, values.model)
-          .then((res) => {
-            actions.resetForm()
-          })
-          .catch((error) => {
-            actions.setFieldError('error', 'Invalid email or password')
-          })
-          .finally(() => {
-            actions.setSubmitting(false)
-          })
-      }}
-    >
-      {(formik) => (
-        <Form>
-          <div className="form-group">
-            <label htmlFor="model.email">Email Address</label>
-            <Field name="model.email" type="email" className="form-control" />
-            <ErrorMessage name="model.email">
-              {(msg) => <div className="text-danger">{msg}</div>}
-            </ErrorMessage>
-          </div>
-
-          <div className="form-group">
-            <label htmlFor="model.password">Password</label>
-            <Field
+    <div className="login-page">
+      <Formik
+        initialValues={initialValues}
+        validationSchema={schema}
+        onSubmit={handleSubmit}
+      >
+        {(formik) => (
+          <form onSubmit={formik.handleSubmit} className="login-form">
+            <TextField
+              label="Email Address"
+              name="model.email"
+              helperText={
+                formik.touched.model?.email ? formik.errors.model?.email : ''
+              }
+              error={Boolean(formik.errors.model?.email)}
+              onChange={formik.handleChange}
+              onBlur={formik.handleBlur}
+              margin="normal"
+            />
+            <TextField
+              label="Password"
               name="model.password"
               type="password"
-              className="form-control"
+              helperText={
+                formik.touched.model?.password
+                  ? formik.errors.model?.password
+                  : ''
+              }
+              error={Boolean(formik.errors.model?.password)}
+              onChange={formik.handleChange}
+              onBlur={formik.handleBlur}
+              margin="normal"
             />
-            <ErrorMessage name="model.password">
-              {(msg) => <div className="text-danger">{msg}</div>}
-            </ErrorMessage>
-          </div>
-
-          <div className="form-group">
-            <button type="submit" className="btn btn-primary">
-              Login
-            </button>
-          </div>
-          <div className="form-group">
-            <ErrorMessage name="error">
-              {(msg) => <div className="text-danger">{msg}</div>}
-            </ErrorMessage>
-          </div>
-        </Form>
-      )}
-    </Formik>
+            <Button
+              type="submit"
+              fullWidth
+              variant="contained"
+              color="primary"
+              disabled={!formik.isValid}
+            >
+              Submit
+            </Button>
+            {formik.errors.error ? (
+              <Alert severity="error">
+                <AlertTitle>Error</AlertTitle>
+                {formik.errors.error}
+              </Alert>
+            ) : (
+              <div />
+            )}
+          </form>
+        )}
+      </Formik>
+    </div>
   )
 }
 
-export default LoginForm
+export default withStyles(styles)(LoginForm)
diff --git a/client/src/index.tsx b/client/src/index.tsx
index 728ad9bd..e7b11a23 100644
--- a/client/src/index.tsx
+++ b/client/src/index.tsx
@@ -1,4 +1,3 @@
-import 'bootstrap/dist/css/bootstrap.min.css'
 import React from 'react'
 import ReactDOM from 'react-dom'
 import App from './App'
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 48e341a0..00000000
--- a/package-lock.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "lockfileVersion": 1
-}
-- 
GitLab