Finished demo app

This commit is contained in:
2020-02-28 16:21:56 +01:00
parent 71c77975f8
commit bead38bb21
12 changed files with 141 additions and 40 deletions
+2
View File
@@ -16,6 +16,7 @@
"@types/istanbul-lib-coverage": "^2.0.1", "@types/istanbul-lib-coverage": "^2.0.1",
"@types/jest": "^24.9.1", "@types/jest": "^24.9.1",
"@types/mocha": "^7.0.1", "@types/mocha": "^7.0.1",
"@types/moment": "^2.13.0",
"@types/node": "^12.12.26", "@types/node": "^12.12.26",
"@types/prop-types": "^15.7.3", "@types/prop-types": "^15.7.3",
"@types/react": "^16.9.19", "@types/react": "^16.9.19",
@@ -26,6 +27,7 @@
"axios": "^0.19.2", "axios": "^0.19.2",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"jquery": "^3.4.1", "jquery": "^3.4.1",
"moment": "^2.24.0",
"popper.js": "^1.16.1", "popper.js": "^1.16.1",
"react": "^16.12.0", "react": "^16.12.0",
"react-bootstrap": "^1.0.0-beta.16", "react-bootstrap": "^1.0.0-beta.16",
@@ -57,6 +57,7 @@ export default class Dashboard extends React.Component<{
this.getResponseDTO = this.getResponseDTO.bind(this); this.getResponseDTO = this.getResponseDTO.bind(this);
this.getGraphEnabled = this.getGraphEnabled.bind(this); this.getGraphEnabled = this.getGraphEnabled.bind(this);
this.setGraph = this.setGraph.bind(this); this.setGraph = this.setGraph.bind(this);
this.logOut = this.logOut.bind(this);
this.getItemsFromApi(); this.getItemsFromApi();
} }
@@ -69,7 +70,6 @@ export default class Dashboard extends React.Component<{
} }
getItemsFromApi() { getItemsFromApi() {
// TODO: Connect to ReportingRepository.
this.state.ReportingRepository.Read(this.state.dto).then((res) => { this.state.ReportingRepository.Read(this.state.dto).then((res) => {
const response = new RESPONSE_DTO(); const response = new RESPONSE_DTO();
response.room_id = res.room_id; 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_user_message_count = res.total_user_message_count;
response.total_visitor_message_count = res.total_visitor_message_count; response.total_visitor_message_count = res.total_visitor_message_count;
response.total_missed_chat_count = res.total_missed_chat_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}); this.setState({response: response});
}); });
} }
sortData(arr: Array<Object>): 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() { getResponseDTO() {
return this.state.response; return this.state.response;
} }
@@ -103,6 +119,10 @@ export default class Dashboard extends React.Component<{
this.setState({ showGraph: !this.state.showGraph }); this.setState({ showGraph: !this.state.showGraph });
} }
logOut() {
this.props.history.push('/');
}
render () { render () {
return (<DashboardView return (<DashboardView
checkFirstDate={this.checkFirstDate} checkFirstDate={this.checkFirstDate}
@@ -111,6 +131,7 @@ export default class Dashboard extends React.Component<{
getResponseDTO={this.getResponseDTO} getResponseDTO={this.getResponseDTO}
getGraphEnabled={this.getGraphEnabled} getGraphEnabled={this.getGraphEnabled}
setGraph={this.setGraph} setGraph={this.setGraph}
logOut={this.logOut}
/>) />)
} }
} }
+2 -1
View File
@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import LoginView from '../../Views/LoginView'; import LoginView from '../../Views/LoginView';
import API_DTO from '../../DTOs/api.dto'; import API_DTO from '../../DTOs/api.dto';
import moment from 'moment';
export default class Login extends React.Component<{ export default class Login extends React.Component<{
history: any history: any
@@ -25,7 +26,7 @@ export default class Login extends React.Component<{
} }
verifyLogin() { verifyLogin() {
localStorage.setItem("lastLoggedIn", new Date().toUTCString()); localStorage.setItem("lastLoggedIn", moment().format('LLLL'));
// eslint-disable-next-line // eslint-disable-next-line
this.props.history.push({ this.props.history.push({
pathname: '/dashboard', pathname: '/dashboard',
+1
View File
@@ -10,6 +10,7 @@ export default class ReportingRepository {
headers: { headers: {
'Authorization': 'Token ' + t.getApiToken(), 'Authorization': 'Token ' + t.getApiToken(),
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Origin': '*',
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept",
'Accept': 'application/json' 'Accept': 'application/json'
} }
}); });
+23
View File
@@ -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 (
<div>
<Card>
<Card.Header className={this.props.cssClassName} as="h6">{this.props.title}</Card.Header>
<Card.Body>
<Card.Text>
{ this.props.content }
</Card.Text>
</Card.Body>
</Card>
</div>
);
}
}
+24 -21
View File
@@ -1,9 +1,11 @@
import React from 'react'; 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 { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSync, faChartLine } from '@fortawesome/free-solid-svg-icons'; import { faSync, faChartLine } from '@fortawesome/free-solid-svg-icons';
import TableView from "./TableView"; import TableView from "./TableView";
import GraphView from "./GraphView"; import GraphView from "./GraphView";
import CardView from "./CardView";
import UserView from "./UserView";
export default class DashboardView extends React.Component<{ export default class DashboardView extends React.Component<{
checkFirstDate: any, checkFirstDate: any,
@@ -12,6 +14,7 @@ export default class DashboardView extends React.Component<{
getResponseDTO: any, getResponseDTO: any,
getGraphEnabled: any, getGraphEnabled: any,
setGraph: any setGraph: any
logOut: any
}> { }> {
render () { render () {
return ( return (
@@ -20,7 +23,10 @@ export default class DashboardView extends React.Component<{
<Row> <Row>
<Col> <Col>
<br /> <br />
<h3>DASHBOARD</h3> <h3 className="center">DASHBOARD</h3>
<UserView
logOut={this.props.logOut}
/>
<hr /> <hr />
</Col> </Col>
</Row> </Row>
@@ -63,28 +69,25 @@ export default class DashboardView extends React.Component<{
</Row> </Row>
<Row> <Row>
<Col> <Col>
<Card> <CardView
<Card.Header as="h6">Total Conversation Count</Card.Header> title="Total Conversation Count"
<Card.Body> content={ this.props.getResponseDTO().total_conversation_count }
<Card.Text>{ this.props.getResponseDTO().total_conversation_count }</Card.Text> cssClassName="bg-card-1"
</Card.Body> />
</Card>
</Col> </Col>
<Col> <Col>
<Card> <CardView
<Card.Header as="h6">Total User Message Count</Card.Header> title="Total User Message Count"
<Card.Body> content={ this.props.getResponseDTO().total_user_message_count }
<Card.Text>{ this.props.getResponseDTO().total_user_message_count }</Card.Text> cssClassName="bg-card-2"
</Card.Body> />
</Card>
</Col> </Col>
<Col> <Col>
<Card> <CardView
<Card.Header as="h6">Total Visitor Message Count</Card.Header> title="Total Visitor Message Count"
<Card.Body> content={ this.props.getResponseDTO().total_visitor_message_count }
<Card.Text>{ this.props.getResponseDTO().total_visitor_message_count }</Card.Text> cssClassName="bg-card-3"
</Card.Body> />
</Card>
</Col> </Col>
</Row> </Row>
<Row> <Row>
@@ -123,7 +126,7 @@ export default class DashboardView extends React.Component<{
<Col> <Col>
<br /> <br />
<hr /> <hr />
<h6>Made with by Jeroen Vijgen </h6> <h6 className="center">Made with by Jeroen Vijgen </h6>
</Col> </Col>
</Row> </Row>
</Container> </Container>
-14
View File
@@ -18,20 +18,6 @@ export default class GraphView extends React.Component<{
} }
parseData(): Array<IData>{ parseData(): Array<IData>{
// 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: // Object needing to be returned:
// { id: "missed_chat_count", data: [{x: int (DATE), y: int (Count)}] } // { id: "missed_chat_count", data: [{x: int (DATE), y: int (Count)}] }
// { id: "conversation_count", data: [{x: int (DATE), y: int (Count)}] } // { id: "conversation_count", data: [{x: int (DATE), y: int (Count)}] }
+3 -1
View File
@@ -1,5 +1,7 @@
import React from 'react'; import React from 'react';
import { Card, Button, FormControl } from 'react-bootstrap'; 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<{ export default class LoginView extends React.Component<{
persistApiLink: any, persistApiLink: any,
@@ -31,7 +33,7 @@ export default class LoginView extends React.Component<{
onChange={(e: any) => this.props.persistAccessToken(e)} onChange={(e: any) => this.props.persistAccessToken(e)}
/> />
</Card.Text> </Card.Text>
<Button variant="primary" onClick={this.props.verifyLogin}>Login </Button> <Button variant="primary" onClick={this.props.verifyLogin}>Login <FontAwesomeIcon icon={faSignInAlt} /></Button>
</Card.Body> </Card.Body>
{ localStorage.getItem("lastLoggedIn") !== null && { localStorage.getItem("lastLoggedIn") !== null &&
<Card.Footer className="text-muted">Your last login was { localStorage.getItem("lastLoggedIn") }</Card.Footer> <Card.Footer className="text-muted">Your last login was { localStorage.getItem("lastLoggedIn") }</Card.Footer>
+3
View File
@@ -16,6 +16,9 @@ export default class TableView extends React.Component<{
keyField='date' keyField='date'
columns={ this.props.columns } columns={ this.props.columns }
data={ this.props.data } data={ this.props.data }
striped
hover
condensed
pagination={ paginationFactory({ pagination={ paginationFactory({
pageStartIndex: 0, pageStartIndex: 0,
showTotal: true, showTotal: true,
+16
View File
@@ -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 (
<span className="center-span">
<b> Hi user123 </b> | Your last login was on: { localStorage.getItem("lastLoggedIn") || "" } | <Button variant="danger" onClick={this.props.logOut}> Log out <FontAwesomeIcon icon={faSignOutAlt} /> </Button>
</span>
);
}
}
+22 -1
View File
@@ -17,7 +17,7 @@ body {
.LoginComponent, .LoginComponent,
.DashboardComponent { .DashboardComponent {
background-color: white; background-color: whitesmoke;
border-style: solid; border-style: solid;
border-color: #FD4114; border-color: #FD4114;
border-radius: 7px; border-radius: 7px;
@@ -30,3 +30,24 @@ body {
.GraphView { .GraphView {
height: 300px; 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;
}
+22
View File
@@ -1384,6 +1384,11 @@
dependencies: dependencies:
"@babel/types" "^7.3.0" "@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": "@types/eslint-visitor-keys@^1.0.0":
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" 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" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-7.0.1.tgz#5d7ec2a789a1f77c59b7ad071b9d50bf1abbfc9e"
integrity sha512-L/Nw/2e5KUaprNJoRA33oly+M8X8n0K+FwLTbYqwTcR14wdPWeRkigBLfSFpN/Asf9ENZTMZwLxjtjeYucAA4Q== 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@*": "@types/node@*":
version "13.7.4" version "13.7.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.4.tgz#76c3cb3a12909510f52e5dc04a6298cdf9504ffd" 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-mimetype "^2.2.0"
whatwg-url "^7.0.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: debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
version "2.6.9" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 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: dependencies:
minimist "0.0.8" 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: move-concurrently@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"