1
0
mirror of https://github.com/mgerb/go-discord-bot synced 2026-01-09 16:42:48 +00:00

statistics tab for discord chat

This commit is contained in:
2018-04-10 21:51:45 -05:00
parent 27a42f1b99
commit 5fa0f1ac2e
22 changed files with 281 additions and 34 deletions

View File

@@ -9,6 +9,7 @@ import { NotFound } from './pages/NotFound/NotFound';
import { Downloader } from './pages/Downloader/Downloader';
import { Clips } from './pages/Clips';
import { Oauth } from './pages/oauth/oauth';
import { Stats } from './pages/stats/stats';
import 'babel-polyfill';
const App: any = (): any => {
@@ -21,6 +22,7 @@ const App: any = (): any => {
<Route path="/downloader" component={Downloader} />
<Route path="/clips" component={Clips} />
<Route path="/oauth" component={Oauth} />
<Route path="/stats" component={Stats} />
<Route component={NotFound} />
</Switch>
</Wrapper>

View File

@@ -1,9 +1,8 @@
import React from 'react';
import { NavLink } from 'react-router-dom';
import jwt_decode from 'jwt-decode';
import { StorageService } from '../../services';
import './Navbar.scss';
import { storage } from '../../storage';
let oauthUrl: string;
@@ -31,25 +30,24 @@ export class Navbar extends React.Component<Props, State> {
}
componentDidMount() {
const token = storage.getJWT();
const token = StorageService.getJWT();
if (token) {
const claims: any = jwt_decode(token!);
console.log(claims);
const email = claims['email'];
this.setState({ token, email });
}
}
private logout = () => {
localStorage.clear();
StorageService.clear();
window.location.href = '/';
};
render() {
return (
<div className="Navbar">
<div className="Navbar__header">Go Discord Bot</div>
<div className="Navbar__header">Cash</div>
<NavLink exact to="/" className="Navbar__item" activeClassName="Navbar__item--active">
Home
</NavLink>
@@ -62,6 +60,9 @@ export class Navbar extends React.Component<Props, State> {
<NavLink to="/clips" className="Navbar__item" activeClassName="Navbar__item--active">
Clips
</NavLink>
<NavLink to="/stats" className="Navbar__item" activeClassName="Navbar__item--active">
Stats
</NavLink>
{!this.state.token ? (
<a href={oauthUrl} className="Navbar__item">

View File

@@ -51,8 +51,8 @@ export class SoundList extends React.Component<Props, State> {
const { soundList, type } = this.props;
return (
<div className="Card">
<div className="Card__header" style={{ display: 'flex' }}>
<div className="card">
<div className="card__header" style={{ display: 'flex' }}>
<div>
<span>{type}</span>
<i className="fa fa fa-volume-up" aria-hidden="true" />

View File

@@ -1,5 +1,5 @@
import React from 'react';
import axios from 'axios';
import { axios } from '../../services';
import { SoundList, SoundType } from '../../components/SoundList';

View File

@@ -1,5 +1,5 @@
import React from 'react';
import axios from 'axios';
import { axios } from '../../services';
import './Downloader.scss';

View File

@@ -1,3 +0,0 @@
.Home {
padding: 10px;
}

View File

@@ -9,9 +9,9 @@ interface State {}
export class Home extends React.Component<Props, State> {
render() {
return (
<div className="Home">
<div className="Card">
<div className="Card__header">Go Discord Bot</div>
<div className="content">
<div className="card">
<div className="card__header">Go Discord Bot</div>
<h3>04-09-18 Update</h3>
<ul>

View File

@@ -3,7 +3,7 @@
*/
import React from 'react';
import axios from 'axios';
import { axios } from '../../services';
import * as _ from 'lodash';
import './Pubg.scss';

View File

@@ -1,11 +1,9 @@
import React from 'react';
import Dropzone from 'react-dropzone';
import axios, { AxiosRequestConfig } from 'axios';
import { axios } from '../../services';
import { SoundList, SoundType } from '../../components/SoundList';
import './Soundboard.scss';
import { storage } from '../../storage';
import { AxiosRequestConfig } from 'axios';
let self: any;
@@ -37,7 +35,6 @@ export class Soundboard extends React.Component<Props, State> {
this.config = {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: `Bearer ${storage.getJWT()}`,
},
onUploadProgress: progressEvent => {
this.setState({

View File

@@ -1,8 +1,7 @@
import React from 'react';
import axios from 'axios';
import { axios, StorageService } from '../../services';
import queryString from 'query-string';
import { RouteComponentProps } from 'react-router-dom';
import { storage } from '../../storage';
interface Props extends RouteComponentProps<any> {}
@@ -25,7 +24,7 @@ export class Oauth extends React.Component<Props, State> {
private async fetchOauth(code: string) {
try {
const res = await axios.post('/api/oauth', { code });
storage.setJWT(res.data);
StorageService.setJWT(res.data);
window.location.href = '/';
} catch (e) {
console.error(e);

View File

@@ -0,0 +1,3 @@
.Stats {
padding: 10px;
}

View File

@@ -0,0 +1,70 @@
import React, { Component } from 'react';
import { HorizontalBar } from 'react-chartjs-2';
import { chain, map } from 'lodash';
import { axios } from '../../services';
import './stats.scss';
interface IState {
data: {
username: string;
count: number;
}[];
}
/**
* a page to show discord chat statistics
* currently keeps track of number messages that contain external links
*/
export class Stats extends Component<any, IState> {
constructor(props: any) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
this.getdata();
}
async getdata() {
const messages = await axios.get('/api/logger/linkedmessages');
const data: any = chain(messages.data)
.map((v, k) => {
return { username: k, count: v };
})
.orderBy(v => v.count, 'desc')
.value();
this.setState({ data });
}
render() {
const data: any = {
labels: map(this.state.data, v => v.username),
datasets: [
{
label: 'Count',
backgroundColor: 'rgba(114,137,218, 0.4)',
borderColor: 'rgba(114,137,218, 0.9)',
borderWidth: 1,
hoverBackgroundColor: 'rgba(114,137,218, 0.6)',
hoverBorderColor: 'rgba(114,137,218, 1)',
data: map(this.state.data, v => v.count),
},
],
options: {
responsive: true,
},
};
return (
<div className="content">
<div className="card" style={{ maxWidth: '1000px' }}>
<div className="card__header">Shitposts</div>
<HorizontalBar data={data} height={500} />
</div>
</div>
);
}
}

View File

@@ -25,6 +25,10 @@ body {
padding-left: $navbarWidth;
}
.content {
padding: 10px;
}
.input {
border-radius: 3px;
border: 1px solid $lightGray;
@@ -56,7 +60,7 @@ body {
}
}
.Card {
.card {
background-color: $gray2;
border-radius: 5px;
max-width: 800px;
@@ -65,7 +69,7 @@ body {
border: 1px solid $gray3;
}
.Card__header {
.card__header {
margin: -10px -10px 10px -10px;
display: flex;
align-items: center;

View File

@@ -0,0 +1,19 @@
import ax from 'axios';
import { StorageService } from './storage.service';
export const axios = ax.create();
axios.interceptors.request.use(
config => {
const jwt = StorageService.getJWT();
if (jwt) {
config.headers['Authorization'] = `Bearer ${jwt}`;
}
// Do something before request is sent
return config;
},
function(error) {
// Do something with request error
return Promise.reject(error);
},
);

View File

@@ -0,0 +1,2 @@
export * from './axios.service';
export * from './storage.service';

View File

@@ -1,3 +1,7 @@
const clear = () => {
localStorage.clear();
};
const setJWT = (token: string) => {
localStorage.setItem('jwt', token);
};
@@ -6,7 +10,8 @@ const getJWT = (): string | null => {
return localStorage.getItem('jwt');
};
export const storage = {
export const StorageService = {
clear,
getJWT,
setJWT,
};

View File

@@ -9,6 +9,11 @@
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz",
"integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow=="
},
"@types/chart.js": {
"version": "2.7.11",
"resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.7.11.tgz",
"integrity": "sha512-56jTNUUBLJ7zr+CSN3S3SBBPYPzPOgAtmoBhscANfCQ7F+AUnXbdS2c7RX0KyGyMzJu3LMfVKWU6lS+JDug/Vw=="
},
"@types/history": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.6.2.tgz",
@@ -42,6 +47,14 @@
"csstype": "2.1.1"
}
},
"@types/react-chartjs-2": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/@types/react-chartjs-2/-/react-chartjs-2-2.5.7.tgz",
"integrity": "sha512-waqYqiNULIVUqaKO7MGUpFmWrVtH7gVPOzqwV4y4zgUyu/JiDwC005PpveO442HKnby9kLgp3t1SB2sld+ACLw==",
"requires": {
"react-chartjs-2": "2.7.0"
}
},
"@types/react-dom": {
"version": "16.0.4",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.0.4.tgz",
@@ -1761,6 +1774,39 @@
"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz",
"integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
},
"chart.js": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz",
"integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==",
"requires": {
"chartjs-color": "2.2.0",
"moment": "2.22.0"
}
},
"chartjs-color": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz",
"integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=",
"requires": {
"chartjs-color-string": "0.5.0",
"color-convert": "0.5.3"
},
"dependencies": {
"color-convert": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
"integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
}
}
},
"chartjs-color-string": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz",
"integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==",
"requires": {
"color-name": "1.1.3"
}
},
"cheerio": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz",
@@ -6799,6 +6845,11 @@
"minimist": "0.0.8"
}
},
"moment": {
"version": "2.22.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.22.0.tgz",
"integrity": "sha512-1muXCh8jb1N/gHRbn9VDUBr0GYb8A/aVcHlII9QSB68a50spqEVLIGN6KVmCOnSvJrUhC0edGgKU5ofnGXdYdg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
@@ -9166,6 +9217,15 @@
"prop-types": "15.6.1"
}
},
"react-chartjs-2": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.7.0.tgz",
"integrity": "sha512-DkT9TVi+/wKaEWL2iI2ka2L3Q0kq+y7TrAqlWNETAqE5CTPphPg1Af3w9X2uQCQ1ZA60Q3base9mK3dRtlb9bQ==",
"requires": {
"lodash": "4.17.5",
"prop-types": "15.6.1"
}
},
"react-dom": {
"version": "16.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.3.1.tgz",

View File

@@ -10,11 +10,13 @@
"author": "Mitchell Gerber",
"license": "MIT",
"dependencies": {
"@types/chart.js": "^2.7.11",
"@types/jwt-decode": "^2.2.1",
"@types/lodash": "^4.14.71",
"@types/node": "^9.4.6",
"@types/query-string": "^5.1.0",
"@types/react": "^16.0.0",
"@types/react-chartjs-2": "^2.5.7",
"@types/react-dom": "^16.0.4",
"@types/react-dropzone": "^4.2.0",
"@types/react-router-dom": "^4.2.6",
@@ -27,6 +29,7 @@
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-0": "^6.16.0",
"chart.js": "^2.7.2",
"clean-webpack-plugin": "^0.1.14",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
@@ -41,6 +44,7 @@
"postcss-loader": "^2.1.3",
"query-string": "^6.0.0",
"react": "^16.3.1",
"react-chartjs-2": "^2.7.0",
"react-dom": "^16.3.1",
"react-dropzone": "^4.2.9",
"react-router-dom": "^4.2.2",