mirror of
https://github.com/mgerb/go-discord-bot
synced 2026-01-10 09:02:49 +00:00
feat: add favorites - update dependencies
This commit is contained in:
@@ -1,19 +1,18 @@
|
||||
import React from 'react';
|
||||
import { SoundService } from '../../services';
|
||||
import { SoundListType, SoundType } from '../../model';
|
||||
|
||||
interface IProps {
|
||||
sound: SoundType;
|
||||
type: 'sounds' | 'clips';
|
||||
showDiscordPlay?: boolean;
|
||||
type: SoundListType;
|
||||
hasModPermissions: boolean;
|
||||
showFavorite?: boolean;
|
||||
onFavorite?: () => void;
|
||||
onPlayBrowser: (sound: SoundType) => void;
|
||||
onPlayDiscord: (sound: SoundType) => void;
|
||||
}
|
||||
|
||||
interface IState {}
|
||||
|
||||
export interface SoundType {
|
||||
extension: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export class ClipPlayerControl extends React.Component<IProps, IState> {
|
||||
checkExtension(extension: string) {
|
||||
switch (extension) {
|
||||
@@ -28,22 +27,21 @@ export class ClipPlayerControl extends React.Component<IProps, IState> {
|
||||
}
|
||||
}
|
||||
|
||||
handlePlayAudioInBrowser(sound: SoundType, type: string) {
|
||||
const url = `/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension;
|
||||
const audio = new Audio(url);
|
||||
audio.play();
|
||||
}
|
||||
|
||||
onPlayDiscord = (sound: SoundType) => {
|
||||
SoundService.playSound(sound);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { sound, showDiscordPlay, type } = this.props;
|
||||
const { onPlayBrowser, onPlayDiscord, sound, hasModPermissions, showFavorite, type } = this.props;
|
||||
|
||||
return (
|
||||
this.checkExtension(sound.extension) && (
|
||||
<div className="flex flex--center">
|
||||
{showFavorite && hasModPermissions && (
|
||||
<i
|
||||
title="Favorite"
|
||||
className={'fa link fa-lg ' + (type === 'favorites' ? 'fa-trash' : 'fa-heart color__red')}
|
||||
aria-hidden="true"
|
||||
style={{ paddingRight: '5px' }}
|
||||
onClick={() => !this.props.onFavorite || this.props.onFavorite()}
|
||||
/>
|
||||
)}
|
||||
<a
|
||||
href={`/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension}
|
||||
download
|
||||
@@ -56,15 +54,15 @@ export class ClipPlayerControl extends React.Component<IProps, IState> {
|
||||
className="fa fa-play link"
|
||||
aria-hidden="true"
|
||||
style={{ paddingLeft: '15px' }}
|
||||
onClick={() => this.handlePlayAudioInBrowser(sound, type)}
|
||||
onClick={() => onPlayBrowser(sound)}
|
||||
/>
|
||||
{showDiscordPlay && (
|
||||
{hasModPermissions && (
|
||||
<i
|
||||
title="Play in discord"
|
||||
className="fa fa-play-circle link fa-lg"
|
||||
aria-hidden="true"
|
||||
style={{ paddingLeft: '10px' }}
|
||||
onClick={() => this.onPlayDiscord(sound)}
|
||||
onClick={() => onPlayDiscord(sound)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,25 +1,23 @@
|
||||
import React from 'react';
|
||||
import { SoundListType, SoundType } from '../../model';
|
||||
import { SoundService } from '../../services';
|
||||
import { ClipPlayerControl } from '../clip-player-control/clip-player-control';
|
||||
import './sound-list.scss';
|
||||
|
||||
interface Props {
|
||||
soundList: SoundType[];
|
||||
type: 'sounds' | 'clips';
|
||||
type: SoundListType;
|
||||
title: string;
|
||||
onPlayDiscord?: (sound: SoundType) => void;
|
||||
showDiscordPlay?: boolean;
|
||||
hasModPermissions: boolean;
|
||||
onFavorite?: (sound: SoundType) => void;
|
||||
deleteFavorite?: (sound: SoundType) => void;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showAudioControls: boolean[];
|
||||
}
|
||||
|
||||
export interface SoundType {
|
||||
extension: string;
|
||||
name: string;
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
export class SoundList extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
@@ -41,14 +39,8 @@ export class SoundList extends React.Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
handlePlayAudioInBrowser(sound: SoundType, type: string) {
|
||||
const url = `/public/${type.toLowerCase()}/` + sound.name + '.' + sound.extension;
|
||||
const audio = new Audio(url);
|
||||
audio.play();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showDiscordPlay, soundList, title, type } = this.props;
|
||||
const { hasModPermissions, onFavorite, soundList, title, type } = this.props;
|
||||
|
||||
return (
|
||||
<div className="card">
|
||||
@@ -66,10 +58,18 @@ export class SoundList extends React.Component<Props, State> {
|
||||
return (
|
||||
<div key={index} className="sound-list__item">
|
||||
<div className="text-wrap">
|
||||
{(type === 'sounds' && sound.prefix ? sound.prefix : '') + sound.name}
|
||||
{((type === 'sounds' || type === 'favorites') && sound.prefix ? sound.prefix : '') + sound.name}
|
||||
</div>
|
||||
|
||||
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={sound} type={type} />
|
||||
<ClipPlayerControl
|
||||
showFavorite={type !== 'clips'}
|
||||
onFavorite={() => !onFavorite || onFavorite(sound)}
|
||||
hasModPermissions={hasModPermissions}
|
||||
sound={sound}
|
||||
type={type}
|
||||
onPlayBrowser={(sound) => SoundService.playAudioInBrowser(sound, type)}
|
||||
onPlayDiscord={SoundService.playSound}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { IUser } from './user';
|
||||
|
||||
export type SoundListType = 'sounds' | 'clips' | 'favorites';
|
||||
|
||||
export interface SoundType {
|
||||
extension: string;
|
||||
name: string;
|
||||
prefix?: string;
|
||||
}
|
||||
|
||||
// sound from database
|
||||
export interface ISound {
|
||||
created_at: string;
|
||||
deleted_at?: string;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { SoundList, SoundType } from '../../components';
|
||||
import { SoundList } from '../../components';
|
||||
import { SoundType } from '../../model';
|
||||
import { axios } from '../../services';
|
||||
|
||||
interface Props {}
|
||||
@@ -23,7 +24,7 @@ export class Clips extends React.Component<Props, State> {
|
||||
private getClipList() {
|
||||
axios
|
||||
.get('/api/cliplist')
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
this.setState({
|
||||
clipList: response.data,
|
||||
});
|
||||
@@ -37,7 +38,8 @@ export class Clips extends React.Component<Props, State> {
|
||||
return (
|
||||
<div className="content">
|
||||
<div className="column">
|
||||
<SoundList soundList={this.state.clipList} type="clips" title="Clips" />
|
||||
{/* no need for permissions on this component - set false */}
|
||||
<SoundList soundList={this.state.clipList} type="clips" title="Clips" hasModPermissions={false} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@ export class Oauth extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const params = queryString.parse(this.props.location.search);
|
||||
const params: any = queryString.parse(this.props.location.search);
|
||||
|
||||
if (params['code']) {
|
||||
// do stuff here
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { inject, observer } from 'mobx-react';
|
||||
import React from 'react';
|
||||
import { SoundList, SoundType, Uploader } from '../../components';
|
||||
import { SoundList, Uploader } from '../../components';
|
||||
import { SoundType } from '../../model';
|
||||
import { axios, SoundService } from '../../services';
|
||||
import { AppStore } from '../../stores';
|
||||
import './soundboard.scss';
|
||||
@@ -39,7 +40,7 @@ export class Soundboard extends React.Component<Props, State> {
|
||||
if (!this.soundListCache) {
|
||||
axios
|
||||
.get('/api/soundlist')
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
this.soundListCache = response.data;
|
||||
this.setState({
|
||||
soundList: response.data,
|
||||
@@ -64,18 +65,42 @@ export class Soundboard extends React.Component<Props, State> {
|
||||
SoundService.playSound(sound);
|
||||
};
|
||||
|
||||
onFavorite = (sound: SoundType) => {
|
||||
this.props.appStore?.addFavorite(sound);
|
||||
};
|
||||
|
||||
onDeleteFavorite = (sound: SoundType) => {
|
||||
this.props.appStore?.removeFavorite(sound);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { soundList } = this.state;
|
||||
const { appStore } = this.props;
|
||||
|
||||
if (!this.props.appStore) {
|
||||
return null;
|
||||
}
|
||||
const { hasModPermissions, getFavorites } = this.props.appStore;
|
||||
|
||||
return (
|
||||
<div className="content">
|
||||
<Uploader onComplete={this.onUploadComplete} />
|
||||
{((hasModPermissions && getFavorites().length) || 0 > 0) && (
|
||||
<SoundList
|
||||
soundList={getFavorites()}
|
||||
title="Favorites"
|
||||
type="favorites"
|
||||
onPlayDiscord={this.onPlayDiscord}
|
||||
hasModPermissions={hasModPermissions()}
|
||||
onFavorite={this.onDeleteFavorite}
|
||||
/>
|
||||
)}
|
||||
<SoundList
|
||||
soundList={soundList}
|
||||
title="Sounds"
|
||||
type="sounds"
|
||||
onPlayDiscord={this.onPlayDiscord}
|
||||
showDiscordPlay={appStore!.hasModPermissions()}
|
||||
hasModPermissions={hasModPermissions()}
|
||||
onFavorite={this.onFavorite}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -26,12 +26,12 @@ export class UploadHistory extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
SoundService.getSounds().then(sounds => {
|
||||
SoundService.getSounds().then((sounds) => {
|
||||
this.setState({ sounds });
|
||||
});
|
||||
}
|
||||
|
||||
renderUploadHistory = (sounds: ISound[], showDiscordPlay: boolean) => {
|
||||
renderUploadHistory = (sounds: ISound[], hasModPermissions: boolean) => {
|
||||
const sortedSounds = orderBy(sounds, 'created_at', 'desc');
|
||||
return (
|
||||
<div className="card">
|
||||
@@ -63,7 +63,13 @@ export class UploadHistory extends React.Component<IProps, IState> {
|
||||
{s.user.email}
|
||||
</td>
|
||||
<td>
|
||||
<ClipPlayerControl showDiscordPlay={showDiscordPlay} sound={s} type="sounds"></ClipPlayerControl>
|
||||
<ClipPlayerControl
|
||||
onPlayBrowser={(sound) => SoundService.playAudioInBrowser(sound, 'sounds')}
|
||||
onPlayDiscord={SoundService.playSound}
|
||||
hasModPermissions={hasModPermissions}
|
||||
sound={s}
|
||||
type="sounds"
|
||||
></ClipPlayerControl>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { SoundType } from '../components/sound-list/sound-list';
|
||||
import { ISound } from '../model';
|
||||
import { ISound, SoundListType, SoundType } from '../model';
|
||||
import { axios } from './axios.service';
|
||||
|
||||
const playSound = (sound: SoundType): Promise<any> => {
|
||||
@@ -11,7 +10,15 @@ const getSounds = async (): Promise<ISound[]> => {
|
||||
return res.data.data;
|
||||
};
|
||||
|
||||
export const playAudioInBrowser = (sound: SoundType, type: SoundListType) => {
|
||||
const t = type === 'favorites' ? 'sounds' : type;
|
||||
const url = `/public/${t.toLowerCase()}/` + sound.name + '.' + sound.extension;
|
||||
const audio = new Audio(url);
|
||||
audio.play();
|
||||
};
|
||||
|
||||
export const SoundService = {
|
||||
getSounds,
|
||||
playSound,
|
||||
playAudioInBrowser,
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { SoundType } from '../model';
|
||||
|
||||
const clear = () => {
|
||||
localStorage.clear();
|
||||
};
|
||||
@@ -10,8 +12,19 @@ const getJWT = (): string | null => {
|
||||
return localStorage.getItem('jwt');
|
||||
};
|
||||
|
||||
const getFavorites = (): SoundType[] => {
|
||||
const f = localStorage.getItem('favorites');
|
||||
return f ? JSON.parse(f) : [];
|
||||
};
|
||||
|
||||
const setFavorites = (f: SoundType[]): void => {
|
||||
localStorage.setItem('favorites', JSON.stringify(f));
|
||||
};
|
||||
|
||||
export const StorageService = {
|
||||
clear,
|
||||
getJWT,
|
||||
setJWT,
|
||||
getFavorites,
|
||||
setFavorites,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import jwt_decode from 'jwt-decode';
|
||||
import { filter, uniqBy } from 'lodash';
|
||||
import { action, observable } from 'mobx';
|
||||
import { IClaims, Permissions } from '../model';
|
||||
import { IClaims, Permissions, SoundType } from '../model';
|
||||
import { axios, StorageService } from '../services';
|
||||
import { Util } from '../util';
|
||||
|
||||
@@ -11,9 +12,12 @@ export class AppStore {
|
||||
public jwt?: string;
|
||||
@observable
|
||||
public claims?: IClaims;
|
||||
@observable
|
||||
private favorites: SoundType[] = [];
|
||||
|
||||
constructor() {
|
||||
const jwt = StorageService.getJWT();
|
||||
this.favorites = StorageService.getFavorites();
|
||||
this.setJWT(jwt as string);
|
||||
this.initNavbar();
|
||||
}
|
||||
@@ -24,7 +28,7 @@ export class AppStore {
|
||||
}
|
||||
}
|
||||
|
||||
private setJWT(jwt?: string) {
|
||||
private setJWT = (jwt?: string) => {
|
||||
if (!jwt) {
|
||||
return;
|
||||
}
|
||||
@@ -34,7 +38,21 @@ export class AppStore {
|
||||
if (claims) {
|
||||
this.claims = claims as IClaims;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public getFavorites = (): SoundType[] => {
|
||||
return this.favorites;
|
||||
};
|
||||
|
||||
public addFavorite = (f: SoundType): void => {
|
||||
this.favorites = uniqBy([...this.favorites, f], 'name');
|
||||
StorageService.setFavorites(this.favorites);
|
||||
};
|
||||
|
||||
public removeFavorite = (f: SoundType): void => {
|
||||
this.favorites = filter(this.favorites, (fa) => fa.name !== f.name);
|
||||
StorageService.setFavorites(this.favorites);
|
||||
};
|
||||
|
||||
@action
|
||||
public toggleNavbar = () => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import './wrapper.scss';
|
||||
|
||||
export const Wrapper = inject('appStore')(
|
||||
withRouter(
|
||||
observer(({ appStore, children }) => {
|
||||
observer(({ appStore, children }: any) => {
|
||||
const openClass = appStore.navbarOpen ? 'wrapper--open' : '';
|
||||
const onNavClick = () => {
|
||||
if (Util.isMobileScreen()) {
|
||||
|
||||
Reference in New Issue
Block a user