feature(database-connection): Restructure frontend
This commit is contained in:
15
frontend/generate-react-cli.json
Normal file
15
frontend/generate-react-cli.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"usesTypeScript": true,
|
||||||
|
"usesCssModule": false,
|
||||||
|
"cssPreprocessor": "scss",
|
||||||
|
"testLibrary": "Testing Library",
|
||||||
|
"component": {
|
||||||
|
"default": {
|
||||||
|
"path": "src/components",
|
||||||
|
"withStyle": true,
|
||||||
|
"withTest": true,
|
||||||
|
"withStory": false,
|
||||||
|
"withLazy": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,37 +18,6 @@
|
|||||||
filter: blur(5px);
|
filter: blur(5px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.first-place {
|
|
||||||
font-size: xx-large;
|
|
||||||
font-weight: bolder;
|
|
||||||
color: gold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.second-place {
|
|
||||||
font-size: x-large;
|
|
||||||
font-weight: bold;
|
|
||||||
color: silver;
|
|
||||||
}
|
|
||||||
|
|
||||||
.third-place {
|
|
||||||
font-size: larger;
|
|
||||||
color: saddlebrown;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 4vw;
|
|
||||||
color: #88c9db;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer {
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:link,
|
a:link,
|
||||||
a:visited,
|
a:visited,
|
||||||
a:hover,
|
a:hover,
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import UserStatsMockService from "./mock/UserStatsMockService";
|
|||||||
import UserStatsService from "./services/UserStatsService";
|
import UserStatsService from "./services/UserStatsService";
|
||||||
import {findDOMNode} from "react-dom";
|
import {findDOMNode} from "react-dom";
|
||||||
import TableEntry from "./models/TableEntry";
|
import TableEntry from "./models/TableEntry";
|
||||||
|
import UserList from './components/UserList/UserList';
|
||||||
|
import ErrorContainer from './components/ErrorContainer/ErrorContainer';
|
||||||
|
import Footer from './components/Footer/Footer';
|
||||||
|
import Header from './components/Header/Header';
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
error?: string,
|
error?: string,
|
||||||
isLoaded: boolean,
|
loading: boolean,
|
||||||
users?: TableEntry[],
|
users: TableEntry[],
|
||||||
mock?: TableEntry[]
|
mock: TableEntry[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
@@ -17,36 +21,47 @@ export default class App extends React.Component {
|
|||||||
private apiService: UserStatsService = new UserStatsService();
|
private apiService: UserStatsService = new UserStatsService();
|
||||||
private mockService = new UserStatsMockService();
|
private mockService = new UserStatsMockService();
|
||||||
|
|
||||||
state: State = {
|
state: State;
|
||||||
error: undefined,
|
|
||||||
isLoaded: false,
|
constructor(props: Readonly<{}>) {
|
||||||
users: undefined,
|
super(props);
|
||||||
mock: undefined
|
this.state = {
|
||||||
|
error: undefined,
|
||||||
|
loading: false,
|
||||||
|
users: [],
|
||||||
|
mock: this.mockService.getStatsWithoutPromise()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentWillMount() {
|
||||||
this.setState({isLoaded: false, mock: this.mockService.getStatsWithoutPromise()});
|
this.fetchData();
|
||||||
// this.mockService.getStats()
|
|
||||||
// .then(data => this.setState({
|
|
||||||
// data: data,
|
|
||||||
// mock: data
|
|
||||||
// }))
|
|
||||||
// .finally(() => {
|
|
||||||
// });
|
|
||||||
this.apiService.getStats()
|
|
||||||
.then(data => this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
users: data
|
|
||||||
}))
|
|
||||||
.catch(error => {
|
|
||||||
error.response.json()
|
|
||||||
.then((err: any) => this.setState({
|
|
||||||
isLoaded: true,
|
|
||||||
error: err.error
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fetchData() {
|
||||||
|
this.setState({ loading: true })
|
||||||
|
this.apiService.getStats()
|
||||||
|
.then(data => this.setState({
|
||||||
|
loading: false,
|
||||||
|
users: data
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// componentDidMount() {
|
||||||
|
// this.setState({loading: false, mock: this.mockService.getStatsWithoutPromise()});
|
||||||
|
// this.apiService.getStats()
|
||||||
|
// .then(data => this.setState({
|
||||||
|
// isLoaded: true,
|
||||||
|
// users: data
|
||||||
|
// }))
|
||||||
|
// .catch(error => {
|
||||||
|
// error.response.json()
|
||||||
|
// .then((err: any) => this.setState({
|
||||||
|
// isLoaded: true,
|
||||||
|
// error: err.error
|
||||||
|
// }))
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const element = findDOMNode(this);
|
const element = findDOMNode(this);
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
@@ -54,63 +69,20 @@ export default class App extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createTableEntries(entries: TableEntry[]) {
|
|
||||||
return entries.map((entry, index) => {
|
|
||||||
const placement = index + 1;
|
|
||||||
const placementClassName = placement === 1 ? "first-place"
|
|
||||||
: (placement === 2 ? "second-place"
|
|
||||||
: (placement === 3 ? "third-place"
|
|
||||||
: undefined))
|
|
||||||
return (
|
|
||||||
<tr key={index} className={placementClassName}>
|
|
||||||
<td>{placement}</td>
|
|
||||||
<td>{entry.name}</td>
|
|
||||||
<td>{entry.rank}</td>
|
|
||||||
<td>{entry.onlineTime}</td>
|
|
||||||
</tr>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTableData() {
|
|
||||||
const { error, isLoaded, users, mock } = this.state;
|
|
||||||
if (users != null && isLoaded && error == null) {
|
|
||||||
return this.createTableEntries(users);
|
|
||||||
} else if (isLoaded && error != null && mock != null) {
|
|
||||||
return this.createTableEntries(mock);
|
|
||||||
} else if (mock != null) {
|
|
||||||
return this.createTableEntries(mock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<p className="title">Humenius' TeamSpeak 3-Ranking</p>
|
<Header />
|
||||||
{ this.state.error != null ? <p className="error-message"> { this.state.error } Please try again later!</p> : null}
|
{/* { this.state.error != null ? <p className="error-message"> { this.state.error } Please try again later!</p> : null} */}
|
||||||
<table>
|
{
|
||||||
<thead>
|
(!this.state.error && this.state.loading)
|
||||||
<tr>
|
? <UserList users={this.state.mock} />
|
||||||
<th>Placement</th>
|
: <UserList users={this.state.users} />
|
||||||
<th>Name</th>
|
}
|
||||||
<th>Rank</th>
|
{
|
||||||
<th>Online time</th>
|
this.state.error && <ErrorContainer message={this.state.error} />
|
||||||
</tr>
|
}
|
||||||
</thead>
|
<Footer />
|
||||||
<tbody className={this.state.error != null || !this.state.isLoaded ? "blurred" : undefined}>
|
|
||||||
{this.renderTableData()}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<footer>
|
|
||||||
Made by <a href="https://humenius.me"
|
|
||||||
>Humenius</a>.
|
|
||||||
Powered by <a href="https://reactjs.org/"
|
|
||||||
>React</a>.
|
|
||||||
<br/>
|
|
||||||
<a href="ts3server://ts.humenius.me">
|
|
||||||
Click here to join my TeamSpeak server
|
|
||||||
</a>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
.ErrorContainer {
|
||||||
|
.error-message {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
import ErrorContainer from './ErrorContainer';
|
||||||
|
|
||||||
|
describe('<ErrorContainer />', () => {
|
||||||
|
test('it should mount', () => {
|
||||||
|
render(<ErrorContainer />);
|
||||||
|
|
||||||
|
const errorContainer = screen.getByTestId('ErrorContainer');
|
||||||
|
|
||||||
|
expect(errorContainer).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
22
frontend/src/components/ErrorContainer/ErrorContainer.tsx
Normal file
22
frontend/src/components/ErrorContainer/ErrorContainer.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './ErrorContainer.scss';
|
||||||
|
|
||||||
|
export interface ErrorContainerProperties {
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class ErrorContainer extends React.Component<ErrorContainerProperties> {
|
||||||
|
constructor(props: Readonly<ErrorContainerProperties>) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="ErrorContainer" data-testid="ErrorContainer">
|
||||||
|
{ this.props.message }
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ErrorContainer;
|
||||||
5
frontend/src/components/Footer/Footer.scss
Normal file
5
frontend/src/components/Footer/Footer.scss
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.Footer {
|
||||||
|
footer {
|
||||||
|
padding: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
frontend/src/components/Footer/Footer.test.tsx
Normal file
14
frontend/src/components/Footer/Footer.test.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
import Footer from './Footer';
|
||||||
|
|
||||||
|
describe('<Footer />', () => {
|
||||||
|
test('it should mount', () => {
|
||||||
|
render(<Footer />);
|
||||||
|
|
||||||
|
const footer = screen.getByTestId('Footer');
|
||||||
|
|
||||||
|
expect(footer).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
17
frontend/src/components/Footer/Footer.tsx
Normal file
17
frontend/src/components/Footer/Footer.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './Footer.scss';
|
||||||
|
|
||||||
|
const Footer: React.FC = () => (
|
||||||
|
<div className="Footer" data-testid="Footer">
|
||||||
|
<footer>
|
||||||
|
Made by <a href="https://humenius.me">Humenius</a>.
|
||||||
|
Powered by <a href="https://reactjs.org/">React</a>.
|
||||||
|
<br/>
|
||||||
|
<a href="ts3server://ts.humenius.me">
|
||||||
|
Click here to join my TeamSpeak server
|
||||||
|
</a>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Footer;
|
||||||
6
frontend/src/components/Header/Header.scss
Normal file
6
frontend/src/components/Header/Header.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.Header {
|
||||||
|
.title {
|
||||||
|
font-size: 4vw;
|
||||||
|
color: #88c9db;
|
||||||
|
}
|
||||||
|
}
|
||||||
14
frontend/src/components/Header/Header.test.tsx
Normal file
14
frontend/src/components/Header/Header.test.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
import Header from './Header';
|
||||||
|
|
||||||
|
describe('<Header />', () => {
|
||||||
|
test('it should mount', () => {
|
||||||
|
render(<Header />);
|
||||||
|
|
||||||
|
const header = screen.getByTestId('Header');
|
||||||
|
|
||||||
|
expect(header).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
10
frontend/src/components/Header/Header.tsx
Normal file
10
frontend/src/components/Header/Header.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import './Header.scss';
|
||||||
|
|
||||||
|
const Header: React.FC = () => (
|
||||||
|
<div className="Header" data-testid="Header">
|
||||||
|
<p className="title">Humenius' TeamSpeak 3-Ranking</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default Header;
|
||||||
19
frontend/src/components/UserList/UserList.scss
Normal file
19
frontend/src/components/UserList/UserList.scss
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
.UserList {
|
||||||
|
.first-place {
|
||||||
|
font-size: xx-large;
|
||||||
|
font-weight: bolder;
|
||||||
|
color: gold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.second-place {
|
||||||
|
font-size: x-large;
|
||||||
|
font-weight: bold;
|
||||||
|
color: silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
.third-place {
|
||||||
|
font-size: larger;
|
||||||
|
color: saddlebrown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
14
frontend/src/components/UserList/UserList.test.tsx
Normal file
14
frontend/src/components/UserList/UserList.test.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from '@testing-library/react';
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
|
import UserList from './UserList';
|
||||||
|
|
||||||
|
describe('<UserList />', () => {
|
||||||
|
test('it should mount', () => {
|
||||||
|
render(<UserList />);
|
||||||
|
|
||||||
|
const userList = screen.getByTestId('UserList');
|
||||||
|
|
||||||
|
expect(userList).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
72
frontend/src/components/UserList/UserList.tsx
Normal file
72
frontend/src/components/UserList/UserList.tsx
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import TableEntry from '../../models/TableEntry';
|
||||||
|
import './UserList.scss';
|
||||||
|
|
||||||
|
// const UserList: React.FC = () => (
|
||||||
|
// <div className="UserList" data-testid="UserList">
|
||||||
|
// UserList Component
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
|
||||||
|
interface UserListProperties {
|
||||||
|
users: TableEntry[]
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserList extends React.Component<UserListProperties> {
|
||||||
|
|
||||||
|
constructor(props: Readonly<UserListProperties>) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createTableEntries(entries: TableEntry[]) {
|
||||||
|
return entries.map((entry, index) => {
|
||||||
|
const placement = index + 1;
|
||||||
|
const placementClassName = placement === 1 ? "first-place"
|
||||||
|
: (placement === 2 ? "second-place"
|
||||||
|
: (placement === 3 ? "third-place"
|
||||||
|
: undefined))
|
||||||
|
return (
|
||||||
|
<tr key={index} className={placementClassName}>
|
||||||
|
<td>{placement}</td>
|
||||||
|
<td>{entry.name}</td>
|
||||||
|
<td>{entry.rank}</td>
|
||||||
|
<td>{entry.onlineTime}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderTableData() {
|
||||||
|
// // const { error, isLoaded, users, mock } = this.state;
|
||||||
|
// // if (users != null && isLoaded && error == null) {
|
||||||
|
// // return this.createTableEntries(users);
|
||||||
|
// // } else if (isLoaded && error != null && mock != null) {
|
||||||
|
// // return this.createTableEntries(mock);
|
||||||
|
// // } else if (mock != null) {
|
||||||
|
// // return this.createTableEntries(mock);
|
||||||
|
// // }
|
||||||
|
// return this.createTableEntries();
|
||||||
|
// }
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="UserList" data-testid="UserList">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Placement</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Rank</th>
|
||||||
|
<th>Online time</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{this.createTableEntries(this.props.users)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UserList;
|
||||||
@@ -7,12 +7,12 @@ export default class UserStatsMockService extends UserStatsService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.entries = [
|
this.entries = [
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
|
{ name: "Humen", rank: "Overwatch Noob", onlineTime: "0d 1h 0m 0s" },
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
|
{ name: "Humen", rank: "Random Rank 3", onlineTime: "0d 1h 0m 0s" },
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
|
{ name: "Humen", rank: "Kas is cool", onlineTime: "0d 1h 0m 0s" },
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
|
{ name: "Humen", rank: "Bremsspur", onlineTime: "0d 1h 0m 0s" },
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
|
{ name: "Humen", rank: "12", onlineTime: "0d 1h 0m 0s" },
|
||||||
{ name: "Humen", onlineTime: "0d 1h 0m 0s" }
|
{ name: "Humen", rank: "ok", onlineTime: "0d 1h 0m 0s" }
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3315
frontend/yarn.lock
3315
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user