1
0
mirror of https://github.com/mgerb/go-discord-bot synced 2026-01-10 09:02:49 +00:00

refactor: move upload history to its own page

This commit is contained in:
2019-08-24 13:22:05 -05:00
parent 55a4bb73af
commit f9c3922670
12 changed files with 104 additions and 82 deletions

View File

@@ -2,7 +2,7 @@ import { Provider } from 'mobx-react';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom'; import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages'; import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, UploadHistory, VideoArchive } from './pages';
import './scss/index.scss'; import './scss/index.scss';
import { rootStoreInstance } from './stores'; import { rootStoreInstance } from './stores';
import { Wrapper } from './wrapper'; import { Wrapper } from './wrapper';
@@ -14,6 +14,7 @@ const App: any = (): any => {
<Wrapper> <Wrapper>
<Switch> <Switch>
<Route exact path="/" component={Soundboard} /> <Route exact path="/" component={Soundboard} />
<Route path="/upload-history" component={UploadHistory} />
<Route path="/downloader" component={Downloader} /> <Route path="/downloader" component={Downloader} />
<Route path="/clips" component={Clips} /> <Route path="/clips" component={Clips} />
<Route path="/oauth" component={Oauth} /> <Route path="/oauth" component={Oauth} />

View File

@@ -2,5 +2,4 @@ export * from './embedded-youtube/embedded-youtube';
export * from './header/header'; export * from './header/header';
export * from './navbar/navbar'; export * from './navbar/navbar';
export * from './sound-list/sound-list'; export * from './sound-list/sound-list';
export * from './upload-history/upload-history';
export * from './uploader/uploader'; export * from './uploader/uploader';

View File

@@ -1,12 +1,11 @@
import React from 'react'; import React from 'react';
import { NavLink } from 'react-router-dom'; import { NavLink } from 'react-router-dom';
import { IClaims, Permissions } from '../../model';
import { OauthService, StorageService } from '../../services'; import { OauthService, StorageService } from '../../services';
import { AppStore } from '../../stores';
import './navbar.scss'; import './navbar.scss';
interface Props { interface Props {
claims?: IClaims; appStore: AppStore;
open: boolean;
onNavClick: () => void; onNavClick: () => void;
} }
@@ -37,7 +36,7 @@ export class Navbar extends React.Component<Props, State> {
}; };
renderLoginButton() { renderLoginButton() {
const { claims } = this.props; const { claims } = this.props.appStore;
if (!this.state.oauthUrl) { if (!this.state.oauthUrl) {
return null; return null;
@@ -69,19 +68,17 @@ export class Navbar extends React.Component<Props, State> {
}; };
render() { render() {
const { claims, open } = this.props; const { claims, navbarOpen, hasModPermissions, hasAdminPermissions } = this.props.appStore;
const openClass = open ? 'navbar--open' : ''; const openClass = navbarOpen ? 'navbar--open' : '';
return ( return (
<div className={'navbar ' + openClass}> <div className={'navbar ' + openClass}>
{this.renderNavLink('Soundboard', '/', { exact: true })} {this.renderNavLink('Soundboard', '/', { exact: true })}
{hasModPermissions() && this.renderNavLink('Upload History', '/upload-history')}
{this.renderNavLink('Video Archive', '/video-archive')} {this.renderNavLink('Video Archive', '/video-archive')}
{this.renderNavLink('Youtube Downloader', '/downloader')} {this.renderNavLink('Youtube Downloader', '/downloader')}
{this.renderNavLink('Clips', '/clips')} {this.renderNavLink('Clips', '/clips')}
{this.renderNavLink('Stats', '/stats')} {this.renderNavLink('Stats', '/stats')}
{claims && {hasAdminPermissions() && this.renderNavLink('Admin', '/admin')}
claims.permissions &&
claims.permissions === Permissions.Admin &&
this.renderNavLink('Admin', '/admin')}
{this.renderLoginButton()} {this.renderLoginButton()}
{claims && claims.email && <div className="navbar__email">{claims.email}</div>} {claims && claims.email && <div className="navbar__email">{claims.email}</div>}

View File

@@ -5,6 +5,7 @@ import './sound-list.scss';
interface Props { interface Props {
soundList: SoundType[]; soundList: SoundType[];
type: 'sounds' | 'clips'; type: 'sounds' | 'clips';
title: string;
onPlayDiscord?: (sound: SoundType) => void; onPlayDiscord?: (sound: SoundType) => void;
showDiscordPlay?: boolean; showDiscordPlay?: boolean;
} }
@@ -47,13 +48,13 @@ export class SoundList extends React.Component<Props, State> {
} }
render() { render() {
const { showDiscordPlay, soundList, type } = this.props; const { showDiscordPlay, soundList, title, type } = this.props;
return ( return (
<div className="card"> <div className="card">
<div className="card__header" style={{ display: 'flex' }}> <div className="card__header" style={{ display: 'flex' }}>
<div> <div>
<span>{type}</span> <span>{title}</span>
<i className="fa fa fa-volume-up" aria-hidden="true" /> <i className="fa fa fa-volume-up" aria-hidden="true" />
</div> </div>
<div style={{ flex: 1 }} /> <div style={{ flex: 1 }} />

View File

@@ -1,53 +0,0 @@
import * as _ from 'lodash';
import { DateTime } from 'luxon';
import React from 'react';
import { ISound } from '../../model';
import { ClipPlayerControl } from '../clip-player-control/clip-player-control';
interface IProps {
sounds: ISound[];
showDiscordPlay?: boolean;
}
export const UploadHistory = ({ sounds, showDiscordPlay }: IProps) => {
const sortedSounds = _.orderBy(sounds, 'created_at', 'desc');
return (
<div className="card">
<div className="card__header">Upload History</div>
<table className="table table--ellipsis">
<thead>
<tr>
<th className="hide-small">Date</th>
<th>Sound</th>
<th className="hide-small">Ext</th>
<th>User</th>
<th className="hide-small">Email</th>
</tr>
</thead>
<tbody>
{sortedSounds.map((s: ISound, i) => {
const formattedDate = DateTime.fromISO(s.created_at).toLocaleString();
return (
<tr key={i}>
<td className="hide-small" title={formattedDate}>
{formattedDate}
</td>
<td title={s.name}>{s.name}</td>
<td className="hide-small" title={s.extension}>
{s.extension}
</td>
<td title={s.user.username}>{s.user.username}</td>
<td className="hide-small" title={s.user.email}>
{s.user.email}
</td>
<td>
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={s} type="sounds"></ClipPlayerControl>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
};

View File

@@ -37,7 +37,7 @@ export class Clips extends React.Component<Props, State> {
return ( return (
<div className="content"> <div className="content">
<div className="column"> <div className="column">
<SoundList soundList={this.state.clipList} type="clips" /> <SoundList soundList={this.state.clipList} type="clips" title="Clips" />
</div> </div>
</div> </div>
); );

View File

@@ -5,4 +5,5 @@ export * from './not-found/not-found';
export * from './oauth/oauth'; export * from './oauth/oauth';
export * from './soundboard/soundboard'; export * from './soundboard/soundboard';
export * from './stats/stats'; export * from './stats/stats';
export * from './upload-history/upload-history';
export * from './video-archive/video-archive'; export * from './video-archive/video-archive';

View File

@@ -72,6 +72,7 @@ export class Soundboard extends React.Component<Props, State> {
<Uploader onComplete={this.onUploadComplete} /> <Uploader onComplete={this.onUploadComplete} />
<SoundList <SoundList
soundList={soundList} soundList={soundList}
title="Sounds"
type="sounds" type="sounds"
onPlayDiscord={this.onPlayDiscord} onPlayDiscord={this.onPlayDiscord}
showDiscordPlay={appStore!.hasModPermissions()} showDiscordPlay={appStore!.hasModPermissions()}

View File

@@ -1,16 +1,11 @@
import { chain, map } from 'lodash'; import { chain, map } from 'lodash';
import { inject, observer } from 'mobx-react';
import React, { Component } from 'react'; import React, { Component } from 'react';
import { HorizontalBar } from 'react-chartjs-2'; import { HorizontalBar } from 'react-chartjs-2';
import { UploadHistory } from '../../components';
import { ISound } from '../../model'; import { ISound } from '../../model';
import { axios, SoundService } from '../../services'; import { axios, SoundService } from '../../services';
import { AppStore } from '../../stores';
import './stats.scss'; import './stats.scss';
interface IProps { interface IProps {}
appStore: AppStore;
}
interface IState { interface IState {
data: { data: {
@@ -24,8 +19,6 @@ interface IState {
* a page to show discord chat statistics * a page to show discord chat statistics
* currently keeps track of number messages that contain external links * currently keeps track of number messages that contain external links
*/ */
@inject('appStore')
@observer
export class Stats extends Component<IProps, IState> { export class Stats extends Component<IProps, IState> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
@@ -74,15 +67,12 @@ export class Stats extends Component<IProps, IState> {
}, },
}; };
const { claims, hasModPermissions } = this.props.appStore;
return ( return (
<div className="content"> <div className="content">
<div className="card"> <div className="card">
<div className="card__header">Posts containing links</div> <div className="card__header">Posts containing links</div>
<HorizontalBar data={data} /> <HorizontalBar data={data} />
</div> </div>
{claims && <UploadHistory sounds={this.state.sounds} showDiscordPlay={hasModPermissions()} />}
</div> </div>
); );
} }

View File

@@ -0,0 +1,81 @@
import orderBy from 'lodash/orderBy';
import { DateTime } from 'luxon';
import { inject, observer } from 'mobx-react';
import React from 'react';
import { ClipPlayerControl } from '../../components/clip-player-control/clip-player-control';
import { ISound } from '../../model';
import { SoundService } from '../../services';
import { AppStore } from '../../stores';
interface IProps {
appStore: AppStore;
}
interface IState {
sounds: ISound[];
}
@inject('appStore')
@observer
export class UploadHistory extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
sounds: [],
};
}
componentDidMount() {
SoundService.getSounds().then(sounds => {
this.setState({ sounds });
});
}
renderUploadHistory = (sounds: ISound[], showDiscordPlay: boolean) => {
const sortedSounds = orderBy(sounds, 'created_at', 'desc');
return (
<div className="card">
<div className="card__header">Upload History</div>
<table className="table table--ellipsis">
<thead>
<tr>
<th className="hide-small">Date</th>
<th>Sound</th>
<th className="hide-small">Ext</th>
<th>User</th>
<th className="hide-small">Email</th>
</tr>
</thead>
<tbody>
{sortedSounds.map((s: ISound, i) => {
const formattedDate = DateTime.fromISO(s.created_at).toLocaleString();
return (
<tr key={i}>
<td className="hide-small" title={formattedDate}>
{formattedDate}
</td>
<td title={s.name}>{s.name}</td>
<td className="hide-small" title={s.extension}>
{s.extension}
</td>
<td title={s.user.username}>{s.user.username}</td>
<td className="hide-small" title={s.user.email}>
{s.user.email}
</td>
<td>
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={s} type="sounds"></ClipPlayerControl>
</td>
</tr>
);
})}
</tbody>
</table>
</div>
);
};
public render() {
const { hasModPermissions } = this.props.appStore;
const { sounds } = this.state;
return <div className="content">{this.renderUploadHistory(sounds, hasModPermissions())}</div>;
}
}

View File

@@ -41,7 +41,11 @@ export class AppStore {
this.navbarOpen = !this.navbarOpen; this.navbarOpen = !this.navbarOpen;
}; };
public hasModPermissions = () => { public hasModPermissions = (): boolean => {
return this.claims && this.claims.permissions >= Permissions.Mod; return !!this.claims && this.claims.permissions >= Permissions.Mod;
};
public hasAdminPermissions = (): boolean => {
return !!this.claims && this.claims.permissions >= Permissions.Admin;
}; };
} }

View File

@@ -18,7 +18,7 @@ export const Wrapper = inject('appStore')(
return ( return (
<div> <div>
<Header onButtonClick={appStore.toggleNavbar} /> <Header onButtonClick={appStore.toggleNavbar} />
<Navbar claims={appStore.claims} open={appStore.navbarOpen} onNavClick={onNavClick} /> <Navbar appStore={appStore} onNavClick={onNavClick} />
<div className={'wrapper ' + openClass}>{children}</div> <div className={'wrapper ' + openClass}>{children}</div>
</div> </div>
); );