diff --git a/README.md b/README.md index 9347782..549bcb6 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ - [X] Static type checking using Typescript. - [X] Documentation on how to run and build/install if needed. - [X] The application running and accessible somewhere (for example in AWS) -- [ ] Virtualisation of existing data. +- [X] Docker image for running the dashboard in an existing Docker stack. +- [X] Virtualisation of existing data. ## Software used diff --git a/package.json b/package.json index f362835..ca1efd1 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "@fortawesome/fontawesome-svg-core": "^1.2.27", "@fortawesome/free-solid-svg-icons": "^5.12.1", "@fortawesome/react-fontawesome": "^0.1.8", + "@nivo/axes": "^0.61.0", + "@nivo/bump": "^0.61.1", "@testing-library/dom": "^6.12.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.4.0", diff --git a/public/index.html b/public/index.html index c4db272..3ea59b9 100644 --- a/public/index.html +++ b/public/index.html @@ -9,6 +9,7 @@ + Demo App - Jeroen Vijgen diff --git a/src/Components/DashboardComponent/Dashboard.tsx b/src/Components/DashboardComponent/Dashboard.tsx index 85d5cd8..e30324a 100644 --- a/src/Components/DashboardComponent/Dashboard.tsx +++ b/src/Components/DashboardComponent/Dashboard.tsx @@ -10,7 +10,8 @@ export default class Dashboard extends React.Component<{ }, { dto: API_DTO, response: RESPONSE_DTO, - ReportingRepository: ReportingRepository + ReportingRepository: ReportingRepository, + showGraph: boolean }> { constructor(props: any) { super(props); @@ -25,7 +26,8 @@ export default class Dashboard extends React.Component<{ this.state = { dto: DTO, response: new RESPONSE_DTO(), - ReportingRepository: new ReportingRepository(DTO) + ReportingRepository: new ReportingRepository(DTO), + showGraph: false } } } catch (err) { @@ -41,7 +43,8 @@ export default class Dashboard extends React.Component<{ this.state = { dto: DTO, response: new RESPONSE_DTO(), - ReportingRepository: new ReportingRepository(DTO) + ReportingRepository: new ReportingRepository(DTO), + showGraph: false } } else { // Route back to / if neither is the case. @@ -52,6 +55,8 @@ export default class Dashboard extends React.Component<{ this.checkSecondDate = this.checkSecondDate.bind(this); this.getItemsFromApi = this.getItemsFromApi.bind(this); this.getResponseDTO = this.getResponseDTO.bind(this); + this.getGraphEnabled = this.getGraphEnabled.bind(this); + this.setGraph = this.setGraph.bind(this); this.getItemsFromApi(); } @@ -90,12 +95,22 @@ export default class Dashboard extends React.Component<{ return this.state.response; } + getGraphEnabled() { + return this.state.showGraph; + } + + setGraph() { + this.setState({ showGraph: !this.state.showGraph }); + } + render () { return () } } diff --git a/src/Views/DashboardView.tsx b/src/Views/DashboardView.tsx index ff4e9d0..4029014 100644 --- a/src/Views/DashboardView.tsx +++ b/src/Views/DashboardView.tsx @@ -1,14 +1,17 @@ import React from 'react'; import { Container, Row, Col, FormControl, Button, InputGroup, Card } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { faSync } from '@fortawesome/free-solid-svg-icons'; -import Table from "./TableView"; +import { faSync, faChartLine } from '@fortawesome/free-solid-svg-icons'; +import TableView from "./TableView"; +import GraphView from "./GraphView"; export default class DashboardView extends React.Component<{ checkFirstDate: any, checkSecondDate: any, getItemsFromApi: any, - getResponseDTO: any + getResponseDTO: any, + getGraphEnabled: any, + setGraph: any }> { render () { return ( @@ -85,7 +88,19 @@ export default class DashboardView extends React.Component<{ - +
+ + { this.props.getGraphEnabled() && + + } + + + + + + + diff --git a/src/Views/GraphView.tsx b/src/Views/GraphView.tsx new file mode 100644 index 0000000..3011f36 --- /dev/null +++ b/src/Views/GraphView.tsx @@ -0,0 +1,63 @@ +import React from 'react'; +import { ResponsiveAreaBump } from '@nivo/bump'; + +interface IData { + id: string; + data: Array<{ + x: any, + y: any + }> +}; + +export default class GraphView extends React.Component<{ + data: any +}> { + parseData(): Array{ + // Object needing to be returned: + // { id: "missed_chat_count", data: [{x: int (DATE), y: int (Count)}] } + // { id: "conversation_count", data: [{x: int (DATE), y: int (Count)}] } + // { id: "visitors_with_conversation_count", data: [{x: int (DATE), y: int (Count)}] } + const array: Array = new Array(); + array.push({ id: "missed_chat_count", data: [] }); + array.push({ id: "conversation_count", data: [] }); + array.push({ id: "visitors_with_conversation_count", data: [] }); + this.props.data.forEach((_item: any) => { + array[0].data.push({ x: _item.date, y: _item.missed_chat_count }); + array[1].data.push({ x: _item.date, y: _item.conversation_count }); + array[2].data.push({ x: _item.date, y: _item.visitors_with_conversation_count }); + }); + return array; + } + + + render () { + return ( +
+ +
+ ) + } +} diff --git a/src/Views/TableView.tsx b/src/Views/TableView.tsx index 299fe24..4771792 100644 --- a/src/Views/TableView.tsx +++ b/src/Views/TableView.tsx @@ -4,13 +4,13 @@ import paginationFactory from 'react-bootstrap-table2-paginator'; import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css'; import 'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min.css'; -export default class Table extends React.Component<{ +export default class TableView extends React.Component<{ columns: any, data: any }> { render () { - return (
-
+ return (
+
=0.10.0" + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -6399,6 +6591,16 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -6856,6 +7058,14 @@ no-case@^3.0.3: lower-case "^2.0.1" tslib "^1.10.0" +node-fetch@^1.0.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" @@ -7466,6 +7676,11 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -8307,6 +8522,13 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + promise@^8.0.3: version "8.0.3" resolved "https://registry.yarnpkg.com/promise/-/promise-8.0.3.tgz#f592e099c6cddc000d538ee7283bb190452b0bf6" @@ -8330,7 +8552,7 @@ prop-types-extra@^1.1.0: react-is "^16.3.2" warning "^4.0.0" -prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -8447,7 +8669,7 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== -raf@^3.4.1: +raf@^3.1.0, raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -8581,11 +8803,30 @@ react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== -react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-measure@^2.2.4: + version "2.3.0" + resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.3.0.tgz#75835d39abec9ae13517f35a819c160997a7a44e" + integrity sha512-dwAvmiOeblj5Dvpnk8Jm7Q8B4THF/f1l1HtKVi0XDecsG6LXwGvzV5R1H32kq3TW6RW64OAf5aoQxpIgLa4z8A== + dependencies: + "@babel/runtime" "^7.2.0" + get-node-dimensions "^1.2.1" + prop-types "^15.6.2" + resize-observer-polyfill "^1.5.0" + +react-motion@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.5.2.tgz#0dd3a69e411316567927917c6626551ba0607316" + integrity sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ== + dependencies: + performance-now "^0.2.0" + prop-types "^15.5.8" + raf "^3.1.0" + react-overlays@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-2.1.1.tgz#ffe2090c4a10da6b8947a1c7b1a67d0457648a0d" @@ -8796,6 +9037,18 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" +recompose@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" + integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w== + dependencies: + "@babel/runtime" "^7.0.0" + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" + symbol-observable "^1.0.4" + recursive-readdir@2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f" @@ -8988,6 +9241,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -9318,7 +9576,7 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -setimmediate@^1.0.4: +setimmediate@^1.0.4, setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= @@ -9920,6 +10178,11 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -10192,6 +10455,11 @@ typescript@~3.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== +ua-parser-js@^0.7.18: + version "0.7.21" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.21.tgz#853cf9ce93f642f67174273cc34565ae6f308777" + integrity sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ== + uncontrollable@^7.0.0: version "7.1.1" resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-7.1.1.tgz#f67fed3ef93637126571809746323a9db815d556" @@ -10610,7 +10878,7 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" -whatwg-fetch@^3.0.0: +whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==