feature(database-connection): Restructure frontend

This commit is contained in:
2021-01-11 08:11:02 +01:00
parent ceea2a7616
commit ff1c56c791
17 changed files with 2057 additions and 1666 deletions

View 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
}
}
}

View File

@@ -18,37 +18,6 @@
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:visited,
a:hover,

View File

@@ -4,12 +4,16 @@ import UserStatsMockService from "./mock/UserStatsMockService";
import UserStatsService from "./services/UserStatsService";
import {findDOMNode} from "react-dom";
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 {
error?: string,
isLoaded: boolean,
users?: TableEntry[],
mock?: TableEntry[]
loading: boolean,
users: TableEntry[],
mock: TableEntry[]
}
export default class App extends React.Component {
@@ -17,36 +21,47 @@ export default class App extends React.Component {
private apiService: UserStatsService = new UserStatsService();
private mockService = new UserStatsMockService();
state: State = {
error: undefined,
isLoaded: false,
users: undefined,
mock: undefined
state: State;
constructor(props: Readonly<{}>) {
super(props);
this.state = {
error: undefined,
loading: false,
users: [],
mock: this.mockService.getStatsWithoutPromise()
}
}
componentDidMount() {
this.setState({isLoaded: false, mock: this.mockService.getStatsWithoutPromise()});
// 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
}))
});
componentWillMount() {
this.fetchData();
}
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() {
const element = findDOMNode(this);
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() {
return (
<div className="App">
<p className="title">Humenius' TeamSpeak 3-Ranking</p>
{ this.state.error != null ? <p className="error-message"> { this.state.error } Please try again later!</p> : null}
<table>
<thead>
<tr>
<th>Placement</th>
<th>Name</th>
<th>Rank</th>
<th>Online time</th>
</tr>
</thead>
<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>
<Header />
{/* { this.state.error != null ? <p className="error-message"> { this.state.error } Please try again later!</p> : null} */}
{
(!this.state.error && this.state.loading)
? <UserList users={this.state.mock} />
: <UserList users={this.state.users} />
}
{
this.state.error && <ErrorContainer message={this.state.error} />
}
<Footer />
</div>
);
}

View File

@@ -0,0 +1,5 @@
.ErrorContainer {
.error-message {
color: red;
}
}

View File

@@ -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();
});
});

View 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;

View File

@@ -0,0 +1,5 @@
.Footer {
footer {
padding: 2rem;
}
}

View 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();
});
});

View 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;

View File

@@ -0,0 +1,6 @@
.Header {
.title {
font-size: 4vw;
color: #88c9db;
}
}

View 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();
});
});

View 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;

View 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;
}
}

View 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();
});
});

View 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;

View File

@@ -7,12 +7,12 @@ export default class UserStatsMockService extends UserStatsService {
constructor() {
super();
this.entries = [
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", onlineTime: "0d 1h 0m 0s" }
{ name: "Humen", rank: "Overwatch Noob", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", rank: "Random Rank 3", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", rank: "Kas is cool", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", rank: "Bremsspur", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", rank: "12", onlineTime: "0d 1h 0m 0s" },
{ name: "Humen", rank: "ok", onlineTime: "0d 1h 0m 0s" }
];
}

File diff suppressed because it is too large Load Diff