Compare commits
3 Commits
b5a0d8bda2
...
705b1f5e12
Author | SHA1 | Date |
---|---|---|
Martyn | 705b1f5e12 | |
Martyn | f721c91690 | |
Martyn | f49d3ec9ab |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -25,3 +25,18 @@
|
|||
.App-menu {
|
||||
max-width: 98%;
|
||||
}
|
||||
|
||||
.Footer {
|
||||
max-width: 98%;
|
||||
background-color: #6207a4 !important;
|
||||
}
|
||||
|
||||
.Footer a {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.FooterCell {
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import React from 'react';
|
||||
import logo from './../../logo.svg';
|
||||
import './App.css';
|
||||
import Container from '@material-ui/core/Container';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { Button, Paper } from '@material-ui/core';
|
||||
import { Button, Paper, Container, AppBar, Table, TableBody, TableCell, TableContainer, TableRow } from '@material-ui/core';
|
||||
|
||||
function App() {
|
||||
const client_id = "sau3e70wvs369jw1u25ex8g3cve599"
|
||||
|
@ -44,6 +43,22 @@ function App() {
|
|||
<Typography component="p" gutterBottom>
|
||||
...Coming "Soon"(tm)
|
||||
</Typography>
|
||||
<AppBar position="static" className="Footer">
|
||||
<TableContainer component={Container}>
|
||||
<Table><TableBody>
|
||||
<TableRow className="FooterRow">
|
||||
<TableCell className="FooterCell"><a href="https://discord.gg/sVgZeRt">Discord</a></TableCell>
|
||||
<TableCell className="FooterCell"><a href="https://git.martyn.berlin/martyn/twitchsingstools">Source Code</a></TableCell>
|
||||
<TableCell className="FooterCell"><a href="https://twitch.tv/iMartynOnTwitch">Martyn's Twitch</a></TableCell>
|
||||
</TableRow>
|
||||
<TableRow className="FooterRow">
|
||||
<TableCell className="FooterCell">Announcements, Support, Optional notifications</TableCell>
|
||||
<TableCell className="FooterCell">Geek out at the really hacky source code from an SRE type person</TableCell>
|
||||
<TableCell className="FooterCell">Streaming and singing is my hobby, not my job, so only if you want to...</TableCell>
|
||||
</TableRow>
|
||||
</TableBody></Table>
|
||||
</TableContainer>
|
||||
</AppBar>
|
||||
</Paper>
|
||||
</Container>
|
||||
);
|
||||
|
|
|
@ -26,3 +26,18 @@
|
|||
.App-menu {
|
||||
max-width: 98%;
|
||||
}
|
||||
|
||||
.Footer {
|
||||
max-width: 98%;
|
||||
background-color: #6207a4 !important;
|
||||
}
|
||||
|
||||
.Footer a {
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.FooterCell {
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import Typography from '@material-ui/core/Typography';
|
|||
import TopTenSongs from "../TopTenSongs/TopTenSongs";
|
||||
import TopTenSingers from "../TopTenSingers/TopTenSingers";
|
||||
import DuetData from "../DuetData/DuetData";
|
||||
import CacheDeets from "../CacheDeets/CacheDeets";
|
||||
import BotDeets from "../BotDeets/BotDeets";
|
||||
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from '@material-ui/core';
|
||||
import ProblemContainer from "../ProblemContainer/ProblemContainer";
|
||||
|
||||
|
@ -40,22 +42,68 @@ function a11yProps(index) {
|
|||
};
|
||||
}
|
||||
|
||||
function AppAdmin() {
|
||||
const [page, setPage] = React.useState(0);
|
||||
class AppAdmin extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.setPage = this.setPage.bind(this);
|
||||
this.reloadSongComponent = this.reloadSongComponent.bind(this);
|
||||
this.reloadSingersComponent = this.reloadSingersComponent.bind(this);
|
||||
this.reloadDuetComponent = this.reloadDuetComponent.bind(this);
|
||||
this.state = {
|
||||
page: 0,
|
||||
reloadSongComponent: false,
|
||||
reloadSingersComponent: false,
|
||||
reloadDuetComponent: false,
|
||||
};
|
||||
}
|
||||
|
||||
setPage(pageNum) {
|
||||
let newState = this.state;
|
||||
newState.page = pageNum;
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
reloadSongComponent(components) {
|
||||
let newState = this.state;
|
||||
newState.reloadComponents = components;
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
reloadSingersComponent(components) {
|
||||
let newState = this.state;
|
||||
newState.reloadComponents = components;
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
reloadDuetComponent(components) {
|
||||
let newState = this.state;
|
||||
newState.reloadDuetComponent = components;
|
||||
console.log("I'm trying!")
|
||||
this.setState(newState);
|
||||
}
|
||||
|
||||
render() {
|
||||
const page = this.state.page
|
||||
if (
|
||||
(window.location.href.split("/").length < 6) ||
|
||||
(window.location.href.split("/")[3].search(/^admin/) < 0) ||
|
||||
(window.location.href.split("/")[5].length !== 48)
|
||||
) {
|
||||
if (window.location.href.split("/")[2] !== "192.168.1.111:3000") {
|
||||
return (
|
||||
<ProblemContainer />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const channelName = window.location.href.split("/")[4]
|
||||
const adminToken = window.location.href.split("/")[5]
|
||||
const csvURL = "/csv/"+ channelName + "/" + adminToken
|
||||
const tsvURL = "/tsv/"+ channelName + "/" + adminToken
|
||||
const setPage = this.setPage
|
||||
const reloadDuetComponent = this.state.reloadDuetComponent
|
||||
const reloadSongComponent = this.state.reloadSongComponent
|
||||
const reloadSingersComponent = this.state.reloadSingersComponent
|
||||
|
||||
function handleChange(event, newValue) {
|
||||
setPage(newValue);
|
||||
|
@ -74,16 +122,21 @@ function AppAdmin() {
|
|||
<Tab label="Top Singers" {...a11yProps(1)}/>
|
||||
<Tab label="Data" {...a11yProps(2)}/>
|
||||
<Tab label="Export" {...a11yProps(3)}/>
|
||||
<Tab label="Cache Details" {...a11yProps(4)}/>
|
||||
<Tab label="Chatbot" {...a11yProps(4)}/>
|
||||
</Tabs>
|
||||
</AppBar>
|
||||
<TabPanel value={page} index={0}>
|
||||
<TopTenSongs />
|
||||
<TopTenSongs reloadSongComponent={reloadSongComponent}
|
||||
onReloadedChange={this.reloadSongComponent}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={page} index={1}>
|
||||
<TopTenSingers />
|
||||
<TopTenSingers reloadSingersComponent={reloadSingersComponent}
|
||||
onReloadedChange={this.reloadSingersComponent}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={page} index={2}>
|
||||
<DuetData />
|
||||
<DuetData reloadDuetComponent={reloadDuetComponent}
|
||||
onReloadedChange={this.reloadDuetComponent}/>
|
||||
</TabPanel>
|
||||
<TabPanel value={page} index={3}>
|
||||
<Typography variant="h5" component="h2" gutterBottom>
|
||||
|
@ -113,9 +166,35 @@ function AppAdmin() {
|
|||
<Typography component="p" gutterBottom>LibreOffice calc kinda just works...just sayin' ;-)</Typography>
|
||||
|
||||
</TabPanel>
|
||||
<TabPanel value={page} index={4}>
|
||||
<CacheDeets
|
||||
onReloadSongsChange={this.reloadSongComponent}
|
||||
onReloadSingersChange={this.reloadSingersComponent}
|
||||
onReloadDuetChange={this.reloadDuetComponent}
|
||||
/>
|
||||
</TabPanel>
|
||||
<TabPanel value={page} index={5}>
|
||||
<BotDeets />
|
||||
</TabPanel>
|
||||
<AppBar position="static" className="Footer">
|
||||
<TableContainer component={Container}>
|
||||
<Table><TableBody>
|
||||
<TableRow className="FooterRow">
|
||||
<TableCell className="FooterCell"><a href="https://discord.gg/sVgZeRt">Discord</a></TableCell>
|
||||
<TableCell className="FooterCell"><a href="https://git.martyn.berlin/martyn/twitchsingstools">Source Code</a></TableCell>
|
||||
<TableCell className="FooterCell"><a href="https://twitch.tv/iMartynOnTwitch">Martyn's Twitch</a></TableCell>
|
||||
</TableRow>
|
||||
<TableRow className="FooterRow">
|
||||
<TableCell className="FooterCell">Announcements, Support, Optional notifications</TableCell>
|
||||
<TableCell className="FooterCell">Geek out at the really hacky source code from an SRE type person</TableCell>
|
||||
<TableCell className="FooterCell">Streaming and singing is my hobby, not my job, so only if you want to...</TableCell>
|
||||
</TableRow>
|
||||
</TableBody></Table>
|
||||
</TableContainer>
|
||||
</AppBar>
|
||||
</Paper>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
export default AppAdmin;
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { Container, Typography, Button } from '@material-ui/core';
|
||||
|
||||
const channelName = window.location.href.split("/")[4]
|
||||
const adminToken = window.location.href.split("/")[5]
|
||||
const dataURL = "/botdeets/"+ channelName + "/" + adminToken
|
||||
|
||||
function BotDeets() {
|
||||
|
||||
const [botState, setBotState] = React.useState({loading: true, botData: []})
|
||||
useEffect(() => {
|
||||
// We should only fetch once!
|
||||
if (botState.loading) {
|
||||
fetch(dataURL).then((res) => res.json().then((data)=>{
|
||||
setBotState({botData: data, loading: false })
|
||||
}));
|
||||
}
|
||||
}, [setBotState, botState.loading]);
|
||||
|
||||
if (botState.loading) {
|
||||
return <p>Sorry, still loading...</p>
|
||||
}
|
||||
|
||||
let dd = botState.botData
|
||||
if (dd.hasleft) {
|
||||
return (
|
||||
<Container>
|
||||
<Typography variant="h5" component="h2" gutterBottom>
|
||||
The chatbot is currently <b>not</b> in your channel. To change the settings, invite it to your channel using the button below :
|
||||
</Typography>
|
||||
<Typography variant="p">
|
||||
You really don't wanna do that, because it's not ready yet.
|
||||
</Typography>
|
||||
<Typography variant="p">
|
||||
<Button variant="contained" color="primary">Join my channel!</Button>
|
||||
</Typography>
|
||||
</Container>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Container>
|
||||
<Typography variant="h5" component="h2" gutterBottom>
|
||||
Coming soon! Bot control panel!
|
||||
</Typography>
|
||||
<Typography component="tt" gutterBottom>
|
||||
{dd}
|
||||
</Typography>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default BotDeets;
|
|
@ -0,0 +1,81 @@
|
|||
import React from 'react';
|
||||
import { Container, Typography, Button } from '@material-ui/core';
|
||||
|
||||
const channelName = window.location.href.split("/")[4]
|
||||
const adminToken = window.location.href.split("/")[5]
|
||||
const dataURL = "/cachedeets/"+ channelName + "/" + adminToken
|
||||
const forceURL = "/force/"+ channelName + "/" + adminToken
|
||||
|
||||
class CacheDeets extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
cacheData: [],
|
||||
loading: true
|
||||
};
|
||||
this.setCacheData = this.setCacheData.bind(this);
|
||||
this.setLoading = this.setLoading.bind(this);
|
||||
}
|
||||
|
||||
setCacheData(data) {
|
||||
let newState = this.state
|
||||
newState.cacheData = data
|
||||
this.setState(newState)
|
||||
}
|
||||
|
||||
setLoading(data) {
|
||||
let newState = this.state
|
||||
newState.loading = data
|
||||
this.setState(newState)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// We should only fetch once!
|
||||
if (this.state.loading) {
|
||||
let actualURL = dataURL
|
||||
if (window.location.href.split("/")[2] === "192.168.1.111:3000") {
|
||||
//Frontend dev mode only
|
||||
actualURL = "/sampleData/cache.json"
|
||||
}
|
||||
fetch(actualURL).then((res) => res.json().then((data)=>{
|
||||
this.setLoading(false)
|
||||
this.setCacheData(data)
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const loading = this.state.loading
|
||||
const setLoading = this.setLoading
|
||||
const cacheData = this.state.cacheData
|
||||
|
||||
function handleClick(e) {
|
||||
setLoading(true)
|
||||
fetch(forceURL).then((data)=>{
|
||||
setLoading(false)
|
||||
window.location.reload()
|
||||
})
|
||||
console.log('The link was clicked.');
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return <p>Sorry, still loading...</p>
|
||||
}
|
||||
|
||||
let dd = cacheData
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Typography variant="h5" component="h2" gutterBottom>
|
||||
Server has cached data from <b>{dd.SongCount} published</b> performances
|
||||
</Typography>
|
||||
<Typography component="p" gutterBottom>
|
||||
Cache data is from about {dd.AgeStr} - it automatically gets updated if it's older than an hour. If you're convinced using Martyn's bandwidth to refresh the cache earlier than that is worth it, here's the button below :
|
||||
</Typography>
|
||||
<Button variant="contained" color="primary" onClick={handleClick}>Force refresh cache</Button>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default CacheDeets;
|
Loading…
Reference in New Issue