diff --git a/client/app/app.tsx b/client/app/app.tsx index a4a755e..657f933 100644 --- a/client/app/app.tsx +++ b/client/app/app.tsx @@ -1,9 +1,9 @@ -import './scss/index.scss'; import { Provider } from 'mobx-react'; import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter, Route, Switch } from 'react-router-dom'; -import { Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages'; +import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, VideoArchive } from './pages'; +import './scss/index.scss'; import { rootStoreInstance } from './stores'; import { Wrapper } from './wrapper'; @@ -19,6 +19,7 @@ const App: any = (): any => { + diff --git a/client/app/components/index.ts b/client/app/components/index.ts index 732c2bb..82ef969 100644 --- a/client/app/components/index.ts +++ b/client/app/components/index.ts @@ -2,4 +2,5 @@ export * from './embedded-youtube/embedded-youtube'; export * from './header/header'; export * from './navbar/navbar'; export * from './sound-list/sound-list'; +export * from './upload-history/upload-history'; export * from './uploader/uploader'; diff --git a/client/app/components/navbar/navbar.tsx b/client/app/components/navbar/navbar.tsx index b27a7ab..745baeb 100644 --- a/client/app/components/navbar/navbar.tsx +++ b/client/app/components/navbar/navbar.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { NavLink } from 'react-router-dom'; -import { IClaims } from '../../model'; +import { IClaims, Permissions } from '../../model'; import { OauthService, StorageService } from '../../services'; import './navbar.scss'; @@ -78,6 +78,10 @@ export class Navbar extends React.Component { {this.renderNavLink('Youtube Downloader', '/downloader')} {this.renderNavLink('Clips', '/clips')} {this.renderNavLink('Stats', '/stats')} + {claims && + claims.permissions && + claims.permissions === Permissions.Admin && + this.renderNavLink('Admin', '/admin')} {this.renderLoginButton()} {claims && claims.email &&
{claims.email}
} diff --git a/client/app/components/upload-history/upload-history.tsx b/client/app/components/upload-history/upload-history.tsx new file mode 100644 index 0000000..079d503 --- /dev/null +++ b/client/app/components/upload-history/upload-history.tsx @@ -0,0 +1,46 @@ +import * as _ from 'lodash'; +import { DateTime } from 'luxon'; +import React from 'react'; +import { ISound } from '../../model'; + +interface IProps { + sounds: ISound[]; +} + +export const UploadHistory = ({ sounds }: IProps) => { + const sortedSounds = _.orderBy(sounds, 'created_at', 'desc'); + return ( +
+
Upload History
+ + + + + + + + + + + + {sortedSounds.map((s: ISound, i) => { + const formattedDate = DateTime.fromISO(s.created_at).toLocaleString(); + return ( + + + + + + + + ); + })} + +
DateSoundExtUsernameEmail
{formattedDate}{s.name} + {s.extension} + {s.user.username} + {s.user.email} +
+
+ ); +}; diff --git a/client/app/model/index.ts b/client/app/model/index.ts index 8a13ade..13ff3d9 100644 --- a/client/app/model/index.ts +++ b/client/app/model/index.ts @@ -1,3 +1,5 @@ export * from './claims'; export * from './permissions'; +export * from './sound'; +export * from './user'; export * from './video-archive'; diff --git a/client/app/model/sound.ts b/client/app/model/sound.ts new file mode 100644 index 0000000..8578961 --- /dev/null +++ b/client/app/model/sound.ts @@ -0,0 +1,12 @@ +import { IUser } from './user'; + +export interface ISound { + created_at: string; + deleted_at?: string; + extension: string; + id: number; + name: string; + updated_at: string; + user: IUser; + user_id: string; +} diff --git a/client/app/model/user.ts b/client/app/model/user.ts new file mode 100644 index 0000000..bfe3b86 --- /dev/null +++ b/client/app/model/user.ts @@ -0,0 +1,17 @@ +import { Permissions } from './permissions'; + +export interface IUser { + avatar: string; + bot: boolean; + created_at: string; + deleted_at?: string; + discriminator: string; + email: string; + id: string; + mfa_enabled: boolean; + permissions: Permissions; + token: string; + updated_at: string; + username: string; + verified: boolean; +} diff --git a/client/app/pages/admin/admin.tsx b/client/app/pages/admin/admin.tsx new file mode 100644 index 0000000..4021d53 --- /dev/null +++ b/client/app/pages/admin/admin.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +interface IProps {} + +interface IState {} + +export class Admin extends React.Component { + render() { + return
TODO:
; + } +} diff --git a/client/app/pages/admin/index.ts b/client/app/pages/admin/index.ts new file mode 100644 index 0000000..9297e48 --- /dev/null +++ b/client/app/pages/admin/index.ts @@ -0,0 +1 @@ +export * from './admin'; diff --git a/client/app/pages/index.ts b/client/app/pages/index.ts index 055d80e..ddc5e7b 100644 --- a/client/app/pages/index.ts +++ b/client/app/pages/index.ts @@ -1,3 +1,4 @@ +export * from './admin'; export * from './clips/clips'; export * from './downloader/downloader'; export * from './not-found/not-found'; diff --git a/client/app/pages/stats/stats.tsx b/client/app/pages/stats/stats.tsx index 88d5336..e04d1c5 100644 --- a/client/app/pages/stats/stats.tsx +++ b/client/app/pages/stats/stats.tsx @@ -1,30 +1,45 @@ +import { chain, map } from 'lodash'; +import { inject, observer } from 'mobx-react'; import React, { Component } from 'react'; import { HorizontalBar } from 'react-chartjs-2'; -import { chain, map } from 'lodash'; -import { axios } from '../../services'; +import { UploadHistory } from '../../components'; +import { ISound } from '../../model'; +import { axios, SoundService } from '../../services'; +import { AppStore } from '../../stores'; import './stats.scss'; +interface IProps { + appStore: AppStore; +} + interface IState { data: { username: string; count: number; }[]; + sounds: ISound[]; } /** * a page to show discord chat statistics * currently keeps track of number messages that contain external links */ -export class Stats extends Component { +@inject('appStore') +@observer +export class Stats extends Component { constructor(props: any) { super(props); this.state = { data: [], + sounds: [], }; } componentDidMount() { this.getdata(); + SoundService.getSounds().then(sounds => { + this.setState({ sounds }); + }); } async getdata() { @@ -59,12 +74,15 @@ export class Stats extends Component { }, }; + const { claims } = this.props.appStore; + return (
-
+
Posts containing links
+ {claims && }
); } diff --git a/client/app/scss/index.scss b/client/app/scss/index.scss index 85dbf16..cc31ce7 100644 --- a/client/app/scss/index.scss +++ b/client/app/scss/index.scss @@ -12,3 +12,4 @@ @import './input.scss'; @import './grid.scss'; @import './nprogress.scss'; +@import './table.scss'; diff --git a/client/app/scss/style.scss b/client/app/scss/style.scss index ac9b3f0..761d232 100644 --- a/client/app/scss/style.scss +++ b/client/app/scss/style.scss @@ -71,3 +71,9 @@ body { white-space: nowrap; text-overflow: ellipsis; } + +.hide-tiny { + @include tinyScreen { + display: none; + } +} diff --git a/client/app/scss/table.scss b/client/app/scss/table.scss new file mode 100644 index 0000000..db7c044 --- /dev/null +++ b/client/app/scss/table.scss @@ -0,0 +1,14 @@ +.table { + width: 100%; + + thead { + text-align: left; + } + + td, + th { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } +} diff --git a/client/app/services/sound.service.ts b/client/app/services/sound.service.ts index 2cc3ded..5c9c2e3 100644 --- a/client/app/services/sound.service.ts +++ b/client/app/services/sound.service.ts @@ -1,10 +1,17 @@ import { SoundType } from '../components/sound-list/sound-list'; +import { ISound } from '../model'; import { axios } from './axios.service'; const playSound = (sound: SoundType): Promise => { return axios.post('/api/sound/play', { name: sound.name }); }; +const getSounds = async (): Promise => { + const res = await axios.get('/api/sound'); + return res.data.data; +}; + export const SoundService = { + getSounds, playSound, };