diff --git a/README.md b/README.md
index 8b688a5..284d4d2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[](https://app.netlify.com/sites/upbeat-agnesi-aad3fb/deploys)
+[](https://upbeat-agnesi-aad3fb.netlify.com/)
## Available Scripts
@@ -9,15 +9,26 @@ In the project directory, you can run:
Runs the app in the development mode.
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
-The page will reload if you make edits.
-You will also see any lint errors in the console.
+The page will reload if you make edits, you will also see any lint errors in the console.
### `yarn build`
Builds the app for production to the `build` folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
-The build is minified and the filenames include the hashes.
-Your app is ready to be deployed!
-
-See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
+The build is minified and the filenames include the hashes. Your app is ready to be deployed!
+
+### 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.
+- [ ] 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.
+
+### 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.
diff --git a/package.json b/package.json
index e54e32f..5f4d821 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^1.2.27",
+ "@fortawesome/free-solid-svg-icons": "^5.12.1",
+ "@fortawesome/react-fontawesome": "^0.1.8",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^7.1.2",
@@ -13,13 +16,16 @@
"@types/prop-types": "^15.7.3",
"@types/react": "^16.9.19",
"@types/react-dom": "^16.9.5",
+ "@types/react-fontawesome": "^1.6.4",
"@types/react-router-dom": "^5.1.3",
+ "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-dom": "^16.12.0",
+ "react-fontawesome": "^1.7.1",
"react-router-dom": "^5.1.2",
"react-scripts": "3.3.1",
"typescript": "~3.7.2"
diff --git a/public/index.html b/public/index.html
index 22ef106..c4db272 100644
--- a/public/index.html
+++ b/public/index.html
@@ -8,6 +8,7 @@
+
Demo App - Jeroen Vijgen
diff --git a/src/Components/AppComponent/App.tsx b/src/Components/AppComponent/App.tsx
index b143361..3ede347 100644
--- a/src/Components/AppComponent/App.tsx
+++ b/src/Components/AppComponent/App.tsx
@@ -6,18 +6,14 @@ import Login from '../LoginComponent/Login';
import Dashboard from '../DashboardComponent/Dashboard';
export default class App extends React.Component {
- componentDidMount() {
- if((localStorage.getItem("APILink") !== undefined || localStorage.getItem("APILink") !== '') &&
- (localStorage.getItem("AccessToken") !== undefined || localStorage.getItem("AccessToken") !== '')) {
- return
- };
- }
render() {
return (
-
-
+
+
);
diff --git a/src/Components/LoginComponent/Login.tsx b/src/Components/LoginComponent/Login.tsx
index e04a10e..8a63bda 100644
--- a/src/Components/LoginComponent/Login.tsx
+++ b/src/Components/LoginComponent/Login.tsx
@@ -1,44 +1,61 @@
import React from 'react';
-import { Card, Button, InputGroup, FormControl } from 'react-bootstrap';
+import LoginView from '../../Views/LoginView';
+import API_DTO from '../../DTOs/api.dto';
+
+export default class Login extends React.Component<{
+ history: any
+}, {
+ dto: any
+}> {
-export default class Login extends React.Component {
// 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);
}
- render () {
- return (
-
-
-
- Please login to see the dashboard.
-
- Please fill in the following items:
-
-
- API url
-
-
-
-
-
- API token
-
-
-
-
- Login
-
- Your last login was X-X-X @ XX:XX
-
-
- );
+ componentDidMount() {
+ const DTO = new API_DTO();
+ DTO.setApiLink(localStorage.getItem("APILink"));
+ DTO.setApiToken(localStorage.getItem("AccessToken"));
+ this.setState({ dto: DTO });
+ }
+
+ verifyLogin() {
+ console.log("API Link: " + this.state.dto.getApiLink());
+ console.log("API Token: " + this.state.dto.getApiToken());
+ localStorage.setItem("lastLoggedIn", new Date().toUTCString());
+ // eslint-disable-next-line
+ this.props.history.push('/dashboard');
+ };
+
+ 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);
+ }
+
+ persistAccessToken(e: any): void {
+ this.state.dto.setApiToken(e.target.value);
+ }
+
+ render() {
+ return ( );
}
}
diff --git a/src/DTOs/api.dto.ts b/src/DTOs/api.dto.ts
new file mode 100644
index 0000000..df15a8e
--- /dev/null
+++ b/src/DTOs/api.dto.ts
@@ -0,0 +1,29 @@
+export default class API_DTO {
+ API_Link: string;
+ API_Token: string;
+
+ constructor() {
+ this.API_Link = "";
+ this.API_Token = "";
+ }
+
+ setApiLink(_api_link: string | null): void {
+ if (_api_link === null) _api_link = "";
+ this.API_Link = _api_link;
+ localStorage.setItem("APILink", this.API_Link);
+ }
+
+ setApiToken(_api_token: string | null): void {
+ if (_api_token === null) _api_token = "";
+ this.API_Token = _api_token;
+ localStorage.setItem("AccessToken", this.API_Token);
+ }
+
+ getApiLink() {
+ return this.API_Link;
+ }
+
+ getApiToken() {
+ return this.API_Token;
+ }
+}
diff --git a/src/Views/LoginView.tsx b/src/Views/LoginView.tsx
new file mode 100644
index 0000000..e56dfd7
--- /dev/null
+++ b/src/Views/LoginView.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Card, Button, FormControl } from 'react-bootstrap';
+
+export default class LoginView extends React.Component<{
+ persistApiLink: any,
+ persistAccessToken: any,
+ verifyLogin: any,
+ getApiLinkFromDTO: any,
+ getApiTokenFromDTO: any
+}> {
+ render () {
+ return (
+
+
+
+ Please login to see the dashboard.
+
+ Please fill in the following items:
+ this.props.persistApiLink(e)}
+ />
+ this.props.persistAccessToken(e)}
+ />
+
+ Login
+
+ { localStorage.getItem("lastLoggedIn") !== null &&
+ Your last login was { localStorage.getItem("lastLoggedIn") }
+ }
+
+
+ );
+ }
+}
diff --git a/src/index.tsx b/src/index.tsx
index e6900ee..8d25800 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -4,4 +4,8 @@ import './index.css';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './Components/AppComponent/App';
-ReactDOM.render( , document.getElementById('App'));
+ReactDOM.render(
+
+
+ ,
+ document.getElementById('App'));
diff --git a/yarn.lock b/yarn.lock
index ea4589a..8284eff 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1259,6 +1259,43 @@ __metadata:
languageName: node
linkType: hard
+"@fortawesome/fontawesome-common-types@npm:^0.2.27":
+ version: 0.2.27
+ resolution: "@fortawesome/fontawesome-common-types@npm:0.2.27"
+ checksum: 2eb1f4adbe31a6533b3d3fdd20e37fd7c9e61cf29d144fcb3d225a5d16b57c16fa2a72dd6862382ea7b184aca85fd65b66781de1570a4b911eb4e9b39a74f9de
+ languageName: node
+ linkType: hard
+
+"@fortawesome/fontawesome-svg-core@npm:^1.2.27":
+ version: 1.2.27
+ resolution: "@fortawesome/fontawesome-svg-core@npm:1.2.27"
+ dependencies:
+ "@fortawesome/fontawesome-common-types": ^0.2.27
+ checksum: 000027a6d1a33a152e4799bd0c3c1507205697f86ddc0961f69f83c8561bcf93327353980efc8794f1dd7e7a1a50a36f710198d9f7e03855d9832fd5df6958f9
+ languageName: node
+ linkType: hard
+
+"@fortawesome/free-solid-svg-icons@npm:^5.12.1":
+ version: 5.12.1
+ resolution: "@fortawesome/free-solid-svg-icons@npm:5.12.1"
+ dependencies:
+ "@fortawesome/fontawesome-common-types": ^0.2.27
+ checksum: f966c13f826dfe57b2e2a212d5968ce7d4f9670ffb26d675259a2f0d19dfa777d269e6e4506e16d00da34943ae8526eb1fb2b889467f309ca3dbf371a57aec94
+ languageName: node
+ linkType: hard
+
+"@fortawesome/react-fontawesome@npm:^0.1.8":
+ version: 0.1.8
+ resolution: "@fortawesome/react-fontawesome@npm:0.1.8"
+ dependencies:
+ prop-types: ^15.5.10
+ peerDependencies:
+ "@fortawesome/fontawesome-svg-core": ^1.2.20
+ react: 16.x
+ checksum: c13777b29061dcca6d39ee2f30d820e1221e4293ce87d336197bb6e0c19adbd4bbb2963be03c71f8e093a36e813b8acf2079849e62a7450f1d871a8678ecd5d6
+ languageName: node
+ linkType: hard
+
"@hapi/address@npm:2.x.x":
version: 2.1.4
resolution: "@hapi/address@npm:2.1.4"
@@ -1769,7 +1806,7 @@ __metadata:
languageName: node
linkType: hard
-"@types/history@npm:*":
+"@types/history@npm:*, @types/history@npm:^4.7.5":
version: 4.7.5
resolution: "@types/history@npm:4.7.5"
checksum: 16a19c2b1aee6d0ff055940e4ca29db26aa8b0c8ff69161e70dec2151abb4fe3d5be846577c696a5d870a281e362669707ff43323d435a3d84811e6a238348f1
@@ -1876,6 +1913,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/react-fontawesome@npm:^1.6.4":
+ version: 1.6.4
+ resolution: "@types/react-fontawesome@npm:1.6.4"
+ dependencies:
+ "@types/react": "*"
+ checksum: ccf31aafa5c595ae9736ce5a9942c141a75c9ad11f8977c62ed4b06d7e1961ee8f226257fe867bd6df72ee62eed5bf8552250ada06d2fe38f8988a4a775fc0f6
+ languageName: node
+ linkType: hard
+
"@types/react-router-dom@npm:^5.1.3":
version: 5.1.3
resolution: "@types/react-router-dom@npm:5.1.3"
@@ -2817,6 +2863,15 @@ __metadata:
languageName: node
linkType: hard
+"axios@npm:^0.19.2":
+ version: 0.19.2
+ resolution: "axios@npm:0.19.2"
+ dependencies:
+ follow-redirects: 1.5.10
+ checksum: 28c860c203dc1e545a899eea83c95c51bb7de4a21ffef4781de11331207371c9cb1a680bcc7122dda936cd5e51f83f7b0a0eccc50801229b5e4914c8f2dd8907
+ languageName: node
+ linkType: hard
+
"axobject-query@npm:^2.0.2":
version: 2.1.1
resolution: "axobject-query@npm:2.1.1"
@@ -4530,6 +4585,15 @@ __metadata:
languageName: node
linkType: hard
+"debug@npm:=3.1.0":
+ version: 3.1.0
+ resolution: "debug@npm:3.1.0"
+ dependencies:
+ ms: 2.0.0
+ checksum: 31ac62be845b3e2bc49ea566665749e58030123e6d0b2960cb7c730037dc825f46d012e3f63f43fc9d60de3c52edbce705d22cb7e571e2822c81bc5d5ae09da9
+ languageName: node
+ linkType: hard
+
"debug@npm:^3.0.0, debug@npm:^3.1.1, debug@npm:^3.2.5, debug@npm:^3.2.6":
version: 3.2.6
resolution: "debug@npm:3.2.6"
@@ -4670,9 +4734,13 @@ __metadata:
version: 0.0.0-use.local
resolution: "demo-app@workspace:."
dependencies:
+ "@fortawesome/fontawesome-svg-core": ^1.2.27
+ "@fortawesome/free-solid-svg-icons": ^5.12.1
+ "@fortawesome/react-fontawesome": ^0.1.8
"@testing-library/jest-dom": ^4.2.4
"@testing-library/react": ^9.4.0
"@testing-library/user-event": ^7.1.2
+ "@types/history": ^4.7.5
"@types/istanbul-lib-coverage": ^2.0.1
"@types/jest": ^24.9.1
"@types/mocha": ^7.0.1
@@ -4680,23 +4748,26 @@ __metadata:
"@types/prop-types": ^15.7.3
"@types/react": ^16.9.19
"@types/react-dom": ^16.9.5
+ "@types/react-fontawesome": ^1.6.4
"@types/react-router-dom": ^5.1.3
"@typescript-eslint/eslint-plugin": ^2.19.2
"@typescript-eslint/parser": ^2.19.2
+ axios: ^0.19.2
bootstrap: ^4.4.1
eslint: ^6.8.0
eslint-config-prettier: ^6.10.0
eslint-plugin-prettier: ^3.1.2
eslint-plugin-react: ^7.18.3
+ history: ^4.10.1
jquery: ^3.4.1
popper.js: ^1.16.1
prettier: ^1.19.1
react: ^16.12.0
react-bootstrap: ^1.0.0-beta.16
react-dom: ^16.12.0
+ react-fontawesome: ^1.7.1
react-router-dom: ^5.1.2
react-scripts: 3.3.1
- store: ^2.0.12
typescript: ~3.7.2
languageName: unknown
linkType: soft
@@ -5994,6 +6065,15 @@ __metadata:
languageName: node
linkType: hard
+"follow-redirects@npm:1.5.10":
+ version: 1.5.10
+ resolution: "follow-redirects@npm:1.5.10"
+ dependencies:
+ debug: =3.1.0
+ checksum: 23c6333d60b73b899f9495d67b3dd5b2b99c26cd76278d03def3c39c715f0eed53cbfe1eb1e342a7281041961fe2c69c03daa97279df66a552ab6fb3d22059fc
+ languageName: node
+ linkType: hard
+
"follow-redirects@npm:^1.0.0":
version: 1.10.0
resolution: "follow-redirects@npm:1.10.0"
@@ -6582,7 +6662,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"history@npm:^4.9.0":
+"history@npm:^4.10.1, history@npm:^4.9.0":
version: 4.10.1
resolution: "history@npm:4.10.1"
dependencies:
@@ -11118,7 +11198,7 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
-"prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
+"prop-types@npm:^15.5.10, prop-types@npm:^15.5.6, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2":
version: 15.7.2
resolution: "prop-types@npm:15.7.2"
dependencies:
@@ -11425,6 +11505,17 @@ fsevents@^1.2.7:
languageName: node
linkType: hard
+"react-fontawesome@npm:^1.7.1":
+ version: 1.7.1
+ resolution: "react-fontawesome@npm:1.7.1"
+ dependencies:
+ prop-types: ^15.5.6
+ peerDependencies:
+ react: ">=0.12.0"
+ checksum: 9cedcd84255cb13196e7db70d49e928dc26982d059ae72396171f132933a38f50c9454b93f1f127edfd4a7fc7a4d01611f82dd73e86110724884ae9e9c064596
+ languageName: node
+ linkType: hard
+
"react-is@npm:^16.3.2, react-is@npm:^16.6.0, react-is@npm:^16.7.0, react-is@npm:^16.8.1, react-is@npm:^16.8.4":
version: 16.12.0
resolution: "react-is@npm:16.12.0"
@@ -12833,13 +12924,6 @@ resolve@1.1.7:
languageName: node
linkType: hard
-"store@npm:^2.0.12":
- version: 2.0.12
- resolution: "store@npm:2.0.12"
- checksum: 101053f2842b6a186d8556ef5a176feb4494cfe4a182b454c5c7150362c67344abafd8e012c7769ea51745cdff38447c3e0c9d5ef36740bcc65e174adb605309
- languageName: node
- linkType: hard
-
"stream-browserify@npm:^2.0.1":
version: 2.0.2
resolution: "stream-browserify@npm:2.0.2"