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

feat: add user admin page - various dependency updates

This commit is contained in:
mg
2022-02-16 23:27:13 -06:00
parent 3484a32284
commit 6b8db59e98
29 changed files with 17038 additions and 841 deletions

View File

@@ -2,7 +2,18 @@ import { Provider } from 'mobx-react';
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import { Admin, Clips, Downloader, NotFound, Oauth, Soundboard, Stats, UploadHistory, VideoArchive } from './pages';
import {
Clips,
Downloader,
NotFound,
Oauth,
Soundboard,
Stats,
UploadHistory,
UserEventLog,
VideoArchive,
} from './pages';
import { Users } from './pages/users';
import './scss/index.scss';
import { rootStoreInstance } from './stores';
import { Wrapper } from './wrapper';
@@ -20,7 +31,8 @@ const App: any = (): any => {
<Route path="/oauth" component={Oauth} />
<Route path="/stats" component={Stats} />
<Route path="/video-archive" component={VideoArchive} />
<Route path="/admin" component={Admin} />
<Route path="/user-event-log" component={UserEventLog} />
<Route path="/users" component={Users} />
<Route component={NotFound} />
</Switch>
</Wrapper>
@@ -29,4 +41,4 @@ const App: any = (): any => {
);
};
ReactDOM.render(<App /> as any, document.getElementById('app'));
ReactDOM.render((<App />) as any, document.getElementById('app'));

View File

@@ -67,8 +67,23 @@ export class Navbar extends React.Component<Props, State> {
);
};
renderAuthLinks = () => {
const { hasAdminPermissions } = this.props.appStore;
if (hasAdminPermissions()) {
return (
<>
{this.renderNavLink('User Event Log', '/user-event-log')}
{this.renderNavLink('Users', '/users')}
</>
);
}
return null;
};
render() {
const { claims, navbarOpen, hasModPermissions, hasAdminPermissions } = this.props.appStore;
const { claims, navbarOpen, hasModPermissions } = this.props.appStore;
const openClass = navbarOpen ? 'navbar--open' : '';
return (
<div className={'navbar ' + openClass}>
@@ -78,7 +93,7 @@ export class Navbar extends React.Component<Props, State> {
{this.renderNavLink('Youtube Downloader', '/downloader')}
{this.renderNavLink('Clips', '/clips')}
{this.renderNavLink('Stats', '/stats')}
{hasAdminPermissions() && this.renderNavLink('Admin', '/admin')}
{this.renderAuthLinks()}
{this.renderLoginButton()}
{claims && claims.email && <div className="navbar__email">{claims.email}</div>}

View File

@@ -13,5 +13,6 @@ export interface IUser {
token: string;
updated_at: string;
username: string;
voice_join_sound: string;
verified: boolean;
}

View File

@@ -1 +0,0 @@
export * from './admin';

View File

@@ -1,4 +1,3 @@
export * from './admin';
export * from './clips/clips';
export * from './downloader/downloader';
export * from './not-found/not-found';
@@ -6,4 +5,5 @@ export * from './oauth/oauth';
export * from './soundboard/soundboard';
export * from './stats/stats';
export * from './upload-history/upload-history';
export * from './user-event-log';
export * from './video-archive/video-archive';

View File

@@ -0,0 +1 @@
export * from './user-event-log';

View File

@@ -8,15 +8,16 @@ interface IState {
userEventLogs: IUserEventLog[];
}
export class Admin extends React.Component<IProps, IState> {
export class UserEventLog extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
userEventLogs: [],
};
}
componentDidMount() {
UserEventLogService.getUserEventLogs().then(userEventLogs => {
UserEventLogService.getUserEventLogs().then((userEventLogs) => {
this.setState({
userEventLogs,
});

View File

@@ -0,0 +1 @@
export * from './users';

View File

@@ -0,0 +1,103 @@
import React from 'react';
import { IUser } from '../../model';
import { UserService } from '../../services/user.service';
interface IState {
users: IUser[];
showSavedMessage: boolean;
}
export class Users extends React.Component<any, IState> {
constructor(props: any) {
super(props);
this.state = {
users: [],
showSavedMessage: false,
};
}
componentDidMount() {
UserService.getUsers().then((users) => {
this.setState({ users });
});
}
onUserChange = (type: 'permissions' | 'voice_join_sound', event: any, index: number) => {
this.setState({ showSavedMessage: false });
let users = [...this.state.users];
const val = type === 'permissions' ? parseInt(event.target.value) : event.target.value;
users[index] = {
...users[index],
[type]: val,
};
this.setState({ users });
};
renderUsers = () => {
return this.state.users.map((u: IUser, i: number) => {
return (
<tr key={i}>
<td>{u.username}</td>
<td>{u.email}</td>
<td>
<input
className="input"
type="number"
min={1}
max={3}
value={u.permissions}
onChange={(e) => this.onUserChange('permissions', e, i)}
/>
</td>
<td>
<input
className="input"
type="text"
value={u.voice_join_sound || ''}
onChange={(e) => this.onUserChange('voice_join_sound', e, i)}
/>
</td>
</tr>
);
});
};
save = (event: any) => {
this.setState({ showSavedMessage: false });
event.preventDefault();
UserService.putUsers(this.state.users).then((users: IUser[]) => {
this.setState({ users, showSavedMessage: true });
});
};
render() {
return (
<form className="content" onSubmit={this.save}>
<div className="card card--wide">
<div className="card__header">Users</div>
<div className="overflow-x-auto">
<table className="table">
<thead>
<tr>
<th>Username</th>
<th>Email</th>
<th>Permissions</th>
<th>Join Sound</th>
</tr>
</thead>
<tbody>{this.renderUsers()}</tbody>
</table>
</div>
<br />
<button className="button button--primary" type="submit">
Save
</button>
{this.state.showSavedMessage && <span style={{ marginLeft: 5 }}>Users updated</span>}
</div>
</form>
);
}
}

View File

@@ -7,6 +7,10 @@
border: 1px solid $gray3;
}
.card--wide {
max-width: 1200px;
}
.card__header {
margin: -10px -10px 10px -10px;
display: flex;

View File

@@ -92,3 +92,7 @@ body {
display: none;
}
}
.overflow-x-auto {
overflow-x: auto;
}

View File

@@ -0,0 +1,14 @@
import { IUser } from '../model';
import { axios } from './axios.service';
export class UserService {
public static async getUsers(): Promise<IUser[]> {
const resp = await axios.get('/api/user');
return resp.data.data;
}
public static async putUsers(users: IUser[]): Promise<IUser[]> {
const resp = await axios.put('/api/user', { users });
return resp.data.data;
}
}

16217
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,7 @@
"mini-css-extract-plugin": "^0.4.2",
"mobx": "^5.15.4",
"mobx-react": "^5.2.5",
"node-sass": "^4.14.1",
"node-sass": "^7.0.1",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"postcss-loader": "^2.1.5",