Fixed some todos and added the start of the dashboard
This commit is contained in:
@@ -20,7 +20,7 @@ The build is minified and the filenames include the hashes. Your app is ready to
|
||||
|
||||
### Requirement list
|
||||
- [X] Create React web app
|
||||
- [ ] 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.
|
||||
- [ ] The dashboard should render three values from the API.
|
||||
- [ ] The dashboard should render a Paginated List.
|
||||
@@ -28,8 +28,9 @@ The build is minified and the filenames include the hashes. Your app is ready to
|
||||
### Software used
|
||||
\# | Software | Reason |
|
||||
--- | --- | --- |
|
||||
\1. | React | Requirement. |
|
||||
\2. | React Router | To route between different components, a react router is used. |
|
||||
\3. | TypeScript | To make use of the strong types, I made use of TypeScript |
|
||||
\4. | Bootstrap | To structure the front-end, bootstrap is used. |
|
||||
\5. | Axios | To communicate with external API's, I added Axios. |
|
||||
1 | React | Requirement. |
|
||||
2 | React Router | To route between different components, a react router is used. |
|
||||
3 | TypeScript | To make use of the strong types, I made use of TypeScript |
|
||||
4 | Bootstrap | To structure the front-end, bootstrap is used. |
|
||||
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. |
|
||||
|
||||
+5
-2
@@ -3,9 +3,11 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.8.4",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||
"@testing-library/dom": "^6.12.2",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.4.0",
|
||||
"@testing-library/user-event": "^7.1.2",
|
||||
@@ -18,16 +20,17 @@
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-fontawesome": "^1.6.4",
|
||||
"@types/react-router-dom": "^5.1.3",
|
||||
"@types/react-table": "^7.0.7",
|
||||
"axios": "^0.19.2",
|
||||
"bootstrap": "^4.4.1",
|
||||
"jquery": "^3.4.1",
|
||||
"popper.js": "^1.16.1",
|
||||
"react": "^16.12.0",
|
||||
"react-bootstrap": "^1.0.0-beta.16",
|
||||
"react-bootstrap-table-next": "^3.3.5",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-fontawesome": "^1.7.1",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.3.1",
|
||||
"react-scripts": "^3.4.0",
|
||||
"typescript": "~3.7.2"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -6,7 +6,6 @@ import Login from '../LoginComponent/Login';
|
||||
import Dashboard from '../DashboardComponent/Dashboard';
|
||||
|
||||
export default class App extends React.Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Switch>
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
import React from 'react';
|
||||
import DashboardView from '../../Views/DashboardView'
|
||||
|
||||
export default class Dashboard extends React.Component<{
|
||||
history: any
|
||||
}, {
|
||||
dto: any
|
||||
}> {
|
||||
state!: {
|
||||
dto: {
|
||||
API_Link: string | null;
|
||||
API_Token: string | null;
|
||||
};
|
||||
};
|
||||
props: any;
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
if (props.location.state.dto !== undefined) {
|
||||
// If the state exists being routed from /, fill in Dashboard State.
|
||||
this.state = { dto: props.location.state.dto };
|
||||
} else if (localStorage.getItem("APILink") !== null &&
|
||||
localStorage.getItem("AccessToken") !== null) {
|
||||
// Check if localStorage has valid items, if this is the case, we can use those.
|
||||
// Resolve issue with cold navigation to /dashboard.
|
||||
this.state = {
|
||||
dto: {
|
||||
API_Link: localStorage.getItem("APILink"),
|
||||
API_Token: localStorage.getItem("AccessToken")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Route back to / if neither is the case.
|
||||
this.props.history.push('/');
|
||||
}
|
||||
}
|
||||
|
||||
export default class Dashboard extends React.Component {
|
||||
render () {
|
||||
return (<h1> This is the dashboard, fuck yeah </h1>)
|
||||
return (<DashboardView />)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,14 @@ export default class Login extends React.Component<{
|
||||
}, {
|
||||
dto: any
|
||||
}> {
|
||||
|
||||
props: any;
|
||||
state: any;
|
||||
// eslint-disable-next-line
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.persistApiLink = this.persistApiLink.bind(this);
|
||||
this.persistAccessToken = this.persistAccessToken.bind(this);
|
||||
this.verifyLogin = this.verifyLogin.bind(this);
|
||||
this.getApiLinkFromDTO = this.getApiLinkFromDTO.bind(this);
|
||||
this.getApiTokenFromDTO = this.getApiTokenFromDTO.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -30,17 +29,12 @@ export default class Login extends React.Component<{
|
||||
console.log("API Token: " + this.state.dto.getApiToken());
|
||||
localStorage.setItem("lastLoggedIn", new Date().toUTCString());
|
||||
// eslint-disable-next-line
|
||||
this.props.history.push('/dashboard');
|
||||
this.props.history.push({
|
||||
pathname: '/dashboard',
|
||||
state: { dto: this.state.dto }
|
||||
});
|
||||
};
|
||||
|
||||
getApiLinkFromDTO(): string {
|
||||
return this.state.dto.getApiLink();
|
||||
}
|
||||
|
||||
getApiTokenFromDTO(): string {
|
||||
return this.state.dto.getApiToken();
|
||||
}
|
||||
|
||||
persistApiLink(e: any): void {
|
||||
this.state.dto.setApiLink(e.target.value);
|
||||
}
|
||||
@@ -54,8 +48,6 @@ export default class Login extends React.Component<{
|
||||
persistApiLink={this.persistApiLink}
|
||||
persistAccessToken={this.persistAccessToken}
|
||||
verifyLogin={this.verifyLogin}
|
||||
getApiLinkFromDTO={this.getApiLinkFromDTO}
|
||||
getApiTokenFromDTO={this.getApiTokenFromDTO}
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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";
|
||||
|
||||
export default class DashboardView extends React.Component {
|
||||
render () {
|
||||
return (
|
||||
<div className="DashboardComponent">
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
<br />
|
||||
<h3>DASHBOARD</h3>
|
||||
<hr />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Prepend>
|
||||
<InputGroup.Text id="basic-addon1">First Date</InputGroup.Text>
|
||||
</InputGroup.Prepend>
|
||||
<FormControl
|
||||
placeholder="2017-05-01"
|
||||
aria-label="2017-05-01"
|
||||
aria-describedby="basic-addon1"
|
||||
defaultValue={localStorage.getItem("FirstDate") || ""}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Col>
|
||||
|
||||
<Col>
|
||||
<InputGroup className="mb-3">
|
||||
<InputGroup.Prepend>
|
||||
<InputGroup.Text id="basic-addon1">Second Date</InputGroup.Text>
|
||||
</InputGroup.Prepend>
|
||||
<FormControl
|
||||
placeholder="2017-06-15"
|
||||
aria-label="2017-06-15"
|
||||
aria-describedby="basic-addon1"
|
||||
defaultValue={localStorage.getItem("SecondDate") || ""}
|
||||
/>
|
||||
</InputGroup>
|
||||
</Col>
|
||||
|
||||
<Col>
|
||||
<Button variant="primary">
|
||||
<FontAwesomeIcon icon={faSync} />
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h5">Total Conversation Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text></Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h5">Total User Message Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text></Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col>
|
||||
<Card>
|
||||
<Card.Header as="h5">Total Visitor Message Count</Card.Header>
|
||||
<Card.Body>
|
||||
<Card.Text></Card.Text>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Table
|
||||
columns={[{
|
||||
dataField: 'id',
|
||||
text: 'Product ID'
|
||||
}, {
|
||||
dataField: 'name',
|
||||
text: 'Product Name'
|
||||
}, {
|
||||
dataField: 'price',
|
||||
text: 'Product Price'
|
||||
}]}
|
||||
data={[]} />
|
||||
</Row>
|
||||
<Row>
|
||||
<Col>
|
||||
<br />
|
||||
<hr /><h6>Made with ❤ by Jeroen Vijgen </h6>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,9 @@ import { Card, Button, FormControl } from 'react-bootstrap';
|
||||
export default class LoginView extends React.Component<{
|
||||
persistApiLink: any,
|
||||
persistAccessToken: any,
|
||||
verifyLogin: any,
|
||||
getApiLinkFromDTO: any,
|
||||
getApiTokenFromDTO: any
|
||||
verifyLogin: any
|
||||
}> {
|
||||
props: any;
|
||||
render () {
|
||||
return (
|
||||
<div className="LoginComponent">
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import BootstrapTable from 'react-bootstrap-table-next';
|
||||
|
||||
export default class Table extends React.Component<{
|
||||
columns: any,
|
||||
data: any
|
||||
}> {
|
||||
render () {
|
||||
return (<div >
|
||||
<BootstrapTable
|
||||
bootstrap4
|
||||
keyField='id'
|
||||
columns={ this.props.columns }
|
||||
data={ this.props.data } />
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
@@ -17,3 +17,8 @@ body {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.DashboardComponent {
|
||||
background-color: white;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -1 +1,2 @@
|
||||
// / <reference types="react-scripts" />
|
||||
declare module 'react-bootstrap-table-next';
|
||||
|
||||
Reference in New Issue
Block a user