diff --git a/package-lock.json b/package-lock.json
index 6463ada39fd86f4a088ae8726c205a054b7c90cf..a5d09a513ce24f8fbb0dba8bc7923b341a5fc223 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1624,12 +1624,6 @@
       "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz",
       "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w=="
     },
-    "abbrev": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
-      "optional": true
-    },
     "accepts": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -1746,16 +1740,6 @@
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
     },
-    "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==",
-      "optional": true,
-      "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",
@@ -2772,17 +2756,6 @@
       "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000971.tgz",
       "integrity": "sha512-TQFYFhRS0O5rdsmSbF1Wn+16latXYsQJat66f7S7lizXW1PVpWJeZw9wqqVLIjuxDRz7s7xRUj13QCfd8hKn6g=="
     },
-    "canvas": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.6.0.tgz",
-      "integrity": "sha512-bEO9f1ThmbknLPxCa8Es7obPlN9W3stB1bo7njlhOFKIdUTldeTqXCh9YclCPAi2pSQs84XA0jq/QEZXSzgyMw==",
-      "optional": true,
-      "requires": {
-        "nan": "^2.14.0",
-        "node-pre-gyp": "^0.11.0",
-        "simple-get": "^3.0.3"
-      }
-    },
     "capture-exit": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz",
@@ -3600,12 +3573,6 @@
         "date-now": "^0.1.4"
       }
     },
-    "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=",
-      "optional": true
-    },
     "constants-browserify": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
@@ -4081,26 +4048,11 @@
       "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
       "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
     },
-    "decompress-response": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
-      "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
-      "optional": true,
-      "requires": {
-        "mimic-response": "^1.0.0"
-      }
-    },
     "deep-equal": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
       "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
     },
-    "deep-extend": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
-      "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
-      "optional": true
-    },
     "deep-is": {
       "version": "0.1.3",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@@ -4204,12 +4156,6 @@
       "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=",
-      "optional": true
-    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -4229,12 +4175,6 @@
       "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
       "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
     },
-    "detect-libc": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
-      "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
-      "optional": true
-    },
     "detect-newline": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
@@ -5352,82 +5292,6 @@
       "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
       "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
     },
-    "fabric": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/fabric/-/fabric-3.3.2.tgz",
-      "integrity": "sha512-xUbSmv3KzmmXgSTqHZbg33YMiIm3ZGlWvDgqEqdTBMSrrQd8V9t596ra7lIgr8rNh3HhxBDu7rZJ+R0t6FNFAg==",
-      "requires": {
-        "canvas": "^2.6.0",
-        "jsdom": "^15.1.0"
-      },
-      "dependencies": {
-        "jsdom": {
-          "version": "15.1.1",
-          "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.1.1.tgz",
-          "integrity": "sha512-cQZRBB33arrDAeCrAEWn1U3SvrvC8XysBua9Oqg1yWrsY/gYcusloJC3RZJXuY5eehSCmws8f2YeliCqGSkrtQ==",
-          "optional": true,
-          "requires": {
-            "abab": "^2.0.0",
-            "acorn": "^6.1.1",
-            "acorn-globals": "^4.3.2",
-            "array-equal": "^1.0.0",
-            "cssom": "^0.3.6",
-            "cssstyle": "^1.2.2",
-            "data-urls": "^1.1.0",
-            "domexception": "^1.0.1",
-            "escodegen": "^1.11.1",
-            "html-encoding-sniffer": "^1.0.2",
-            "nwsapi": "^2.1.4",
-            "parse5": "5.1.0",
-            "pn": "^1.1.0",
-            "request": "^2.88.0",
-            "request-promise-native": "^1.0.7",
-            "saxes": "^3.1.9",
-            "symbol-tree": "^3.2.2",
-            "tough-cookie": "^3.0.1",
-            "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": "^7.0.0",
-            "xml-name-validator": "^3.0.0"
-          }
-        },
-        "tough-cookie": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz",
-          "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==",
-          "optional": true,
-          "requires": {
-            "ip-regex": "^2.1.0",
-            "psl": "^1.1.28",
-            "punycode": "^2.1.1"
-          }
-        },
-        "whatwg-url": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz",
-          "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==",
-          "optional": true,
-          "requires": {
-            "lodash.sortby": "^4.7.0",
-            "tr46": "^1.0.1",
-            "webidl-conversions": "^4.0.2"
-          }
-        },
-        "ws": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/ws/-/ws-7.1.0.tgz",
-          "integrity": "sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g==",
-          "optional": true,
-          "requires": {
-            "async-limiter": "^1.0.0"
-          }
-        }
-      }
-    },
     "fast-deep-equal": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
@@ -5709,15 +5573,6 @@
         "universalify": "^0.1.0"
       }
     },
-    "fs-minipass": {
-      "version": "1.2.6",
-      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.6.tgz",
-      "integrity": "sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==",
-      "optional": true,
-      "requires": {
-        "minipass": "^2.2.1"
-      }
-    },
     "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",
@@ -5750,59 +5605,6 @@
       "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
     },
-    "gauge": {
-      "version": "2.7.4",
-      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
-      "optional": true,
-      "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"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-          "optional": true
-        },
-        "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=",
-          "optional": true,
-          "requires": {
-            "number-is-nan": "^1.0.0"
-          }
-        },
-        "string-width": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-          "optional": true,
-          "requires": {
-            "code-point-at": "^1.0.0",
-            "is-fullwidth-code-point": "^1.0.0",
-            "strip-ansi": "^3.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-          "optional": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        }
-      }
-    },
     "get-caller-file": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
@@ -6046,12 +5848,6 @@
       "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
       "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
     },
-    "has-unicode": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
-      "optional": true
-    },
     "has-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
@@ -6378,15 +6174,6 @@
       "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
       "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
     },
-    "ignore-walk": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
-      "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
-      "optional": true,
-      "requires": {
-        "minimatch": "^3.0.4"
-      }
-    },
     "immer": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
@@ -8488,12 +8275,6 @@
       "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
       "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
     },
-    "mimic-response": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
-      "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
-      "optional": true
-    },
     "mini-create-react-context": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz",
@@ -8537,25 +8318,6 @@
       "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
       "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
     },
-    "minipass": {
-      "version": "2.3.5",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
-      "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
-      "optional": true,
-      "requires": {
-        "safe-buffer": "^5.1.2",
-        "yallist": "^3.0.0"
-      }
-    },
-    "minizlib": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
-      "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
-      "optional": true,
-      "requires": {
-        "minipass": "^2.2.1"
-      }
-    },
     "mississippi": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@@ -8696,28 +8458,6 @@
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
     },
-    "needle": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz",
-      "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==",
-      "optional": true,
-      "requires": {
-        "debug": "^3.2.6",
-        "iconv-lite": "^0.4.4",
-        "sax": "^1.2.4"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "optional": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        }
-      }
-    },
     "negotiator": {
       "version": "0.6.2",
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
@@ -8812,32 +8552,6 @@
         }
       }
     },
-    "node-pre-gyp": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz",
-      "integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==",
-      "optional": true,
-      "requires": {
-        "detect-libc": "^1.0.2",
-        "mkdirp": "^0.5.1",
-        "needle": "^2.2.1",
-        "nopt": "^4.0.1",
-        "npm-packlist": "^1.1.6",
-        "npmlog": "^4.0.2",
-        "rc": "^1.2.7",
-        "rimraf": "^2.6.1",
-        "semver": "^5.3.0",
-        "tar": "^4"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "5.7.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
-          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
-          "optional": true
-        }
-      }
-    },
     "node-releases": {
       "version": "1.1.21",
       "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.21.tgz",
@@ -8853,16 +8567,6 @@
         }
       }
     },
-    "nopt": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
-      "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
-      "optional": true,
-      "requires": {
-        "abbrev": "1",
-        "osenv": "^0.1.4"
-      }
-    },
     "normalize-package-data": {
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -8899,22 +8603,6 @@
       "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
       "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg=="
     },
-    "npm-bundled": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
-      "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
-      "optional": true
-    },
-    "npm-packlist": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.4.tgz",
-      "integrity": "sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==",
-      "optional": true,
-      "requires": {
-        "ignore-walk": "^3.0.1",
-        "npm-bundled": "^1.0.1"
-      }
-    },
     "npm-run-path": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
@@ -8923,18 +8611,6 @@
         "path-key": "^2.0.0"
       }
     },
-    "npmlog": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
-      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
-      "optional": true,
-      "requires": {
-        "are-we-there-yet": "~1.1.2",
-        "console-control-strings": "~1.1.0",
-        "gauge": "~2.7.3",
-        "set-blocking": "~2.0.0"
-      }
-    },
     "nth-check": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -9159,12 +8835,6 @@
       "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
       "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
     },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-      "optional": true
-    },
     "os-locale": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
@@ -9180,16 +8850,6 @@
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
     },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "optional": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
     "p-defer": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
@@ -10597,18 +10257,6 @@
         }
       }
     },
-    "rc": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
-      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
-      "optional": true,
-      "requires": {
-        "deep-extend": "^0.6.0",
-        "ini": "~1.3.0",
-        "minimist": "^1.2.0",
-        "strip-json-comments": "~2.0.1"
-      }
-    },
     "react": {
       "version": "16.8.6",
       "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz",
@@ -11651,23 +11299,6 @@
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
       "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
     },
-    "simple-concat": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
-      "integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=",
-      "optional": true
-    },
-    "simple-get": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.0.3.tgz",
-      "integrity": "sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==",
-      "optional": true,
-      "requires": {
-        "decompress-response": "^3.3.0",
-        "once": "^1.3.1",
-        "simple-concat": "^1.0.0"
-      }
-    },
     "simple-swizzle": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
@@ -12342,21 +11973,6 @@
       "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
       "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
     },
-    "tar": {
-      "version": "4.4.10",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.10.tgz",
-      "integrity": "sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==",
-      "optional": true,
-      "requires": {
-        "chownr": "^1.1.1",
-        "fs-minipass": "^1.2.5",
-        "minipass": "^2.3.5",
-        "minizlib": "^1.2.1",
-        "mkdirp": "^0.5.0",
-        "safe-buffer": "^5.1.2",
-        "yallist": "^3.0.3"
-      }
-    },
     "terser": {
       "version": "3.17.0",
       "resolved": "https://registry.npmjs.org/terser/-/terser-3.17.0.tgz",
@@ -13279,15 +12895,6 @@
       "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
       "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
     },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-      "optional": true,
-      "requires": {
-        "string-width": "^1.0.2 || 2"
-      }
-    },
     "wordwrap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
diff --git a/src/App.css b/src/App.css
index bc9556dc36b07c79980b0602f863690d34a151e9..fe44e37477b045f8d82ed74f1ef0658da3cbacd1 100644
--- a/src/App.css
+++ b/src/App.css
@@ -13,7 +13,7 @@ body {
 /* UserMap */
 .map {
   position: absolute;
-  margin-top: 50px;
+  /* margin-top: 50px; */
   height: 95vh;
   width: 100vw;
 }
@@ -214,6 +214,8 @@ div.login button:hover {
 .gamelist {
   border: 2px solid white;
   max-width: 800px;
+  max-height: 500px;
+  overflow: scroll;
 }
 
 .gamelist-item {
@@ -238,6 +240,20 @@ div.login button:hover {
   flex-direction: column;
 }
 
+.notification-popup {
+  position: absolute;
+  z-index: 1010;
+}
+
+.notification-popup.warning {
+  background-color: yellow;
+  color: black;
+}
+
+.notification-popup.alert {
+  background-color: red;
+}
+
 .leaflet-control-playback {
   position: relative;
   background-color: #7cbdf5;
diff --git a/src/App.js b/src/App.js
index b1752f70d4e09e5afc57d112005bc247f8d70d8e..c0fb6be1e2302e9f6f186b126553e0afe4508a78 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,8 +1,6 @@
 import React, { Component } from "react";
 import "../node_modules/leaflet-draw/dist/leaflet.draw.css";
 import "./App.css";
-
-import ClientSocket from "./components/Socket";
 import {
   BrowserRouter as Router,
   Route,
diff --git a/src/components/DrawTools.js b/src/components/DrawTools.js
index be1b7b35dedab72665c5c3221072c5781656b027..8040ce5920a3f990eebb6ce94081538103d2a6b7 100644
--- a/src/components/DrawTools.js
+++ b/src/components/DrawTools.js
@@ -246,51 +246,54 @@ class DrawTools extends Component {
       // The elements you draw will be added to this FeatureGroup layer,
       // when you hit edit button only items in this layer will be edited."
       <FeatureGroup>
-        <EditControl
-          position="topright"
-          onCreated={this._onCreated}
-          onEdited={this._onEdited}
-          onEditStart={this._onEditDeleteStart}
-          onEditStop={this._onEditDeleteStop}
-          onDeleted={this._onDeleted}
-          onDeleteStart={this._onEditDeleteStart}
-          onDeleteStop={this._onEditDeleteStop}
-          draw={{
-            circle: {
-              repeatMode: false, // allows using the tool again after finishing the previous shape
-              shapeOptions: {
-                color: "#f9f10c",
-                opacity: 1 // affects the outline only. for some reason it wasn't at full opacity, so this is needed for more clarity
-              }
-            },
-            rectangle: {
-              repeatMode: false
-            },
-            polygon: {
-              repeatMode: true,
-              allowIntersection: false, // Restricts shapes to simple polygons
-              drawError: {
-                color: "#e1e100", // Color the shape will turn when intersects
-                message: "<strong>Oh snap!<strong> you can't draw that!" // Message that will show when intersect
+        {(this.props.role === "admin" ||
+          this.props.role === "factionleader") && (
+          <EditControl
+            position="topright"
+            onCreated={this._onCreated}
+            onEdited={this._onEdited}
+            onEditStart={this._onEditDeleteStart}
+            onEditStop={this._onEditDeleteStop}
+            onDeleted={this._onDeleted}
+            onDeleteStart={this._onEditDeleteStart}
+            onDeleteStop={this._onEditDeleteStop}
+            draw={{
+              circle: {
+                repeatMode: false, // allows using the tool again after finishing the previous shape
+                shapeOptions: {
+                  color: "#f9f10c",
+                  opacity: 1 // affects the outline only. for some reason it wasn't at full opacity, so this is needed for more clarity
+                }
               },
-              shapeOptions: {
-                color: "#ed2572",
-                opacity: 1
-              }
-            },
-            polyline: {
-              repeatMode: true,
-              shapeOptions: {
-                color: "#ed2572",
-                opacity: 1
-              }
-            },
-            marker: {
-              repeatMode: false
-            },
-            circlemarker: false
-          }}
-        />
+              rectangle: {
+                repeatMode: false
+              },
+              polygon: {
+                repeatMode: true,
+                allowIntersection: false, // Restricts shapes to simple polygons
+                drawError: {
+                  color: "#e1e100", // Color the shape will turn when intersects
+                  message: "<strong>Oh snap!<strong> you can't draw that!" // Message that will show when intersect
+                },
+                shapeOptions: {
+                  color: "#ed2572",
+                  opacity: 1
+                }
+              },
+              polyline: {
+                repeatMode: true,
+                shapeOptions: {
+                  color: "#ed2572",
+                  opacity: 1
+                }
+              },
+              marker: {
+                repeatMode: false
+              },
+              circlemarker: false
+            }}
+          />
+        )}
 
         {/* iterate through every element fetched from back-end */}
         {this.props.geoJSONLayer.features.map(feature => {
diff --git a/src/components/EditGameForm.js b/src/components/EditGameForm.js
index c0fc662e0442d42c9a4ac6df49ef3b9fc943bc6b..65b5d7f38bb7f1664401f316f2808cf909eff421 100644
--- a/src/components/EditGameForm.js
+++ b/src/components/EditGameForm.js
@@ -30,19 +30,14 @@ export default class EditGameForm extends React.Component {
       objectivePoints: [],
       capture_time: 300,
       confirmation_time: 60,
-      displayColorPicker: false
+      displayColorPicker: false,
+      saved: true
     };
-
-    this.handleMapDrag = this.handleMapDrag.bind(this);
   }
 
-  handleError = error => {
-    this.setState({ errorMsg: error });
-  };
-
   handleChange = e => {
     const { name, value } = e.target;
-    this.setState({ [name]: value });
+    this.setState({ [name]: value, saved: false });
   };
 
   handleFactionAdd = e => {
@@ -185,7 +180,12 @@ export default class EditGameForm extends React.Component {
 
   // show/hide this form
   handleView = e => {
-    this.props.toggleView(this.props.view);
+    if (
+      this.state.saved ||
+      window.confirm("Are you sure you want to leave without saving?")
+    ) {
+      this.props.toggleView(this.props.view);
+    }
   };
 
   // remove view with ESC
@@ -195,17 +195,7 @@ export default class EditGameForm extends React.Component {
     }
   };
 
-  handleMapDrag = e => {
-    this.setState({
-      mapCenter: e.target.getCenter()
-    });
-  };
-
-  handleMapScroll = e => {
-    this.setState({
-      zoom: e.target.getZoom()
-    });
-  };
+  handleMapScroll = e => {};
 
   handleGameSave = e => {
     e.preventDefault();
@@ -248,6 +238,7 @@ export default class EditGameForm extends React.Component {
     }
 
     let token = sessionStorage.getItem("token");
+    let error = false;
 
     // Send Game info to the server
     fetch(`${process.env.REACT_APP_API_URL}/game/edit/${this.props.gameId}`, {
@@ -261,15 +252,23 @@ export default class EditGameForm extends React.Component {
     })
       .then(res => {
         if (!res.ok) {
-          throw Error(res.statusMessage);
-        } else {
-          return res.json();
+          error = true;
         }
+        return res.json();
       })
       .then(result => {
         alert(result.message);
-        this.props.onEditSave();
-        this.handleView();
+        if (!error) {
+          this.setState(
+            {
+              saved: true
+            },
+            () => {
+              this.handleView();
+              this.props.onEditSave();
+            }
+          );
+        }
       })
       .catch(error => console.log("Error: ", error));
   };
@@ -446,7 +445,7 @@ export default class EditGameForm extends React.Component {
             onSubmit={this.handleObjectivePointAdd}
           />
 
-          <h1>Demo Game Editor</h1>
+          <h1>Game Editor</h1>
           <br />
           <input
             placeholder="Game name"
@@ -515,10 +514,10 @@ export default class EditGameForm extends React.Component {
           />
           <br />
           <br />
-
           <label>Factions</label>
           <br />
           <input
+            id="editGameFactionNameInput"
             name="factionNameInput"
             value={this.state.factionNameInput}
             minLength="2"
@@ -527,6 +526,7 @@ export default class EditGameForm extends React.Component {
             form="factionAddFrom"
           />
           <input
+            id="editGameFactionPasswordInput"
             name="factionPasswordInput"
             value={this.state.factionPasswordInput}
             minLength="3"
@@ -536,6 +536,7 @@ export default class EditGameForm extends React.Component {
             form="factionAddFrom"
           />
           <div
+            id="editGameColorPickerButton"
             style={styles.swatch}
             onClick={() =>
               this.setState({
@@ -547,6 +548,7 @@ export default class EditGameForm extends React.Component {
           </div>
           {this.state.displayColorPicker && (
             <div
+              id="editGameColorPicker"
               style={styles.cover}
               onClick={() => this.setState({ displayColorPicker: false })}
             >
@@ -558,7 +560,11 @@ export default class EditGameForm extends React.Component {
               />
             </div>
           )}
-          <button type="submit" form="factionAddFrom">
+          <button
+            id="editGameFactionSubmitButton"
+            type="submit"
+            form="factionAddFrom"
+          >
             Add
           </button>
           <ul>{factions}</ul>
@@ -567,6 +573,7 @@ export default class EditGameForm extends React.Component {
           <label>Objective points</label>
           <br />
           <input
+            id="editGameObjectivePointDescriptionInput"
             name="objectivePointDescriptionInput"
             type="number"
             value={this.state.objectivePointDescriptionInput}
@@ -576,6 +583,7 @@ export default class EditGameForm extends React.Component {
             form="objectivePointAddFrom"
           />
           <input
+            id="editGameObjectivePointMultiplierInput"
             name="objectivePointMultiplierInput"
             type="number"
             value={this.state.objectivePointMultiplierInput}
@@ -583,7 +591,11 @@ export default class EditGameForm extends React.Component {
             placeholder="Objective point multiplier"
             form="objectivePointAddFrom"
           />
-          <button type="submit" form="objectivePointAddFrom">
+          <button
+            id="editGameObjectivePointSubmitButton"
+            type="submit"
+            form="objectivePointAddFrom"
+          >
             Add
           </button>
           <ul>{objectivePoints}</ul>
@@ -596,6 +608,7 @@ export default class EditGameForm extends React.Component {
             Capture time:
           </label>
           <input
+            id="editGameCaptureTimeInput"
             name="capture_time"
             type="number"
             value={this.state.capture_time}
@@ -604,6 +617,7 @@ export default class EditGameForm extends React.Component {
           />
           <label className="">Confimation time:</label>
           <input
+            id="editGameConfirmationTimeInput"
             name="confirmation_time"
             type="number"
             value={this.state.confirmation_time}
@@ -621,8 +635,8 @@ export default class EditGameForm extends React.Component {
             zoom={this.state.zoom}
             maxZoom="13"
             style={{ height: "400px", width: "400px" }}
-            onmoveend={this.handleMapDrag}
-            onzoomend={this.handleMapScroll}
+            onmoveend={e => this.setState({ mapCenter: e.target.getCenter() })}
+            onzoomend={e => this.setState({ zoom: e.target.getZoom() })}
           >
             <TileLayer
               attribution="Maanmittauslaitoksen kartta"
@@ -631,6 +645,7 @@ export default class EditGameForm extends React.Component {
           </Map>
           <br />
           <button
+            id="editGameDeleteGameButton"
             style={{ backgroundColor: "red" }}
             type="submit"
             form="gameDeletionForm"
diff --git a/src/components/GameInfoView.js b/src/components/GameInfoView.js
new file mode 100644
index 0000000000000000000000000000000000000000..dc961d61a855e0bccf28c2a5a82c335817de66a4
--- /dev/null
+++ b/src/components/GameInfoView.js
@@ -0,0 +1,70 @@
+import React from "react";
+import { Map, TileLayer } from "react-leaflet";
+
+export default class GameInfoView extends React.Component {
+  componentDidMount() {
+    document.addEventListener("keyup", this.handleEsc);
+  }
+
+  componentWillUnmount() {
+    document.removeEventListener("keyup", this.handleEsc);
+  }
+
+  handleEsc = e => {
+    if (e.keyCode === 27) {
+      this.props.toggleView();
+    }
+  };
+
+  render() {
+    if (this.props.gameInfo === undefined) {
+      return false;
+    }
+    return (
+      <div className="fade-main">
+        <div className="sticky">
+          <span
+            id="closeGameInfoX"
+            className="close"
+            onClick={this.props.toggleView}
+          >
+            ×
+          </span>
+        </div>
+        <div className="">
+          <h1>Game Info</h1>
+          <p>Game name: {this.props.gameInfo.name}</p>
+          <p>Description: {this.props.gameInfo.desc}</p>
+          <p>Start date: {this.props.gameInfo.startdate}</p>
+          <p>End date: {this.props.gameInfo.enddate}</p>
+          <h2>Factions</h2>
+          <div>
+            {this.props.gameInfo.factions.map(faction => (
+              <p key={faction.factionId} style={{ color: faction.colour }}>
+                {faction.factionName}
+              </p>
+            ))}
+          </div>
+          <div>
+            <Map
+              id="gameInfoCenterMap"
+              className=""
+              center={[
+                this.props.gameInfo.center.lat,
+                this.props.gameInfo.center.lng
+              ]}
+              zoom="13"
+              maxZoom="13"
+              style={{ height: "400px", width: "400px" }}
+            >
+              <TileLayer
+                attribution="Maanmittauslaitoksen kartta"
+                url=" https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg"
+              />
+            </Map>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/components/GameList.js b/src/components/GameList.js
index 4796e8a1c3dfe575f9efded6b02c2017ece1e8eb..c7df36e8ae8147d2e051ac1976101689f208abee 100644
--- a/src/components/GameList.js
+++ b/src/components/GameList.js
@@ -35,8 +35,6 @@ class GameList extends React.Component {
               ? games[0].id
               : undefined
         });
-        // taking the initialized gameID to App.js (GameList.js -> GameSidebar.js -> Header.js -> App.js)
-        this.props.handleGameChange(games[0].id);
       })
       .catch(error => {
         console.log(error);
@@ -89,10 +87,7 @@ class GameList extends React.Component {
     ));
 
     return (
-      <div
-        className="gamelist"
-        style={{ maxHeight: "500px", overflow: "scroll" }}
-      >
+      <div className="gamelist">
         <div className="gamelist-item">{gamelistItems}</div>
       </div>
     );
diff --git a/src/components/GameStateButtons.js b/src/components/GameStateButtons.js
index c770ed7896facdddaf56adecde4c689d10dbeb3f..946f9e5b14003d7ad793f08bc9a8f67da8196dea 100644
--- a/src/components/GameStateButtons.js
+++ b/src/components/GameStateButtons.js
@@ -6,53 +6,71 @@ export default class GameStateButtons extends React.Component {
   };
 
   setGameState(state) {
-    console.log(state);
-    let token = sessionStorage.getItem("token");
-    let error = false;
-    fetch(
-      `${process.env.REACT_APP_API_URL}/game/edit-state/${this.props.gameId}`,
-      {
-        method: "PUT",
-        headers: {
-          Authorization: "Bearer " + token,
-          Accept: "application/json",
-          "Content-Type": "application/json"
-        },
-        body: JSON.stringify({
-          id: this.props.gameId,
-          state: state
-        })
-      }
-    )
-      .then(res => {
-        if (!res.ok) {
-          error = true;
-        }
-        return res.json();
-      })
-      .then(res => {
-        if (error) {
-          console.log(res);
-        } else {
-          alert(`Game state changed to ${state}`);
-          this.setState({ gameState: state });
+    if (
+      window.confirm(`Are you sure you want to change game state to ${state}?`)
+    ) {
+      let token = sessionStorage.getItem("token");
+      let error = false;
+      fetch(
+        `${process.env.REACT_APP_API_URL}/game/edit-state/${this.props.gameId}`,
+        {
+          method: "PUT",
+          headers: {
+            Authorization: "Bearer " + token,
+            Accept: "application/json",
+            "Content-Type": "application/json"
+          },
+          body: JSON.stringify({
+            id: this.props.gameId,
+            state: state
+          })
         }
-      })
-      .catch(error => console.log(error));
+      )
+        .then(res => {
+          if (!res.ok) {
+            error = true;
+          }
+          return res.json();
+        })
+        .then(res => {
+          if (error) {
+            console.log(res);
+          } else {
+            alert(`Game state changed to ${state}`);
+            this.setState({ gameState: state });
+          }
+        })
+        .catch(error => console.log(error));
+    }
   }
 
   render() {
     if (this.state.gameState === "CREATED") {
       return (
-        <button onClick={() => this.setGameState("STARTED")}>Start</button>
+        <button
+          id="gameStateStartButton"
+          onClick={() => this.setGameState("STARTED")}
+        >
+          Start
+        </button>
       );
     }
 
     if (this.state.gameState === "STARTED") {
       return (
         <Fragment>
-          <button onClick={() => this.setGameState("PAUSED")}>Pause</button>
-          <button onClick={() => this.setGameState("ENDED")}>Stop</button>
+          <button
+            id="gameStatePauseButton"
+            onClick={() => this.setGameState("PAUSED")}
+          >
+            Pause
+          </button>
+          <button
+            id="gameStateStopButton"
+            onClick={() => this.setGameState("ENDED")}
+          >
+            Stop
+          </button>
         </Fragment>
       );
     }
@@ -60,8 +78,18 @@ export default class GameStateButtons extends React.Component {
     if (this.state.gameState === "PAUSED") {
       return (
         <Fragment>
-          <button onClick={() => this.setGameState("STARTED")}>Continue</button>
-          <button onClick={() => this.setGameState("ENDED")}>Stop</button>
+          <button
+            id="gameStateContinueButton"
+            onClick={() => this.setGameState("STARTED")}
+          >
+            Continue
+          </button>
+          <button
+            id="gameStateStopButton"
+            onClick={() => this.setGameState("ENDED")}
+          >
+            Stop
+          </button>
         </Fragment>
       );
     }
diff --git a/src/components/GameView.js b/src/components/GameView.js
index a6f19ecd92759fa930d68769bd7a14535d32aba1..73f61c60cfb6160af96c32850113f711bb2f2eb7 100644
--- a/src/components/GameView.js
+++ b/src/components/GameView.js
@@ -8,6 +8,8 @@ import PlayerlistView from "./PlayerlistView";
 import NotificationView from "./NotificationView";
 import GameStateButtons from "./GameStateButtons";
 import ClientSocket from "./Socket";
+import NotificationPopup from "./NotificationPopup";
+import GameInfoView from "./GameInfoView";
 
 export default class GameView extends React.Component {
   state = {
@@ -18,7 +20,8 @@ export default class GameView extends React.Component {
     lng: 25.7597186,
     zoom: 13,
     mapUrl: "https://tiles.kartat.kapsi.fi/taustakartta/{z}/{x}/{y}.jpg",
-    socketSignal: null
+    socketSignal: null,
+    socket: null
   };
 
   componentDidMount() {
@@ -79,24 +82,54 @@ export default class GameView extends React.Component {
     )
       .then(res => {
         if (!res.ok) {
-          error = true;
+          throw Error();
+        } else {
+          return res.json();
         }
-        return res.json();
       })
       .then(res => {
         alert(res.message);
         this.getPlayerRole(this.state.gameInfo.id);
       })
-      .catch(error => console.log(error));
+      .catch(error => {
+        alert("Game not found");
+        window.document.location.href = "/";
+      });
+  };
+
+  handleLeaveFaction = e => {
+    if (window.confirm("Are you sure you want to leave your faction?")) {
+      let token = sessionStorage.getItem("token");
+      fetch(
+        `${process.env.REACT_APP_API_URL}/faction/leave/${
+          this.state.gameInfo.id
+        }`,
+        {
+          method: "DELETE",
+          headers: {
+            Authorization: "Bearer " + token
+          }
+        }
+      )
+        .then(res => {
+          if (!res.ok) {
+          }
+          return res.json();
+        })
+        .then(res => {
+          alert(res.message);
+          this.getPlayerRole(this.state.gameInfo.id);
+        })
+        .catch(error => console.log(error));
+    }
   };
 
   // setting the socket signal automatically fires shouldComponentUpdate function where socketSignal prop is present
   // setting socketSignal to null immediately after to avoid multiple database fetches
-  getSocketSignal = type => {
-    console.log(type);
+  getSocketSignal = data => {
     this.setState(
       {
-        socketSignal: type
+        socketSignal: data
       },
       () => {
         this.setState({
@@ -106,13 +139,18 @@ export default class GameView extends React.Component {
     );
   };
 
+  onSocketChange = newSocket => {
+    this.setState({
+      socket: newSocket
+    });
+  };
+
   render() {
     const initialPosition = [this.state.lat, this.state.lng];
-
     return (
       <div>
         <Link to="/">
-          <button>Game selection</button>
+          <button id="gameViewGameSelectionButton">Game selection</button>
         </Link>
         {this.state.gameInfo !== null && (
           <div>
@@ -120,6 +158,7 @@ export default class GameView extends React.Component {
               <ClientSocket
                 gameId={this.state.gameInfo.id}
                 getSocketSignal={this.getSocketSignal}
+                onSocketChange={this.onSocketChange}
               />
             )}
             <div>Game Name: {this.state.gameInfo.name}</div>
@@ -129,14 +168,21 @@ export default class GameView extends React.Component {
             {this.state.role !== "" && (
               <div>Your role in this game: {this.state.role}</div>
             )}
-            {this.state.role === "admin" && (
-              <button
-                id="editGameButton"
-                onClick={() => this.setState({ form: "edit" })}
-              >
-                Edit
-              </button>
-            )}
+            {this.state.role === "admin" &&
+              this.state.gameInfo.state === "CREATED" && (
+                <button
+                  id="editGameButton"
+                  onClick={() => this.setState({ form: "edit" })}
+                >
+                  Edit
+                </button>
+              )}
+            <button
+              id="gameInfoButton"
+              onClick={() => this.setState({ form: "info" })}
+            >
+              Game Info
+            </button>
             {this.state.role === "" && (
               <button
                 id="joinGameButton"
@@ -163,6 +209,7 @@ export default class GameView extends React.Component {
               <TaskListButton
                 gameId={this.state.gameInfo.id}
                 role={this.state.role}
+                factions={this.state.gameInfo.factions}
               />
             )}
             {this.state.role !== "admin" && this.state.role !== "" && (
@@ -181,16 +228,20 @@ export default class GameView extends React.Component {
               zoom={this.state.zoom}
               mapUrl={this.state.mapUrl}
               currentGameId={this.state.gameInfo.id}
-              socketSignal={this.state.socketSignal}
+              socketSignal={
+                this.state.socketSignal === null
+                  ? null
+                  : this.state.socketSignal.type
+              }
               role={this.state.role}
-            />
+            >
+              <NotificationPopup socketSignal={this.state.socketSignal} />
+            </UserMap>
             {this.state.form === "edit" && (
               <EditGameForm
                 gameId={this.state.gameInfo.id}
                 toggleView={() => this.setState({ form: "" })}
-                onEditSave={() => {
-                  this.getGameInfo(this.state.gameInfo.id);
-                }}
+                onEditSave={() => this.getGameInfo(this.state.gameInfo.id)}
               />
             )}
             {this.state.form === "join" && (
@@ -211,6 +262,19 @@ export default class GameView extends React.Component {
               <NotificationView
                 gameId={this.state.gameInfo.id}
                 toggleView={() => this.setState({ form: "" })}
+                socket={this.state.socket}
+                role={this.state.role}
+                gameState={
+                  this.state.gameInfo !== undefined
+                    ? this.state.gameInfo.state
+                    : ""
+                }
+              />
+            )}
+            {this.state.form === "info" && (
+              <GameInfoView
+                gameInfo={this.state.gameInfo}
+                toggleView={() => this.setState({ form: "" })}
               />
             )}
           </div>
diff --git a/src/components/JoinGameForm.js b/src/components/JoinGameForm.js
index b638b61f2aeb6ac745f9afde6aa833103f69d318..35841c043a890f8ed4450590afe7740fb00c7028 100644
--- a/src/components/JoinGameForm.js
+++ b/src/components/JoinGameForm.js
@@ -105,6 +105,7 @@ export default class JoinGameForm extends React.Component {
             <h1>Join game: {this.state.gameJSON.name}</h1>
             <h2>Description: {this.state.gameJSON.desc}</h2>
             <select
+              id="selectFactionList"
               onChange={e =>
                 this.setState({ selectedFactionId: e.target.value })
               }
diff --git a/src/components/LoginForm.js b/src/components/LoginForm.js
index b71777f007071ead97db3da75187caa80728a10d..d1e90cb994a8abfd30e15ad81aaaac2ac6c64ad9 100644
--- a/src/components/LoginForm.js
+++ b/src/components/LoginForm.js
@@ -87,7 +87,7 @@ export class LoginForm extends React.Component {
             <h2>{this.state.errorMsg}</h2>
           </form>
           <Link to="/register">
-            <button>Create account</button>
+            <button id="loginRegisterButton">Create account</button>
           </Link>
         </div>
       </div>
diff --git a/src/components/NotificationCard.js b/src/components/NotificationCard.js
new file mode 100644
index 0000000000000000000000000000000000000000..cf49d28f285a8f6f662007b947b1d7a42cc682fc
--- /dev/null
+++ b/src/components/NotificationCard.js
@@ -0,0 +1,11 @@
+import React from "react";
+
+export default class NotificationCard extends React.Component {
+  render() {
+    return (
+      <div>
+        {this.props.notification.type} : {this.props.notification.message}
+      </div>
+    );
+  }
+}
diff --git a/src/components/NotificationPopup.js b/src/components/NotificationPopup.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3e9a723a6b62f03d7ace1024c1912e8f32ee38a
--- /dev/null
+++ b/src/components/NotificationPopup.js
@@ -0,0 +1,58 @@
+import React from "react";
+
+export default class NotificationPopup extends React.Component {
+  state = {
+    lastNotification: null,
+    visible: true
+  };
+
+  componentDidUpdate(prevProps, prevState) {
+    if (
+      prevProps.socketSignal !== null &&
+      prevProps.socketSignal !== this.state.lastNotification
+    ) {
+      if (prevProps.socketSignal.type === "alert") {
+        this.setState({
+          lastNotification: prevProps.socketSignal,
+          visible: true
+        });
+      }
+      if (prevProps.socketSignal.type === "note") {
+        this.setState({
+          lastNotification: prevProps.socketSignal,
+          visible: true
+        });
+      }
+    }
+  }
+
+  render() {
+    if (this.state.lastNotification !== null && this.state.visible) {
+      return (
+        <div
+          className={
+            this.state.lastNotification.type === "alert"
+              ? "notification-popup alert"
+              : "notification-popup warning"
+          }
+        >
+          <button
+            id="NotificationPopupCloseButton"
+            onClick={() => {
+              this.setState({ visible: false });
+            }}
+          >
+            Close
+          </button>
+          <br />
+          <label>
+            {this.state.lastNotification.type === "alert" ? "ALERT" : "Note"}
+          </label>
+          <p>{this.state.lastNotification.message}</p>
+        </div>
+      );
+    }
+
+    return false;
+  }
+}
diff --git a/src/components/NotificationView.js b/src/components/NotificationView.js
index 5fcf80141e569562492417d719854bd7b654ced1..d63d0253b0f585b9ad7d904fb9eaced0fa28b3d9 100644
--- a/src/components/NotificationView.js
+++ b/src/components/NotificationView.js
@@ -1,7 +1,99 @@
 import React from "react";
+import NotificationCard from "./NotificationCard";
 
 export default class NotificationView extends React.Component {
+  state = {
+    notifications: [],
+    notificationInput: "",
+    notificationTypeInput: "note"
+  };
+
+  componentDidMount() {
+    this.getNotifications(this.props.gameId);
+  }
+
+  getNotifications(gameId) {
+    let token = sessionStorage.getItem("token");
+    fetch(`${process.env.REACT_APP_API_URL}/notifications/${gameId}`, {
+      headers: {
+        Authorization: "Bearer " + token
+      }
+    })
+      .then(res => res.json())
+      .then(res => {
+        this.setState({ notifications: res.reverse() });
+      });
+  }
+
+  handleSend = e => {
+    e.preventDefault();
+
+    if (this.state.notificationInput === "") {
+      alert("notification message can't be empty");
+    } else if (
+      window.confirm("Are you sure you want to send the notification")
+    ) {
+      this.props.socket.emit("game-info", {
+        type: this.state.notificationTypeInput,
+        message: this.state.notificationInput,
+        game: this.props.gameId
+      });
+      alert("Notification sent");
+      this.getNotifications(this.props.gameId);
+      this.setState({ notificationInput: "" });
+    }
+  };
+
   render() {
-    return false;
+    let notifications = this.state.notifications.map(notification => (
+      <NotificationCard key={notification.id} notification={notification} />
+    ));
+
+    return (
+      <div className="fade-main">
+        <button
+          id="notificationViewCloseButton"
+          onClick={() => this.props.toggleView()}
+        >
+          Close
+        </button>
+        <div>
+          {this.props.role === "admin" &&
+            this.props.gameState !== "ENDED" &&
+            this.props.gameState !== "CREATED" && (
+              <form onSubmit={this.handleSend}>
+                <select
+                  id="notificationViewTypeSelect"
+                  value={this.state.notificationTypeInput}
+                  onChange={e =>
+                    this.setState({ notificationTypeInput: e.target.value })
+                  }
+                >
+                  <option value="note">Note</option>
+                  <option value="alert">Alert</option>
+                </select>
+                <input
+                  id="notificationViewMessageInput"
+                  type="text"
+                  value={this.state.notificationInput}
+                  onChange={e =>
+                    this.setState({ notificationInput: e.target.value })
+                  }
+                  placeholder="Notification message..."
+                />
+                <button id="notificationSubmitButton" type="submit">
+                  Send Notification
+                </button>
+              </form>
+            )}
+          {this.props.role === "admin" &&
+            (this.props.gameState === "ENDED" ||
+              this.props.gameState === "CREATED") && (
+              <p>Notifications can only be sent if the game is ongoing</p>
+            )}
+        </div>
+        {notifications}
+      </div>
+    );
   }
 }
diff --git a/src/components/PlayerlistPlayerCard.js b/src/components/PlayerlistPlayerCard.js
index ebc2ddeb5c6eb75958cf6390404206f488f73878..7260d5abaa4b4f617cb32ea7b428756f5ab606ba 100644
--- a/src/components/PlayerlistPlayerCard.js
+++ b/src/components/PlayerlistPlayerCard.js
@@ -69,13 +69,20 @@ export default class PlayerlistPlayerCard extends React.Component {
         <div>
           {this.props.player.person.name} :{" "}
           <select
+            id={"playerCardRoleSelect" + this.props.player.person.name}
             value={this.state.roleInput}
             onChange={e => this.setState({ roleInput: e.target.value })}
           >
             {roleOptions()}
           </select>
-          <button onClick={this.handleSave}>Save</button>
           <button
+            id={"playerCardSaveButton" + this.props.player.person.name}
+            onClick={this.handleSave}
+          >
+            Save
+          </button>
+          <button
+            id={"playerCardCancelButton" + this.props.player.person.name}
             onClick={() => {
               this.setState({ edit: false, roleInput: this.props.player.role });
             }}
@@ -92,16 +99,13 @@ export default class PlayerlistPlayerCard extends React.Component {
         {this.props.player.person.name} : {this.state.edit && roleOptions()}
         {!this.state.edit && this.props.player.role}
         {this.props.role === "admin" && !this.state.edit && (
-          <button onClick={() => this.setState({ edit: !this.state.edit })}>
+          <button
+            id={"playerCardEditButton" + this.props.player.person.name}
+            onClick={() => this.setState({ edit: !this.state.edit })}
+          >
             Edit
           </button>
         )}
-        {this.state.edit && (
-          <Fragment>
-            <button>Save</button>
-            <button>Cancel</button>
-          </Fragment>
-        )}
       </div>
     );
   }
diff --git a/src/components/PlayerlistView.js b/src/components/PlayerlistView.js
index 6967b0e2e0dc25017ff4940710e3d1e4488a6150..60c294fc257c3f12cd9fded17659c8e0323be4c5 100644
--- a/src/components/PlayerlistView.js
+++ b/src/components/PlayerlistView.js
@@ -71,7 +71,7 @@ export default class PlayerlistView extends React.Component {
       <div className="fade-main">
         <div className="sticky">
           <span
-            id="closeEditGameFormX"
+            id="closePlayerlistX"
             className="close"
             onClick={() => this.props.toggleView()}
           >
diff --git a/src/components/RegisterForm.js b/src/components/RegisterForm.js
index 889f3351917fd7d4366fa0afde5ed3b3f348ae68..b0e2ad24bae0139169c94b6d5447c508e4fecb1d 100644
--- a/src/components/RegisterForm.js
+++ b/src/components/RegisterForm.js
@@ -72,6 +72,7 @@ export class RegisterForm extends React.Component {
             <h1>Register</h1>
             <br />
             <input
+              id="registerUsernameInput"
               placeholder="Enter Username"
               name="username"
               value={this.state.username}
@@ -81,6 +82,7 @@ export class RegisterForm extends React.Component {
             />
             <br />
             <input
+              id="registerPasswordInput"
               placeholder="Enter password"
               type="password"
               name="password"
@@ -90,6 +92,7 @@ export class RegisterForm extends React.Component {
             />
             <br />
             <input
+              id="registerPasswordVerifyInput"
               placeholder="Verify password"
               type="password"
               name="password2"
@@ -98,11 +101,13 @@ export class RegisterForm extends React.Component {
               //required
             />
             <br />
-            <button type="submit">Submit</button>
+            <button id="submitRegisterButton" type="submit">
+              Submit
+            </button>
             <h2>{this.state.errorMsg}</h2>
           </form>
           <Link to="/">
-            <button>Login</button>
+            <button id="openLoginFormButton">Login</button>
           </Link>
         </div>
       </div>
diff --git a/src/components/Socket.js b/src/components/Socket.js
index 8256585f5df46e07970c64e774e79c586c3522cb..07142e51ea875131ffa3605ce2f83fcee746fd01 100644
--- a/src/components/Socket.js
+++ b/src/components/Socket.js
@@ -20,8 +20,8 @@ export default class ClientSocket extends React.Component {
     console.log("hi socket");
     // need to explicitly update drawings and trackings when gameID first becomes available
     if (this.props.gameId !== null) {
-      await this.props.getSocketSignal("drawing-update");
-      await this.props.getSocketSignal("tracking-update");
+      await this.props.getSocketSignal({ type: "drawing-update" });
+      await this.props.getSocketSignal({ type: "tracking-update" });
     }
     this.initSocket();
   }
@@ -38,7 +38,7 @@ export default class ClientSocket extends React.Component {
 
   // disconnect the socket on component dismount
   componentWillUnmount() {
-    console.log("bye socket");
+    // console.log("bye socket");
     this.state.sock.disconnect();
   }
 
@@ -47,11 +47,12 @@ export default class ClientSocket extends React.Component {
 
     // set the socket to listen gameId-thread
     socket.on(this.props.gameId, data => {
-      this.props.getSocketSignal(data.type);
+      this.props.getSocketSignal(data);
       // check socket update type
-      this.setState({ update: data.type });
+      this.setState({ update: data });
     });
 
+    this.props.onSocketChange(socket);
     this.setState({ sock: socket });
   };
 
diff --git a/src/components/TaskItem.js b/src/components/TaskItem.js
index 0265ca779fe1efdea077bca5c26557726f4400c1..21644f10a0bde41ed9d09b7c0a02406969ede078 100644
--- a/src/components/TaskItem.js
+++ b/src/components/TaskItem.js
@@ -96,11 +96,17 @@ class TaskItem extends React.Component {
           )}
         </div>
         {this.props.task.taskIsActive && this.props.role === "admin" && (
-          <button onClick={this.onEditClick}>Edit</button>
+          <button
+            id={"taskEditButton" + this.props.task.taskName}
+            onClick={this.onEditClick}
+          >
+            Edit
+          </button>
         )}
         {this.state.edit && (
           <form onSubmit={this.onSaveSubmit}>
             <select
+              id={"taskWinnerSelect" + this.props.task.taskName}
               value={this.state.selectedFactionId}
               onChange={e =>
                 this.setState({ selectedFactionId: e.target.value })
@@ -113,6 +119,7 @@ class TaskItem extends React.Component {
         )}
         {this.props.role === "admin" && (
           <button
+            id={"taskDeleteButton" + this.props.task.taskName}
             onClick={this.onTaskDelete}
             style={{ backgroundColor: "red" }}
           >
diff --git a/src/components/TaskList.js b/src/components/TaskList.js
index 241caa494f16220184c55288e637d54b4585dd52..1b8e1374f85cb8c81b6212368e370e9c1495c3cf 100644
--- a/src/components/TaskList.js
+++ b/src/components/TaskList.js
@@ -9,14 +9,12 @@ class TaskList extends React.Component {
       taskNameInput: "", // 3-31 chars
       taskDescriptionInput: "", // 0-255
       tasks: [],
-      factionlist: [],
       selectedFactionId: ""
     };
   }
 
   componentDidMount() {
     this.getTasks(this.props.gameId);
-    this.getFactionlist(this.props.gameId); // TODO: remove if the user is not admin?
   }
 
   getTasks(gameId) {
@@ -42,25 +40,6 @@ class TaskList extends React.Component {
       .catch(error => console.log(error));
   }
 
-  getFactionlist(gameId) {
-    fetch(`${process.env.REACT_APP_API_URL}/game/${gameId}`, {
-      method: "GET"
-    })
-      .then(result => {
-        if (!result.ok) {
-          throw Error(result.responseText);
-        } else {
-          return result.json();
-        }
-      })
-      .then(result => {
-        this.setState({
-          factionlist: result.factions
-        });
-      })
-      .catch(error => console.log(error));
-  }
-
   handleTaskCreation = e => {
     e.preventDefault();
     if (this.state.taskNameInput === "") {
@@ -206,10 +185,10 @@ class TaskList extends React.Component {
       }
     }
 
-    let factionlistItems = this.state.factionlist.map(item => {
+    let factionlistItems = this.props.factions.map(faction => {
       return (
-        <option key={item.factionId} value={item.factionId}>
-          {item.factionName}
+        <option key={faction.factionId} value={faction.factionId}>
+          {faction.factionName}
         </option>
       );
     });
diff --git a/src/components/TaskListButton.js b/src/components/TaskListButton.js
index c0e5f8c1257edaaae2e062fbc8dce562538aa5c1..bb56314129f92204ab45d226b3d0f69593b18d05 100644
--- a/src/components/TaskListButton.js
+++ b/src/components/TaskListButton.js
@@ -45,7 +45,11 @@ export default class TaskListButton extends React.Component {
           Tasks
         </button>
         {this.state.open && (
-          <TaskList gameId={this.props.gameId} role={this.props.role} />
+          <TaskList
+            gameId={this.props.gameId}
+            role={this.props.role}
+            factions={this.props.factions}
+          />
         )}
       </Fragment>
     );
diff --git a/src/components/UserMap.js b/src/components/UserMap.js
index e9b2b26252fc313e0d5b171d7c36bf71e684ebf8..83f4de8d09da8efa58426855273b27fbf4145b0b 100644
--- a/src/components/UserMap.js
+++ b/src/components/UserMap.js
@@ -39,6 +39,7 @@ class UserMap extends Component {
   }
 
   componentDidUpdate(prevProps, prevState) {
+    console.log(prevProps.socketSignal);
     if (prevProps.socketSignal === "drawing-update") {
       this.fetchGeoJSON();
     }
@@ -162,15 +163,13 @@ class UserMap extends Component {
           url={this.props.mapUrl}
         />
         <ZoomControl position="topright" />
-        {(this.props.role === "admin" ||
-          this.props.role === "factionleader") && (
-          <DrawTools
-            position={this.props.position}
-            sendGeoJSON={this.sendGeoJSON}
-            geoJSONLayer={this.state.geoJSONLayer}
-            currentGameId={this.props.currentGameId}
-          />
-        )}
+        <DrawTools
+          position={this.props.position}
+          sendGeoJSON={this.sendGeoJSON}
+          geoJSONLayer={this.state.geoJSONLayer}
+          currentGameId={this.props.currentGameId}
+          role={this.props.role}
+        />
         {this.state.ownLat !== null && (
           <Marker position={[this.state.ownLat, this.state.ownLng]}>
             <Popup>
@@ -183,6 +182,7 @@ class UserMap extends Component {
           currentGameId={this.props.currentGameId}
           socketSignal={this.props.socketSignal}
         />
+        {this.props.children}
       </Map>
     );
   }