diff --git a/package-lock.json b/package-lock.json index 2207e63b9..db958783b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1162,6 +1162,39 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==" }, + "@react-bootstrap/react-popper": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@react-bootstrap/react-popper/-/react-popper-1.2.1.tgz", + "integrity": "sha512-4l3q7LcZEhrSkI4d3Ie3g4CdrXqqTexXX4PFT45CB0z5z2JUbaxgRwKNq7r5j2bLdVpZm+uvUGqxJw8d9vgbJQ==", + "requires": { + "babel-runtime": "6.x.x", + "create-react-context": "^0.2.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.5", + "warning": "^3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, + "@restart/context": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", + "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==" + }, + "@restart/hooks": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.1.tgz", + "integrity": "sha512-kjGGlli8iTe5TFDw6qHZJ5QK1naITMveIO+o8yQJJqwX8VIkiQzLddK98Lduga2krJMzWlNqDR/4isGLiyBlUA==" + }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz", @@ -1902,6 +1935,38 @@ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, + "axios": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz", + "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==", + "requires": { + "follow-redirects": "1.5.10", + "is-buffer": "^2.0.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "follow-redirects": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", + "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==", + "requires": { + "debug": "=3.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "axobject-query": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz", @@ -2396,6 +2461,11 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, + "bootstrap": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz", + "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3327,6 +3397,11 @@ } } }, + "classnames": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" + }, "clean-css": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", @@ -3677,6 +3752,15 @@ "sha.js": "^2.4.8" } }, + "create-react-context": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.3.tgz", + "integrity": "sha512-CQBmD0+QGgTaxDL3OX1IDXYqjkp2It4RIbcb99jS6AEg27Ga+a9G3JtK6SIu0HBwPLZlmwt9F7UwWA4Bn92Rag==", + "requires": { + "fbjs": "^0.8.0", + "gud": "^1.0.0" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -4234,6 +4318,14 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, "dom-serializer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz", @@ -4360,6 +4452,14 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -5200,6 +5300,35 @@ "bser": "^2.0.0" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, "figgy-pudding": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", @@ -5603,6 +5732,11 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "gzip-size": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", @@ -5777,6 +5911,19 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/history/-/history-4.9.0.tgz", + "integrity": "sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^2.2.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^0.4.0" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -5787,6 +5934,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", + "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "requires": { + "react-is": "^16.7.0" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -6378,6 +6533,15 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -7701,6 +7865,11 @@ "array-includes": "^3.0.3" } }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -8134,6 +8303,16 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" }, + "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", + "integrity": "sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw==", + "requires": { + "@babel/runtime": "^7.4.0", + "gud": "^1.0.0", + "tiny-warning": "^1.0.2" + } + }, "mini-css-extract-plugin": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz", @@ -8330,6 +8509,15 @@ "lower-case": "^1.1.1" } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", @@ -8983,6 +9171,11 @@ "ts-pnp": "^1.0.0" } }, + "popper.js": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz", + "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==" + }, "portfinder": { "version": "1.0.20", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", @@ -9924,6 +10117,25 @@ "react-is": "^16.8.1" } }, + "prop-types-extra": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.0.tgz", + "integrity": "sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg==", + "requires": { + "react-is": "^16.3.2", + "warning": "^3.0.0" + }, + "dependencies": { + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "property-information": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.1.0.tgz", @@ -10096,6 +10308,33 @@ "whatwg-fetch": "3.0.0" } }, + "react-bootstrap": { + "version": "1.0.0-beta.9", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.0.0-beta.9.tgz", + "integrity": "sha512-M0BYLuuUdMITJ16+DDDb1p4vWV87csEBi/uOxZYODuDZh7hvbrJVahfvPXcqeqq4eEpNL+PKSlqb9fNaY0HZyA==", + "requires": { + "@babel/runtime": "^7.4.2", + "@react-bootstrap/react-popper": "1.2.1", + "@restart/context": "^2.1.4", + "@restart/hooks": "^0.3.0", + "classnames": "^2.2.6", + "dom-helpers": "^3.4.0", + "invariant": "^2.2.4", + "keycode": "^2.2.0", + "popper.js": "^1.14.7", + "prop-types": "^15.7.2", + "prop-types-extra": "^1.1.0", + "react-overlays": "^1.2.0", + "react-transition-group": "^4.0.0", + "uncontrollable": "^6.1.0", + "warning": "^4.0.3" + } + }, + "react-context-toolbox": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-context-toolbox/-/react-context-toolbox-2.0.2.tgz", + "integrity": "sha512-tY4j0imkYC3n5ZlYSgFkaw7fmlCp3IoQQ6DxpqeNHzcD0hf+6V+/HeJxviLUZ1Rv1Yn3N3xyO2EhkkZwHn0m1A==" + }, "react-dev-utils": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-9.0.1.tgz", @@ -10194,6 +10433,96 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", "integrity": "sha512-aUk3bHfZ2bRSVFFbbeVS4i+lNPZr3/WM5jT2J5omUVV1zzcs1nAaf3l51ctA5FFvCRbhrH0bdAsRRQddFJZPtA==" }, + "react-overlays": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-1.2.0.tgz", + "integrity": "sha512-i/FCV8wR6aRaI+Kz/dpJhOdyx+ah2tN1RhT9InPrexyC4uzf3N4bNayFTGtUeQVacj57j1Mqh1CwV60/5153Iw==", + "requires": { + "classnames": "^2.2.6", + "dom-helpers": "^3.4.0", + "prop-types": "^15.6.2", + "prop-types-extra": "^1.1.0", + "react-context-toolbox": "^2.0.2", + "react-popper": "^1.3.2", + "uncontrollable": "^6.0.0", + "warning": "^4.0.2" + } + }, + "react-popper": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.3.tgz", + "integrity": "sha512-ynMZBPkXONPc5K4P5yFWgZx5JGAUIP3pGGLNs58cfAPgK67olx7fmLp+AdpZ0+GoQ+ieFDa/z4cdV6u7sioH6w==", + "requires": { + "@babel/runtime": "^7.1.2", + "create-react-context": "<=0.2.2", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + }, + "dependencies": { + "create-react-context": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz", + "integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==", + "requires": { + "fbjs": "^0.8.0", + "gud": "^1.0.0" + } + }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + } + } + }, + "react-router": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.0.1.tgz", + "integrity": "sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.3.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "react-router-dom": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.0.1.tgz", + "integrity": "sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA==", + "requires": { + "@babel/runtime": "^7.1.2", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.0.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "react-scripts": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-3.0.1.tgz", @@ -10254,6 +10583,27 @@ "workbox-webpack-plugin": "4.2.0" } }, + "react-transition-group": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.1.1.tgz", + "integrity": "sha512-K/N1wqJ2GRP2yj3WBqEUYa0KV5fiaAWpUfU9SpHOHefeKvyrO+VrnMBML21M19QZoVbDZKmuQFHZYoMMi1xuJA==", + "requires": { + "@babel/runtime": "^7.4.5", + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + } + } + }, "read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -10575,6 +10925,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -11685,6 +12040,16 @@ "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz", "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=" }, + "tiny-invariant": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.0.4.tgz", + "integrity": "sha512-lMhRd/djQJ3MoaHEBrw8e2/uM4rs9YMNk0iOr8rHQ0QdbM7D4l0gFl3szKdeixrlyfm9Zqi4dxHCM2qVG8ND5g==" + }, + "tiny-warning": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.2.tgz", + "integrity": "sha512-rru86D9CpQRLvsFG5XFdy0KdLAvjdQDyZCsRcuu60WtzFylDM3eAWSxEVz5kzL2Gp544XiUvPbVKtOA/txLi9Q==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -11821,11 +12186,21 @@ "mime-types": "~2.1.24" } }, + "typed-styles": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz", + "integrity": "sha512-ht+rEe5UsdEBAa3gr64+QjUOqjOLJfWLvl5HZR5Ev9uo/OnD3p43wPeFSB1hNFc13GXQF/JU1Bn0YHLUqBRIlw==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "ua-parser-js": { + "version": "0.7.20", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", + "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==" + }, "uglify-js": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", @@ -11847,6 +12222,25 @@ } } }, + "uncontrollable": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-6.2.3.tgz", + "integrity": "sha512-VgOAoBU2ptCL2bfTG2Mra0I8i1u6Aq84AFonD5tmCAYSfs3hWvr2Rlw0q2ntoxXTHjcQOmZOh3FKaN+UZVyREQ==", + "requires": { + "@babel/runtime": "^7.4.5", + "invariant": "^2.2.4" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.4.5.tgz", + "integrity": "sha512-TuI4qpWZP6lGOGIuGWtp9sPluqYICmbk8T/1vpSysqJxRPkudh/ofFWyqdcMsDf2s7KvDL4/YHgKyvcS3g9CJQ==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + } + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -12122,6 +12516,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -12212,6 +12611,14 @@ "makeerror": "1.0.x" } }, + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "watchpack": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", diff --git a/package.json b/package.json index e7e4a7c62..e092f2f8c 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,12 @@ "version": "0.1.0", "private": true, "dependencies": { + "axios": "^0.19.0", + "bootstrap": "^4.3.1", "react": "^16.8.6", + "react-bootstrap": "^1.0.0-beta.9", "react-dom": "^16.8.6", + "react-router-dom": "^5.0.1", "react-scripts": "3.0.1" }, "scripts": { @@ -12,5 +16,17 @@ "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } } diff --git a/src/App.css b/src/App.css index c5c6e8a68..d81badff8 100644 --- a/src/App.css +++ b/src/App.css @@ -1,28 +1,91 @@ -.App { +@import url('https://fonts.googleapis.com/css?family=Limelight&display=swap'); + +.nav_container { + background: #300701 url("https://i.kinja-img.com/gawker-media/image/upload/s--m9daP_xN--/c_scale,f_auto,fl_progressive,q_80,w_800/unsnbwg2cke5spzlpsuy.jpg") no-repeat center top; + background-size: 100% 180%; + display: flex; + flex-direction: column; + height: 15rem; +} + +.brand { + display: flex; + flex-direction: row; + justify-content: center; + text-shadow: + -1px -1px 0 white, + 1px -1px 0 white, + -1px 1px 0 white, + 1px 1px 0 white; + color: black; + font-size: 6rem; + text-decoration-line: none; + margin-left: 1rem; text-align: center; + margin-top: 20px; + font-family: 'Limelight', cursive; } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 80px; +.nav { + display: flex; + justify-content: center; } -.App-header { - background-color: #222; - height: 150px; - padding: 20px; +.nav_link { + font-family: 'Limelight', cursive; color: white; + text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; + font-size: 2rem; + text-decoration: none; + padding-left: 15px; + padding-right: 15px; +} + +.nav_link:first-child { + border-left: none; } -.App-title { - font-size: 1.5em; +.nav_link:hover { + color: red; + text-shadow: + -1px -1px 0 #990708, + 1px -1px 0 #990708, + -1px 1px 0 #990708, + 1px 1px 0 #990708; + text-decoration: none; } -.App-intro { - font-size: large; +.brand:hover { + color: #990708; + text-shadow: + -1px -1px 0 red, + 1px -1px 0 red, + -1px 1px 0 red, + 1px 1px 0 red; + text-decoration: none; } -@keyframes App-logo-spin { - from { transform: rotate(0deg); } - to { transform: rotate(360deg); } +#rentalSection { + border-top: 10px solid black; + background: white; + padding-bottom: 15px; } + +.currently-selected { + font-size: 1em; + text-align: center; + margin-left: 500px; + margin-right: 500px; + background-color: #FEE1A8; + border: 4px dotted black; + margin-top: 1rem; + padding: 15px; +} + +.rentalHeader { + font-size: 2em; +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 203067e4d..0e6a437dd 100644 --- a/src/App.js +++ b/src/App.js @@ -1,21 +1,355 @@ import React, { Component } from 'react'; -import logo from './logo.svg'; +import 'bootstrap/dist/css/bootstrap.min.css'; +import Nav from 'react-bootstrap/Nav'; +import Button from 'react-bootstrap/Button'; +import { BrowserRouter as Router, Route, Link } from "react-router-dom"; +import Search from './components/Search'; +import Library from './components/Library'; +import Customers from './components/Customers'; +import OverdueMovies from './components/OverdueMovies'; +import axios from 'axios'; import './App.css'; class App extends Component { + constructor() { + super(); + + this.state = { + movies: [], + expandedMovies: {}, + customers: [], + expandedCustomers: {}, + deselectedMovie: null, + rentedMovie: undefined, + chosenCustomer: undefined, + deselectedCustomer: null, + dueDate: undefined, + checkoutDate: undefined, + currentRental: { + count: undefined, + movie: undefined, + customer: undefined, + checkin: false, + }, + allRentals: undefined, + // customerRentals: undefined, + overdueMovies: undefined, + error: null, + }; + } + + componentDidMount() { + axios.get('http://localhost:3001/movies') + .then((response) => { + this.setState({ movies: response.data }); + }) + .catch((error) => { + this.setState({ error: error.message }); + }); + + axios.get('http://localhost:3001/customers') + .then((response) => { + this.setState({ customers: response.data }); + }) + .catch((error) => { + this.setState({ error: error.message }); + }); + } + + addMovieCallback = (movie) => { + const movieIds = this.state.movies.map(movie => movie.id) + this.setState({ + movies: [...this.state.movies, {...movie, id: Math.max(...movieIds) + 1}] + }); + } + + onClickMovieDetailsCallback = (id) => { + const movie = this.state.movies.find(movie => movie.id === id); + const title = movie.title; + + axios.get("http://localhost:3001/movies/" + title) + .then((response) => { + this.setState({ + expandedMovies: { + ...response.data, + } + }); + }) + .catch((error) => { + this.setState({error: error.message}) + }); + } + + onCloseMovieDetailsCallback = () => { + this.setState({ + expandedMovies: null + }); + } + + onSelectMovieCallback = (id) => { + const selectedMovie = this.state.movies.find(movie => movie.id === id); + this.setState({ + rentedMovie: selectedMovie, + deselectedMovie: null + }); + } + + onDeselectMovieCallback = (id) => { + const deselectedMovie = this.state.movies.find(movie => movie.id === id); + + this.setState({ + deselectedMovie: deselectedMovie, + rentedMovie: null, + }); + } + + + onClickCustomerRentalsCallback = (id) => { + this.setState((prevState) => ({ + expandedCustomers: { + ...prevState.expandedCustomers, + [id]: !prevState.expandedCustomers[id], + } + })); + } + + onSelectCustomerCallback = (id) => { + const selectedCustomer = this.state.customers.find(customer => customer.id === id); + this.setState({ + deselectedCustomer: null, + chosenCustomer: selectedCustomer + }); + } + + onDeselectCustomerCallback = (id) => { + const deselectedCustomer = this.state.customers.find(customer => customer.id === id); + this.setState({ + chosenCustomer: null, + deselectedCustomer + }); + } + + rentMovie = () => { + const checkoutDate = new Date(); + const dueDate = new Date(); + dueDate.setDate(dueDate.getDate() + 1 ); + + const url = `http://localhost:3001/rentals/${this.state.rentedMovie.title}/check-out`; + + const params = { + due_date: dueDate, + customer_id: this.state.chosenCustomer.id, + } + + axios.post(url, params) + .then((response)=> { + this.setState((prevState) => ({ + dueDate: dueDate, + checkoutDate: checkoutDate, + currentRental: { + ...prevState.currentRental, + count: response.data["rental"], + movie: prevState.rentedMovie.title, + customer: prevState.chosenCustomer.id, + } + })) + + this.onRentCallback() + }) + .catch((error) => { + this.setState({ + error: error.message + }) + }) + } + + onRentCallback = () => { + this.setState({ + rentedMovie: undefined, + chosenCustomer: undefined, + dueDate: undefined, + checkoutDate: undefined, + }) + } + + checkinMovie = () => { + const url = `http://localhost:3001/rentals/${this.state.currentRental.movie}/return`; + + const params = { + customer_id: this.state.currentRental.customer, + } + + axios.post(url, params) + .then(() => { + this.setState((prevState) => ({ + currentRental: { + ...prevState.currentRental, + count: undefined, + movie: undefined, + customer: undefined, + checkin: true, + } + })) + }) + .catch((error) => { + this.setState({ + error: error.message + }) + }) + } + + setOverdueMoviesCallback = (value) => { + this.setState({ + overdueMovies: value + }) + } + + setErrorOverdueCallback = (error) => { + this.setState({ + error: error.message + }); + } + + onCustomerRentalsCallback = (customerID) => { + let uniqueRentals = {} + + axios.get('http://localhost:3001/rentals') + .then((response) => { + response.data.forEach((rental, i) => { + if (rental !== null) { + uniqueRentals[i] = { + "customer": rental.customer_id, + "movie": rental.title, + "checkout_date": rental.checkout_date, + "due_date": rental.due_date + } + } + }) + + this.setState({ + allRentals: uniqueRentals + }) + + // this.findCustomerRentals(customerID) + this.onClickCustomerRentalsCallback(customerID) + }) + .catch((error) => { + this.setState({ + error: error.message + }); + }); + } + render() { + const errorSection = (this.state.error) ? + (
Error: {this.state.error}
) : null; + + const currentlySelected = (this.state.rentedMovie || this.state.chosenCustomer) ? +
+

ACTIVE RENTAL SELECTION

+ { this.state.rentedMovie &&

Movie: {this.state.rentedMovie.title}

} + + { this.state.chosenCustomer &&

Customer: {this.state.chosenCustomer.name}

} + + { this.state.chosenCustomer && this.state.rentedMovie && } +
: null + return ( -
-
- logo -

Welcome to React

-
-

- To get started, edit src/App.js and save to reload. -

-
+ +
+
+ +
+ {currentlySelected} + + { + this.state.currentRental.count && +
+

Rental #{this.state.currentRental.count}

+

"{this.state.currentRental.movie}" checked out by Customer #{this.state.currentRental.customer}

+ {this.state.currentRental.count && } +
+ } + + { + !this.state.chosenCustomer && !this.state.rentedMovie && + this.state.currentRental.checkin && +

Movie Successfully Checked-In!

+ } + +
+ + {errorSection} + + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> + ( + + )} + /> +
+
); } } +function Header() { + return ( +
+ +
+ ); +} + export default App; diff --git a/src/components/Customer.js b/src/components/Customer.js new file mode 100644 index 000000000..d078fef4c --- /dev/null +++ b/src/components/Customer.js @@ -0,0 +1,67 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import CustomerRentals from './CustomerRentals'; +import Card from 'react-bootstrap/Card'; +import Table from 'react-bootstrap/Table'; +import Button from 'react-bootstrap/Button' +// import './Customer.css'; + +const Customer = (props) => { + const onSelectCustomer = () => { + props.onSelectCustomerCallback(props.customer.id) + } + + const onDeselectCustomer = () => { + props.onDeselectCustomerCallback(props.customer.id) + } + + const onViewRentals = () => { + props.onCustomerRentalsCallback(props.customer.id) + } + + + const selectButton = (props.chosenCustomer === props.customer) ? + : + + + const rentalButton = (props.viewCustomerRental) ? + : + + + return ( +
+

#{props.customer.id}. {props.customer.name}

+

{selectButton}{rentalButton}

+ {props.viewCustomerRental && + + + + {props.customer.name}'s Rentals + + + + + + + + + + + +
TitleCheck-outCheck-in
+
+
+
} +
+ ) +} + +Customer.propTypes = { + customer: PropTypes.object.isRequired, + viewCustomerRental: PropTypes.bool, + customerRentals: PropTypes.array, + onSelectCustomerCallback: PropTypes.func.isRequired, + onCustomerRentalsCallback: PropTypes.func.isRequired, +}; + +export default Customer; \ No newline at end of file diff --git a/src/components/CustomerRentals.js b/src/components/CustomerRentals.js new file mode 100644 index 000000000..b4e0a58fc --- /dev/null +++ b/src/components/CustomerRentals.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +// import './CustomerRentals.css'; + +const CustomerRentals = (props) => { + const rentalHTML = props.rentals.map((rental, i) => { + return + {rental["movie"]} + {rental["checkout_date"]} + {rental["due_date"]} + + }) + + return rentalHTML +} + +CustomerRentals.propTypes = { + rentals: PropTypes.array, +}; + +export default CustomerRentals; \ No newline at end of file diff --git a/src/components/Customers.css b/src/components/Customers.css new file mode 100644 index 000000000..de4df6af7 --- /dev/null +++ b/src/components/Customers.css @@ -0,0 +1,35 @@ +#communityHeader { + border-top: 10px solid black; + padding-top: 20px; + text-align: center; + font-size: 3em; + color: black; + background: #DCDCDC; +} + +.customers_container { + background: #DCDCDC; + padding: 50px; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + padding-top: 20px; +} + +.user { + font-size: 25px; + text-align: center; +} + + +.avatar { + background-color: white; + border-radius: 25px; + border: 5px outset #fff3c9; + margin: 15px; +} + +.buttons { + padding-left: 10px; +} \ No newline at end of file diff --git a/src/components/Customers.js b/src/components/Customers.js new file mode 100644 index 000000000..b12bb76d5 --- /dev/null +++ b/src/components/Customers.js @@ -0,0 +1,53 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Customer from './Customer'; +import './Customers.css'; + +const Customers = (props) => { + + const findRentalsCallback = (customerID) => { + const rentals = [] + for (let key in props.allRentals) { + if (props.allRentals[key]["customer"] === customerID) { + rentals.push( + { + "movie": props.allRentals[key]["movie"], + "checkout_date": props.allRentals[key]["checkout_date"], + "due_date": props.allRentals[key]["due_date"] + } + ) + } + } + return rentals + } + + + const customerCollection = props.customers.map((customer, i) => { + return
+ }); + + return ( + +
- Our Community -
+
+ {customerCollection} +
+ + ) +} + +Customers.propTypes = { + customers: PropTypes.array.isRequired, + expandedCustomer: PropTypes.object, + onSelectCustomerCallback: PropTypes.func.isRequired, + onCustomerRentalsCallback: PropTypes.func.isRequired, +}; + +export default Customers; \ No newline at end of file diff --git a/src/components/Library.css b/src/components/Library.css new file mode 100644 index 000000000..d35d8a906 --- /dev/null +++ b/src/components/Library.css @@ -0,0 +1,19 @@ +.library_container { + border-top: 10px solid black; + background: #DCDCDC; + text-align: left; + padding: 30px; +} + +#collectionHeader { + text-align: center; + font-size: 3em; + color: #000; +} + +.movie_container { + background: white; + margin: 5px; + margin-left: 40px; + margin-right: 40px; +} diff --git a/src/components/Library.js b/src/components/Library.js new file mode 100644 index 000000000..1c3547a6e --- /dev/null +++ b/src/components/Library.js @@ -0,0 +1,40 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Movie from './Movie'; +import Table from 'react-bootstrap/Table'; +import './Library.css'; + +const Library = (props) => { + const movieCollection = props.library.map((movie, i) => { + return + }); + + return ( +
+

- Our Collection -

+ + + + {movieCollection} + +
+
+ ) +} + +Library.propTypes = { + library: PropTypes.array.isRequired, + expandedMovies: PropTypes.object, + onSelectMovieCallback: PropTypes.func.isRequired, + onClickMovieDetailsCallback: PropTypes.func.isRequired, +}; + +export default Library; \ No newline at end of file diff --git a/src/components/Movie.css b/src/components/Movie.css new file mode 100644 index 000000000..4e25f7513 --- /dev/null +++ b/src/components/Movie.css @@ -0,0 +1,31 @@ +.movie_container { + height: 300px; + display: flex; + flex-direction: row; +} + +.title { + font-weight: bold; + font-size: 1.5rem; +} + +.movie_description { + margin-left: 1rem; + font-family: 'Courier New', Courier, monospace; +} + +.bold_words { + font-weight: bold; +} + + +.description { + display: flex; + flex-direction: column; + /* flex-wrap: wrap; */ +} + +.btn-sm, .btn-group-sm > .btn { + margin-right: 1rem; +} + diff --git a/src/components/Movie.js b/src/components/Movie.js new file mode 100644 index 000000000..a246fa786 --- /dev/null +++ b/src/components/Movie.js @@ -0,0 +1,80 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import MovieDetails from './MovieDetails'; +import './Movie.css'; +import Button from 'react-bootstrap/Button' + + +const Movie = (props) => { + const onSelectMovie = () => { + props.onSelectMovieCallback(props.movie.id) + } + + const onViewMovieDetails = () => { + props.onClickMovieDetailsCallback(props.movie.id) + } + + const onCloseMovieDetails = () => { + props.onCloseMovieDetailsCallback(props.movie.id) + } + + const onDeselectMovie = () => { + props.onDeselectMovieCallback(props.movie.id) + } + + let movieDescription =
+

{props.movie.title}

+

Release Date: {props.movie.release_date}

+

Overview: {props.movie.overview.length > 128 ? `${props.movie.overview.substring(0, 150)}...` : props.movie.overview}

+
+ + let movieDetails = null; + let showButton = + let selectButton = + + if (props.viewMovieDetails) { + if (props.viewMovieDetails.title === props.movie.title) { + movieDescription = null; + movieDetails = + + showButton = + + } + } + + if (props.selectedMovie === props.movie) { + selectButton = + } + + if (props.deselectedMovie === props.movie) { + selectButton = + } + + return ( + + + + {props.movie.title}/ +
+ {movieDescription} + {movieDetails} +
+
+ {showButton} + {selectButton} +
+
+
+ + + ) +} + +Movie.propTypes = { + movie: PropTypes.object.isRequired, + viewMovieDetails: PropTypes.bool, + onClickMovieDetailsCallback: PropTypes.func.isRequired, + onSelectMovieCallback: PropTypes.func.isRequired, +}; + +export default Movie; \ No newline at end of file diff --git a/src/components/MovieCard.css b/src/components/MovieCard.css new file mode 100644 index 000000000..0b6f26e1e --- /dev/null +++ b/src/components/MovieCard.css @@ -0,0 +1,5 @@ +@import url('https://fonts.googleapis.com/css?family=DM+Serif+Display&display=swap'); + +#button_font { + font-family: 'DM Serif Display', serif; +} \ No newline at end of file diff --git a/src/components/MovieCard.js b/src/components/MovieCard.js new file mode 100644 index 000000000..08596cc9c --- /dev/null +++ b/src/components/MovieCard.js @@ -0,0 +1,26 @@ +import React from 'react'; +import Button from 'react-bootstrap/Button' +import './MovieCard.css'; + +const MovieCard = (props) => { + const {image_url, title, overview, release_date,addMovieCallback } = props; + const addMovie = () => { + addMovieCallback(props); + } + return ( + + + + {title}/ +
+

{title}

+

Release Date: {release_date}

+

Overview: {overview}

+ +
+ + + ) +} + +export default MovieCard; \ No newline at end of file diff --git a/src/components/MovieDetails.css b/src/components/MovieDetails.css new file mode 100644 index 000000000..7595d469b --- /dev/null +++ b/src/components/MovieDetails.css @@ -0,0 +1,7 @@ +.pic { + width: 200px; +} + +.inline { + display: inline; +} \ No newline at end of file diff --git a/src/components/MovieDetails.js b/src/components/MovieDetails.js new file mode 100644 index 000000000..eaef686a0 --- /dev/null +++ b/src/components/MovieDetails.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './MovieDetails.css'; + +const MovieDetails = (props) => { + const movieDetails = () => { + return ( +
+

{props.title}

+

Release Date: {props.release_date}

+

Overview: {props.overview}

+

Inventory: {props.inventory}

+

Available Inventory: {props.available_inventory}

+
+ ) + }; + + return movieDetails(); +} + +MovieDetails.propTypes = { + external_id: PropTypes.number.isRequired, + id: PropTypes.number.isRequired, + image_url: PropTypes.string.isRequired, + overview: PropTypes.string.isRequired, + release_date: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, +}; + +export default MovieDetails; \ No newline at end of file diff --git a/src/components/OverdueMovies.css b/src/components/OverdueMovies.css new file mode 100644 index 000000000..d407bb6c2 --- /dev/null +++ b/src/components/OverdueMovies.css @@ -0,0 +1,13 @@ +.overdue_container { + border-top: 10px solid black; + background: #DCDCDC; + padding: 80px; + min-height: 800px; + display: flex-wrap; + text-align: center; + list-style: none; +} + +.overdueMovie { + list-style: none; +} \ No newline at end of file diff --git a/src/components/OverdueMovies.js b/src/components/OverdueMovies.js new file mode 100644 index 000000000..97bd7e910 --- /dev/null +++ b/src/components/OverdueMovies.js @@ -0,0 +1,34 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import axios from 'axios'; +import Button from 'react-bootstrap/Button'; +import './OverdueMovies.css'; + +const OverdueMovies = (props) => { + const overdueMoviesCall = () => { + axios.get('http://localhost:3001/rentals/overdue') + .then((response) => { + const overdueMovieCollection = response.data.map((overdueMovie) => { + console.log(overdueMovie) + return
  • {overdueMovie.title} due {overdueMovie.due_date}
  • + }) + props.setOverdueMoviesCallback(overdueMovieCollection) + }) + .catch((error) => { + props.setErrorOverdueCallback(error) + }); + } + return ( +
    + + {props.overdueMovies &&
      {props.overdueMovies.length > 0 ? props.overdueMovies : "No Movies are Overdue!" }
    } +
    + ) +} + +OverdueMovies.propTypes = { + setOverdueMoviesCallback: PropTypes.func.isRequired, + overdueMovies: PropTypes.array, +}; + +export default OverdueMovies; \ No newline at end of file diff --git a/src/components/Search.css b/src/components/Search.css new file mode 100644 index 000000000..faf93744d --- /dev/null +++ b/src/components/Search.css @@ -0,0 +1,10 @@ +.search_title { + text-align: center; + margin-top: 5rem; +} + +.search_container { + min-height: 800px; + border-top: 10px solid black; + background: #DCDCDC; +} \ No newline at end of file diff --git a/src/components/Search.js b/src/components/Search.js new file mode 100644 index 000000000..bd400bda2 --- /dev/null +++ b/src/components/Search.js @@ -0,0 +1,119 @@ +import React, {Component} from 'react'; +import SearchBar from './SearchBar'; +import MovieCard from './MovieCard'; +import axios from 'axios'; +import Table from 'react-bootstrap/Table'; +import './Search.css'; +class Search extends Component { + constructor(props) { + super(props); + this.state = { + searchResults: [], + searched: false, + error: null, + success: null + }; + } + + getSearchResults = (queryString) => { + axios.get('http://localhost:3001/movies?query=' + queryString) + .then((response) => { + this.setState({ + searchResults: response.data + }) + }) + .catch((error) => { + this.setState({ + error: error.message + }); + }); + } + + searchCallback = (queryString) => { + this.setState({ + queryString, + searched: true + }); + + this.getSearchResults(queryString); + + }; + + addMovieCallback = (movie) => { + + if (this.props.moviesInLibrary.find(currentMovie => currentMovie.external_id === movie.external_id)) { + this.setState({ + error: "Movie already exists!" + }) + } else { + const movieToLibrary = { + external_id: movie.external_id, + image_url: movie.image_url.substring(31, movie.image_url.length), + // image_url: movie.image_url, + title: movie.title, + overview: movie.overview, + release_date: movie.release_date + } + axios.post('http://localhost:3001/movies', movieToLibrary) + .then((response)=> { + if (response.status === 200) { + this.setState({ + success: "Movie has been added to the rental library!" + }); + this.props.addMovieCallback(movie); + } + }) + .catch((error) => { + this.setState({ + error: error.message + }) + }); + } + } + + render() { + + const errorSection = (this.state.error) ? + (
    Error: {this.state.error}
    ) : null; + + const successSection = (this.state.success) ? + (
    {this.state.success}
    ) : null; + + let movieCards; + + if (this.state.searchResults !== null) { + movieCards = this.state.searchResults.map((movie,i) => { + return [] + }); + + } else if (this.state.searched) { + movieCards = (No matched Results!); + } else { + movieCards = null; + } + + return ( +
    +

    Search Titles

    + + {errorSection} + {successSection} + + + {movieCards} + +
    + +
    + ) + } +}; + +export default Search; \ No newline at end of file diff --git a/src/components/SearchBar.css b/src/components/SearchBar.css new file mode 100644 index 000000000..68e7ca272 --- /dev/null +++ b/src/components/SearchBar.css @@ -0,0 +1,7 @@ +.search_bar { + margin: 20px auto; + width: 100%; + max-width: 300px; + height: 40px; + text-align: center; +} \ No newline at end of file diff --git a/src/components/SearchBar.js b/src/components/SearchBar.js new file mode 100644 index 000000000..ffc37939e --- /dev/null +++ b/src/components/SearchBar.js @@ -0,0 +1,38 @@ +import React, {Component} from 'react'; +import Form from 'react-bootstrap/Form'; +import FormControl from 'react-bootstrap/FormControl'; +import './SearchBar.css'; + + +class SearchBar extends Component { + constructor(props) { + super(props); + this.state = { + queryString: "" + }; + } + + queryChanged = (event) => { + const queryString = event.target.value; + this.setState({ + queryString + }) + + this.props.searchCallback(event.target.value); + } + render() { + return ( +
    +
    + + +
    + ) + } +}; + +export default SearchBar; \ No newline at end of file diff --git a/src/index.css b/src/index.css index b4cc7250b..df5e0649a 100644 --- a/src/index.css +++ b/src/index.css @@ -1,5 +1,7 @@ -body { +@import url('https://fonts.googleapis.com/css?family=DM+Serif+Display&display=swap'); + +* { margin: 0; padding: 0; - font-family: sans-serif; + font-family: 'DM Serif Display', serif; } diff --git a/src/index.js b/src/index.js index fae3e3500..cb6856b7c 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; +import 'bootstrap/dist/css/bootstrap.css'; ReactDOM.render(, document.getElementById('root')); registerServiceWorker();