Bind dashboard front-end to component

This commit is contained in:
2020-02-22 22:38:28 +01:00
parent 6ca0a99e78
commit ada58864e0
14 changed files with 136 additions and 38 deletions
+6 -3
View File
@@ -18,14 +18,16 @@ It correctly bundles React in production mode and optimizes the build for the be
The build is minified and the filenames include the hashes. Your app is ready to be deployed! The build is minified and the filenames include the hashes. Your app is ready to be deployed!
### Requirement list ## Requirement list
- [X] Create React web app - [X] Create React web app
- [X] It should have fields for giving start date, end date and access token as arguments to the app. - [X] It should have fields for giving start date, end date and access token as arguments to the app.
- [ ] App should make HTTP GET request to the API to fetch chat counts between those two given dates. - [ ] App should make HTTP GET request to the API to fetch chat counts between those two given dates.
- [ ] The dashboard should render three values from the API. - [ ] The dashboard should render three values from the API.
- [ ] The dashboard should render a Paginated List. - [X] The dashboard should render a Paginated List.
## Software used
### Software used
\# | Software | Reason | \# | Software | Reason |
--- | --- | --- | --- | --- | --- |
1 | React | Requirement. | 1 | React | Requirement. |
@@ -34,3 +36,4 @@ The build is minified and the filenames include the hashes. Your app is ready to
4 | Bootstrap | To structure the front-end, bootstrap is used. | 4 | Bootstrap | To structure the front-end, bootstrap is used. |
5 | Axios | To communicate with external API's, I added Axios. | 5 | Axios | To communicate with external API's, I added Axios. |
6 | FontAwesome | To communicate actions to the user, I have added some relatable icons for actions. | 6 | FontAwesome | To communicate actions to the user, I have added some relatable icons for actions. |
7 | react-bootstrap-table2-* | To get a paginated table, React Bootstrap Table is used. |
+1
View File
@@ -28,6 +28,7 @@
"react": "^16.12.0", "react": "^16.12.0",
"react-bootstrap": "^1.0.0-beta.16", "react-bootstrap": "^1.0.0-beta.16",
"react-bootstrap-table-next": "^3.3.5", "react-bootstrap-table-next": "^3.3.5",
"react-bootstrap-table2-paginator": "^2.1.0",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",
"react-scripts": "^3.4.0", "react-scripts": "^3.4.0",
+29 -16
View File
@@ -1,40 +1,53 @@
import React from 'react'; import React from 'react';
import DashboardView from '../../Views/DashboardView' import DashboardView from '../../Views/DashboardView'
import API_DTO from '../../DTOs/api.dto';
import ReportingRepository from '../../Repositories/ReportingRepository';
export default class Dashboard extends React.Component<{ export default class Dashboard extends React.Component<{
history: any history: any
}, { }, {
dto: any dto: API_DTO,
ReportingRepository: ReportingRepository
}> { }> {
state!: {
dto: {
API_Link: string | null;
API_Token: string | null;
};
};
props: any;
constructor(props: any) { constructor(props: any) {
super(props); super(props);
if (props.location.state.dto !== undefined) { if (props.location.state.dto !== undefined) {
// If the state exists being routed from /, fill in Dashboard State. // If the state exists being routed from /, fill in Dashboard State.
this.state = { dto: props.location.state.dto }; this.setState({ dto: props.location.state.dto });
} else if (localStorage.getItem("APILink") !== null && } else if (localStorage.getItem("APILink") !== null &&
localStorage.getItem("AccessToken") !== null) { localStorage.getItem("AccessToken") !== null) {
// Check if localStorage has valid items, if this is the case, we can use those. // Check if localStorage has valid items, if this is the case, we can use those.
// Resolve issue with cold navigation to /dashboard. // Resolve issue with cold navigation to /dashboard.
this.state = { const DTO = new API_DTO();
dto: { DTO.setApiLink(localStorage.getItem("APILink"));
API_Link: localStorage.getItem("APILink"), DTO.setApiToken(localStorage.getItem("AccessToken"));
API_Token: localStorage.getItem("AccessToken") this.setState({ dto: DTO });
}
}
} else { } else {
// Route back to / if neither is the case. // Route back to / if neither is the case.
this.props.history.push('/'); this.props.history.push('/');
} }
this.checkFirstDate = this.checkFirstDate.bind(this);
this.checkSecondDate = this.checkSecondDate.bind(this);
this.getItemsFromApi = this.getItemsFromApi.bind(this);
}
checkFirstDate(_e: any) {
this.state.dto.setFirstDate(_e.target.value);
}
checkSecondDate(_e: any) {
this.state.dto.setSecondDate(_e.target.value);
}
getItemsFromApi() {
// TODO: Connect to ReportingRepository.
} }
render () { render () {
return (<DashboardView />) return (<DashboardView
checkFirstDate={this.checkFirstDate}
checkSecondDate={this.checkSecondDate}
getItemsFromApi={this.getItemsFromApi}
/>)
} }
} }
-2
View File
@@ -25,8 +25,6 @@ export default class Login extends React.Component<{
} }
verifyLogin() { verifyLogin() {
console.log("API Link: " + this.state.dto.getApiLink());
console.log("API Token: " + this.state.dto.getApiToken());
localStorage.setItem("lastLoggedIn", new Date().toUTCString()); localStorage.setItem("lastLoggedIn", new Date().toUTCString());
// eslint-disable-next-line // eslint-disable-next-line
this.props.history.push({ this.props.history.push({
+1
View File
@@ -0,0 +1 @@
export default interface IDTO { };
+35 -3
View File
@@ -1,10 +1,17 @@
export default class API_DTO { import IDTO from './IDTO';
export default class API_DTO implements IDTO {
API_Link: string; API_Link: string;
API_Token: string; API_Token: string;
First_Date: string;
Second_Date: string;
checkDate = /((\d{4})-(\d{2})-(\d{2}))/g
constructor() { constructor() {
this.API_Link = ""; this.API_Link = "";
this.API_Token = ""; this.API_Token = "";
this.First_Date = "";
this.Second_Date = "";
} }
setApiLink(_api_link: string | null): void { setApiLink(_api_link: string | null): void {
@@ -19,11 +26,36 @@ export default class API_DTO {
localStorage.setItem("AccessToken", this.API_Token); localStorage.setItem("AccessToken", this.API_Token);
} }
getApiLink() { setFirstDate(_first_date: string | null): void {
if (!this.checkDate.test(_first_date || "")
|| _first_date === null) _first_date = "2017-05-01";
// TODO: Check validity of range of first date.
this.First_Date = _first_date;
localStorage.setItem("FirstDate", this.First_Date);
}
setSecondDate(_second_date: string | null): void {
if (!this.checkDate.test(_second_date || "")
|| _second_date === null) _second_date = "2017-06-15";
// TODO: Check validity of range of second date.
this.Second_Date = _second_date;
localStorage.setItem("SecondDate", this.Second_Date);
}
getApiLink(): string {
return this.API_Link; return this.API_Link;
} }
getApiToken() { getApiToken(): string {
return this.API_Token; return this.API_Token;
} }
getFirstDate(): string {
return this.First_Date;
}
getSecondDate(): string {
return this.Second_Date;
}
} }
+6
View File
@@ -0,0 +1,6 @@
export default interface IRepository {
Create(t: any): any;
Read(t: any): any;
Update(t: any): any;
Delete(t: any): any;
}
+16
View File
@@ -0,0 +1,16 @@
import IRepository from './IRepository';
export default class ReportingRepository implements IRepository {
Create(_t: any) {
throw new Error("Method not implemented.");
}
Read(_t: any) {
throw new Error("Method not implemented.");
}
Update(_t: any) {
throw new Error("Method not implemented.");
}
Delete(_t: any) {
throw new Error("Method not implemented.");
}
}
+16 -10
View File
@@ -4,7 +4,11 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSync } from '@fortawesome/free-solid-svg-icons'; import { faSync } from '@fortawesome/free-solid-svg-icons';
import Table from "./TableView"; import Table from "./TableView";
export default class DashboardView extends React.Component { export default class DashboardView extends React.Component<{
checkFirstDate: any,
checkSecondDate: any,
getItemsFromApi: any
}> {
render () { render () {
return ( return (
<div className="DashboardComponent"> <div className="DashboardComponent">
@@ -26,7 +30,8 @@ export default class DashboardView extends React.Component {
placeholder="2017-05-01" placeholder="2017-05-01"
aria-label="2017-05-01" aria-label="2017-05-01"
aria-describedby="basic-addon1" aria-describedby="basic-addon1"
defaultValue={localStorage.getItem("FirstDate") || ""} defaultValue={localStorage.getItem("FirstDate") || "2017-05-01"}
onChange={(e: any) => this.props.checkFirstDate(e)}
/> />
</InputGroup> </InputGroup>
</Col> </Col>
@@ -40,13 +45,14 @@ export default class DashboardView extends React.Component {
placeholder="2017-06-15" placeholder="2017-06-15"
aria-label="2017-06-15" aria-label="2017-06-15"
aria-describedby="basic-addon1" aria-describedby="basic-addon1"
defaultValue={localStorage.getItem("SecondDate") || ""} defaultValue={localStorage.getItem("SecondDate") || "2017-06-15"}
onChange={(e: any) => this.props.checkSecondDate(e)}
/> />
</InputGroup> </InputGroup>
</Col> </Col>
<Col> <Col>
<Button variant="primary"> <Button variant="primary" onClick={this.props.getItemsFromApi}>
<FontAwesomeIcon icon={faSync} /> <FontAwesomeIcon icon={faSync} />
</Button> </Button>
</Col> </Col>
@@ -80,14 +86,14 @@ export default class DashboardView extends React.Component {
<Row> <Row>
<Table <Table
columns={[{ columns={[{
dataField: 'id', dataField: 'conversation_count',
text: 'Product ID' text: 'Conversation Count'
}, { }, {
dataField: 'name', dataField: 'missed_chat_count',
text: 'Product Name' text: 'Missed Chat Count'
}, { }, {
dataField: 'price', dataField: 'visitors_with_conversation_count',
text: 'Product Price' text: 'Visitors With Conversation Count'
}]} }]}
data={[]} /> data={[]} />
</Row> </Row>
+1 -1
View File
@@ -18,7 +18,7 @@ export default class LoginView extends React.Component<{
<FormControl aria-label="Default" <FormControl aria-label="Default"
aria-describedby="inputGroup-sizing-default" aria-describedby="inputGroup-sizing-default"
type="text" type="text"
placeholder="API Link" placeholder="API Link (http://api.concept.com/)"
defaultValue={localStorage.getItem("APILink") || ""} defaultValue={localStorage.getItem("APILink") || ""}
onChange={(e: any) => this.props.persistApiLink(e)} onChange={(e: any) => this.props.persistApiLink(e)}
/> />
+12 -2
View File
@@ -1,17 +1,27 @@
import React from 'react'; import React from 'react';
import BootstrapTable from 'react-bootstrap-table-next'; import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory from 'react-bootstrap-table2-paginator';
import 'react-bootstrap-table2-paginator/dist/react-bootstrap-table2-paginator.min.css';
export default class Table extends React.Component<{ export default class Table extends React.Component<{
columns: any, columns: any,
data: any data: any
}> { }> {
render () { render () {
return (<div > return (<div className="fullSize">
<br />
<BootstrapTable <BootstrapTable
bootstrap4 bootstrap4
keyField='id' keyField='id'
columns={ this.props.columns } columns={ this.props.columns }
data={ this.props.data } /> data={ this.props.data }
pagination={ paginationFactory({
paginationSize: 4,
pageStartIndex: 0,
showTotal: true,
sizePerPageList: [5]
}) }
/>
</div>) </div>)
} }
} }
+5
View File
@@ -22,3 +22,8 @@ body {
background-color: white; background-color: white;
border-radius: 7px; border-radius: 7px;
} }
.fullSize {
width: 96%;
margin: 0 auto;
}
+2
View File
@@ -1,2 +1,4 @@
// / <reference types="react-scripts" /> // / <reference types="react-scripts" />
// Set module declaration for modules that do not have @types/* available on NPM repository
declare module 'react-bootstrap-table-next'; declare module 'react-bootstrap-table-next';
declare module 'react-bootstrap-table2-paginator';
+5
View File
@@ -8505,6 +8505,11 @@ react-bootstrap-table-next@^3.3.5:
react-transition-group "2.5.3" react-transition-group "2.5.3"
underscore "1.9.1" underscore "1.9.1"
react-bootstrap-table2-paginator@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/react-bootstrap-table2-paginator/-/react-bootstrap-table2-paginator-2.1.0.tgz#fa3b8de029fe27d511b493685a0f0c4376f9b753"
integrity sha512-VtXIu8ogLZnQfvlSDTCVctr1oTuW2I7/Y7p0ikMuQXDlXwo8wP2MQ6ThQp2s7AvK7uZHsCkEgRPdjXGCe+veMg==
react-bootstrap@^1.0.0-beta.16: react-bootstrap@^1.0.0-beta.16:
version "1.0.0-beta.16" version "1.0.0-beta.16"
resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.0.0-beta.16.tgz#42da0314aee6754494e478687b8e6953de1aaf62" resolved "https://registry.yarnpkg.com/react-bootstrap/-/react-bootstrap-1.0.0-beta.16.tgz#42da0314aee6754494e478687b8e6953de1aaf62"