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
|
### Requirement list
|
||||||
- [X] Create React web app
|
- [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.
|
- [ ] 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.
|
- [ ] 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 used
|
||||||
\# | Software | Reason |
|
\# | Software | Reason |
|
||||||
--- | --- | --- |
|
--- | --- | --- |
|
||||||
\1. | React | Requirement. |
|
1 | React | Requirement. |
|
||||||
\2. | React Router | To route between different components, a react router is used. |
|
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 |
|
3 | TypeScript | To make use of the strong types, I made use of TypeScript |
|
||||||
\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. |
|
||||||
|
|||||||
+5
-2
@@ -3,9 +3,11 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@babel/core": "^7.8.4",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
"@fortawesome/fontawesome-svg-core": "^1.2.27",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
"@fortawesome/free-solid-svg-icons": "^5.12.1",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.8",
|
"@fortawesome/react-fontawesome": "^0.1.8",
|
||||||
|
"@testing-library/dom": "^6.12.2",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
"@testing-library/react": "^9.4.0",
|
"@testing-library/react": "^9.4.0",
|
||||||
"@testing-library/user-event": "^7.1.2",
|
"@testing-library/user-event": "^7.1.2",
|
||||||
@@ -18,16 +20,17 @@
|
|||||||
"@types/react-dom": "^16.9.5",
|
"@types/react-dom": "^16.9.5",
|
||||||
"@types/react-fontawesome": "^1.6.4",
|
"@types/react-fontawesome": "^1.6.4",
|
||||||
"@types/react-router-dom": "^5.1.3",
|
"@types/react-router-dom": "^5.1.3",
|
||||||
|
"@types/react-table": "^7.0.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",
|
||||||
"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",
|
||||||
|
"react-bootstrap-table-next": "^3.3.5",
|
||||||
"react-dom": "^16.12.0",
|
"react-dom": "^16.12.0",
|
||||||
"react-fontawesome": "^1.7.1",
|
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"react-scripts": "3.3.1",
|
"react-scripts": "^3.4.0",
|
||||||
"typescript": "~3.7.2"
|
"typescript": "~3.7.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import Login from '../LoginComponent/Login';
|
|||||||
import Dashboard from '../DashboardComponent/Dashboard';
|
import Dashboard from '../DashboardComponent/Dashboard';
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|||||||
@@ -1,7 +1,40 @@
|
|||||||
import React from 'react';
|
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 () {
|
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
|
dto: any
|
||||||
}> {
|
}> {
|
||||||
|
props: any;
|
||||||
|
state: any;
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props);
|
super(props);
|
||||||
this.persistApiLink = this.persistApiLink.bind(this);
|
this.persistApiLink = this.persistApiLink.bind(this);
|
||||||
this.persistAccessToken = this.persistAccessToken.bind(this);
|
this.persistAccessToken = this.persistAccessToken.bind(this);
|
||||||
this.verifyLogin = this.verifyLogin.bind(this);
|
this.verifyLogin = this.verifyLogin.bind(this);
|
||||||
this.getApiLinkFromDTO = this.getApiLinkFromDTO.bind(this);
|
|
||||||
this.getApiTokenFromDTO = this.getApiTokenFromDTO.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -30,17 +29,12 @@ export default class Login extends React.Component<{
|
|||||||
console.log("API Token: " + this.state.dto.getApiToken());
|
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('/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 {
|
persistApiLink(e: any): void {
|
||||||
this.state.dto.setApiLink(e.target.value);
|
this.state.dto.setApiLink(e.target.value);
|
||||||
}
|
}
|
||||||
@@ -54,8 +48,6 @@ export default class Login extends React.Component<{
|
|||||||
persistApiLink={this.persistApiLink}
|
persistApiLink={this.persistApiLink}
|
||||||
persistAccessToken={this.persistAccessToken}
|
persistAccessToken={this.persistAccessToken}
|
||||||
verifyLogin={this.verifyLogin}
|
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<{
|
export default class LoginView extends React.Component<{
|
||||||
persistApiLink: any,
|
persistApiLink: any,
|
||||||
persistAccessToken: any,
|
persistAccessToken: any,
|
||||||
verifyLogin: any,
|
verifyLogin: any
|
||||||
getApiLinkFromDTO: any,
|
|
||||||
getApiTokenFromDTO: any
|
|
||||||
}> {
|
}> {
|
||||||
|
props: any;
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div className="LoginComponent">
|
<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;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.DashboardComponent {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+1
@@ -1 +1,2 @@
|
|||||||
// / <reference types="react-scripts" />
|
// / <reference types="react-scripts" />
|
||||||
|
declare module 'react-bootstrap-table-next';
|
||||||
|
|||||||
+36
-36
@@ -1,36 +1,36 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"dom.iterable",
|
"dom.iterable",
|
||||||
"esnext"
|
"esnext"
|
||||||
],
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"isolatedModules": true
|
"isolatedModules": true
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"build"
|
"build"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user