diff --git a/package.json b/package.json index ca1efd1..527c686 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@types/istanbul-lib-coverage": "^2.0.1", "@types/jest": "^24.9.1", "@types/mocha": "^7.0.1", + "@types/moment": "^2.13.0", "@types/node": "^12.12.26", "@types/prop-types": "^15.7.3", "@types/react": "^16.9.19", @@ -26,6 +27,7 @@ "axios": "^0.19.2", "bootstrap": "^4.4.1", "jquery": "^3.4.1", + "moment": "^2.24.0", "popper.js": "^1.16.1", "react": "^16.12.0", "react-bootstrap": "^1.0.0-beta.16", diff --git a/src/Components/DashboardComponent/Dashboard.tsx b/src/Components/DashboardComponent/Dashboard.tsx index e30324a..6c2f1bf 100644 --- a/src/Components/DashboardComponent/Dashboard.tsx +++ b/src/Components/DashboardComponent/Dashboard.tsx @@ -57,6 +57,7 @@ export default class Dashboard extends React.Component<{ this.getResponseDTO = this.getResponseDTO.bind(this); this.getGraphEnabled = this.getGraphEnabled.bind(this); this.setGraph = this.setGraph.bind(this); + this.logOut = this.logOut.bind(this); this.getItemsFromApi(); } @@ -69,7 +70,6 @@ export default class Dashboard extends React.Component<{ } getItemsFromApi() { - // TODO: Connect to ReportingRepository. this.state.ReportingRepository.Read(this.state.dto).then((res) => { const response = new RESPONSE_DTO(); response.room_id = res.room_id; @@ -86,11 +86,27 @@ export default class Dashboard extends React.Component<{ response.total_user_message_count = res.total_user_message_count; response.total_visitor_message_count = res.total_visitor_message_count; response.total_missed_chat_count = res.total_missed_chat_count; - response.by_date = res.by_date; + response.by_date = this.sortData(res.by_date); this.setState({response: response}); }); } + sortData(arr: Array): Object[] { + // Sort data to coherently display in the Graph & Table. + // eslint-disable-next-line + arr.sort((a: any, b: any) => { + let dateA = new Date(a.date); + let dateB = new Date(b.date); + // Date A is greater than Date B. + if (dateA > dateB) return 1; + // Date A is lesser than Date B. + if (dateA < dateB) return -1; + // Date is eql, for stable sorting. + return 0; + }); + return arr; + } + getResponseDTO() { return this.state.response; } @@ -103,6 +119,10 @@ export default class Dashboard extends React.Component<{ this.setState({ showGraph: !this.state.showGraph }); } + logOut() { + this.props.history.push('/'); + } + render () { return () } } diff --git a/src/Components/LoginComponent/Login.tsx b/src/Components/LoginComponent/Login.tsx index 9f0a690..244ee88 100644 --- a/src/Components/LoginComponent/Login.tsx +++ b/src/Components/LoginComponent/Login.tsx @@ -1,6 +1,7 @@ import React from 'react'; import LoginView from '../../Views/LoginView'; import API_DTO from '../../DTOs/api.dto'; +import moment from 'moment'; export default class Login extends React.Component<{ history: any @@ -25,7 +26,7 @@ export default class Login extends React.Component<{ } verifyLogin() { - localStorage.setItem("lastLoggedIn", new Date().toUTCString()); + localStorage.setItem("lastLoggedIn", moment().format('LLLL')); // eslint-disable-next-line this.props.history.push({ pathname: '/dashboard', diff --git a/src/Repositories/ReportingRepository.ts b/src/Repositories/ReportingRepository.ts index 4df6937..c3e4843 100644 --- a/src/Repositories/ReportingRepository.ts +++ b/src/Repositories/ReportingRepository.ts @@ -10,6 +10,7 @@ export default class ReportingRepository { headers: { 'Authorization': 'Token ' + t.getApiToken(), 'Access-Control-Allow-Origin': '*', + "Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept", 'Accept': 'application/json' } }); diff --git a/src/Views/CardView.tsx b/src/Views/CardView.tsx new file mode 100644 index 0000000..3028fdf --- /dev/null +++ b/src/Views/CardView.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Card } from 'react-bootstrap'; + +export default class CardView extends React.Component<{ + title: any, + content: any, + cssClassName?: any +}> { + render() { + return ( +
+ + {this.props.title} + + + { this.props.content } + + + +
+ ); + } +} diff --git a/src/Views/DashboardView.tsx b/src/Views/DashboardView.tsx index 4029014..57885ee 100644 --- a/src/Views/DashboardView.tsx +++ b/src/Views/DashboardView.tsx @@ -1,9 +1,11 @@ import React from 'react'; -import { Container, Row, Col, FormControl, Button, InputGroup, Card } from 'react-bootstrap'; +import { Container, Row, Col, FormControl, Button, InputGroup } from 'react-bootstrap'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSync, faChartLine } from '@fortawesome/free-solid-svg-icons'; import TableView from "./TableView"; import GraphView from "./GraphView"; +import CardView from "./CardView"; +import UserView from "./UserView"; export default class DashboardView extends React.Component<{ checkFirstDate: any, @@ -12,6 +14,7 @@ export default class DashboardView extends React.Component<{ getResponseDTO: any, getGraphEnabled: any, setGraph: any + logOut: any }> { render () { return ( @@ -20,7 +23,10 @@ export default class DashboardView extends React.Component<{
-

DASHBOARD

+

DASHBOARD

+
@@ -63,28 +69,25 @@ export default class DashboardView extends React.Component<{ - - Total Conversation Count - - { this.props.getResponseDTO().total_conversation_count } - - + - - Total User Message Count - - { this.props.getResponseDTO().total_user_message_count } - - + - - Total Visitor Message Count - - { this.props.getResponseDTO().total_visitor_message_count } - - + @@ -123,7 +126,7 @@ export default class DashboardView extends React.Component<{

-
Made with ❤ by Jeroen Vijgen
+
Made with ❤ by Jeroen Vijgen
diff --git a/src/Views/GraphView.tsx b/src/Views/GraphView.tsx index 48fc66d..2035d5a 100644 --- a/src/Views/GraphView.tsx +++ b/src/Views/GraphView.tsx @@ -18,20 +18,6 @@ export default class GraphView extends React.Component<{ } parseData(): Array{ - // Sort data to coherently display in the Graph. - // eslint-disable-next-line - this.props.data.sort((a: any, b: any) => { - let dateA = new Date(a.date); - let dateB = new Date(b.date); - let same = dateA.getTime() === dateB.getTime(); - // Date is eql, ignore sorting to stablize sorting. - if (same) return 0; - // Date A is greater than Date B. - if (dateA > dateB) return 1; - // Date A is lesser than Date B. - if (dateA < dateB) return -1; - }); - // 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)}] } diff --git a/src/Views/LoginView.tsx b/src/Views/LoginView.tsx index f70e715..1ddd25b 100644 --- a/src/Views/LoginView.tsx +++ b/src/Views/LoginView.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { Card, Button, FormControl } from 'react-bootstrap'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSignInAlt } from '@fortawesome/free-solid-svg-icons'; export default class LoginView extends React.Component<{ persistApiLink: any, @@ -31,7 +33,7 @@ export default class LoginView extends React.Component<{ onChange={(e: any) => this.props.persistAccessToken(e)} /> - + { localStorage.getItem("lastLoggedIn") !== null && Your last login was { localStorage.getItem("lastLoggedIn") } diff --git a/src/Views/TableView.tsx b/src/Views/TableView.tsx index 4771792..80a2126 100644 --- a/src/Views/TableView.tsx +++ b/src/Views/TableView.tsx @@ -16,6 +16,9 @@ export default class TableView extends React.Component<{ keyField='date' columns={ this.props.columns } data={ this.props.data } + striped + hover + condensed pagination={ paginationFactory({ pageStartIndex: 0, showTotal: true, diff --git a/src/Views/UserView.tsx b/src/Views/UserView.tsx new file mode 100644 index 0000000..8576b50 --- /dev/null +++ b/src/Views/UserView.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Button } from 'react-bootstrap'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; + +export default class UserView extends React.Component<{ + logOut: any +}> { + render () { + return ( + + Hi user123 | Your last login was on: { localStorage.getItem("lastLoggedIn") || "" } | + + ); + } +} \ No newline at end of file diff --git a/src/index.css b/src/index.css index 77cdf25..67aae22 100644 --- a/src/index.css +++ b/src/index.css @@ -17,7 +17,7 @@ body { .LoginComponent, .DashboardComponent { - background-color: white; + background-color: whitesmoke; border-style: solid; border-color: #FD4114; border-radius: 7px; @@ -29,4 +29,25 @@ body { .GraphView { height: 300px; +} + +.bg-card-1 { + background-color: #ffc1074d; +} + +.bg-card-2 { + background-color: #dc35455c; +} + +.bg-card-3 { + background-color: #28a74559; +} + +.center { + text-align: center; +} + +.center-span { + display: table; + margin: 0 auto; } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 5582519..961c4c3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1384,6 +1384,11 @@ dependencies: "@babel/types" "^7.3.0" +"@types/datejs@^0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/datejs/-/datejs-0.0.30.tgz#590c625c8a962b253f4b8059f96891c957d30bde" + integrity sha512-UM5Nf0spXBPoT0NXJvkLyTAyRKTVNF5n8eSQoo1XA4qNAFa7lIC48O0JK4nkzIrWi9f2TmJUvxP5G1yrjGRVHQ== + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" @@ -1450,6 +1455,13 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.1.tgz#5d7ec2a789a1f77c59b7ad071b9d50bf1abbfc9e" integrity sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q== +"@types/moment@^2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@types/moment/-/moment-2.13.0.tgz#604ebd189bc3bc34a1548689404e61a2a4aac896" + integrity sha1-YE69GJvDvDShVIaJQE5hoqSqyJY= + dependencies: + moment "*" + "@types/node@*": version "13.7.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.4.tgz#76c3cb3a12909510f52e5dc04a6298cdf9504ffd" @@ -3506,6 +3518,11 @@ data-urls@^1.0.0, data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +datejs@^1.0.0-rc3: + version "1.0.0-rc3" + resolved "https://registry.yarnpkg.com/datejs/-/datejs-1.0.0-rc3.tgz#bffa1efedefeb41fdd8a242af55afa01fb58de57" + integrity sha1-v/oe/t7+tB/diiQq9Vr6AftY3lc= + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6958,6 +6975,11 @@ mkdirp@0.5.1, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +moment@*, moment@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"