Finished demo app
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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>): 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 (<DashboardView
|
||||
checkFirstDate={this.checkFirstDate}
|
||||
@@ -111,6 +131,7 @@ export default class Dashboard extends React.Component<{
|
||||
getResponseDTO={this.getResponseDTO}
|
||||
getGraphEnabled={this.getGraphEnabled}
|
||||
setGraph={this.setGraph}
|
||||
logOut={this.logOut}
|
||||
/>)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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
@@ -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<{
|
||||
<Row>
|
||||
<Col>
|
||||
<br />
|
||||
<h3>DASHBOARD</h3>
|
||||
<h3 className="center">DASHBOARD</h3>
|
||||
<UserView
|
||||
logOut={this.props.logOut}
|
||||
/>
|
||||
<hr />
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -63,28 +69,25 @@ export default class DashboardView extends React.Component<{
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h6">Total Conversation Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text>{ this.props.getResponseDTO().total_conversation_count }</Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
<CardView
|
||||
title="Total Conversation Count"
|
||||
content={ this.props.getResponseDTO().total_conversation_count }
|
||||
cssClassName="bg-card-1"
|
||||
/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h6">Total User Message Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text>{ this.props.getResponseDTO().total_user_message_count }</Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
<CardView
|
||||
title="Total User Message Count"
|
||||
content={ this.props.getResponseDTO().total_user_message_count }
|
||||
cssClassName="bg-card-2"
|
||||
/>
|
||||
</Col>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h6">Total Visitor Message Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text>{ this.props.getResponseDTO().total_visitor_message_count }</Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
<CardView
|
||||
title="Total Visitor Message Count"
|
||||
content={ this.props.getResponseDTO().total_visitor_message_count }
|
||||
cssClassName="bg-card-3"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
@@ -123,7 +126,7 @@ export default class DashboardView extends React.Component<{
|
||||
<Col>
|
||||
<br />
|
||||
<hr />
|
||||
<h6>Made with ❤ by Jeroen Vijgen </h6>
|
||||
<h6 className="center">Made with ❤ by Jeroen Vijgen </h6>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
|
||||
@@ -18,20 +18,6 @@ export default class GraphView extends React.Component<{
|
||||
}
|
||||
|
||||
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:
|
||||
// { id: "missed_chat_count", data: [{x: int (DATE), y: int (Count)}] }
|
||||
// { id: "conversation_count", data: [{x: int (DATE), y: int (Count)}] }
|
||||
|
||||
@@ -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)}
|
||||
/>
|
||||
</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>
|
||||
{ localStorage.getItem("lastLoggedIn") !== null &&
|
||||
<Card.Footer className="text-muted">Your last login was { localStorage.getItem("lastLoggedIn") }</Card.Footer>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
@@ -17,7 +17,7 @@ body {
|
||||
|
||||
.LoginComponent,
|
||||
.DashboardComponent {
|
||||
background-color: white;
|
||||
background-color: whitesmoke;
|
||||
border-style: solid;
|
||||
border-color: #FD4114;
|
||||
border-radius: 7px;
|
||||
@@ -30,3 +30,24 @@ 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;
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user