mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-01 21:52:19 +00:00
0.0.8
- Added Admin/Site config page in frontend for admin users - Added API POST/GET /config endpoint
This commit is contained in:
parent
8be4a190a6
commit
af02bd99cc
17 changed files with 826 additions and 24 deletions
|
@ -25,6 +25,7 @@ export const PostLogin = (formValues) => {
|
|||
uuid: expandedUser.sub,
|
||||
exp: expandedUser.exp,
|
||||
username: expandedUser.username,
|
||||
admin: expandedUser.admin
|
||||
}
|
||||
|
||||
toast.success('Successfully logged in.');
|
||||
|
@ -72,3 +73,31 @@ export const getRecentScrobbles = (id) => {
|
|||
return data.data;
|
||||
});
|
||||
};
|
||||
|
||||
export const getConfigs = () => {
|
||||
return axios.get(process.env.REACT_APP_API_URL + "config", { headers: getHeaders() })
|
||||
.then((data) => {
|
||||
return data.data;
|
||||
});
|
||||
};
|
||||
|
||||
export const postConfigs = (values, toggle) => {
|
||||
if (toggle) {
|
||||
values.REGISTRATION_ENABLED = "1"
|
||||
} else {
|
||||
values.REGISTRATION_ENABLED = "0"
|
||||
}
|
||||
|
||||
return axios.post(process.env.REACT_APP_API_URL + "config", values, { headers: getHeaders() })
|
||||
.then((data) => {
|
||||
if (data.data && data.data.message) {
|
||||
toast.success(data.data.message);
|
||||
} else if (data.data && data.data.error) {
|
||||
toast.error(data.data.error);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error('Error updating values');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import './App.css';
|
||||
import { Route, Switch, withRouter } from 'react-router-dom';
|
||||
|
||||
import Home from './Pages/Home';
|
||||
import About from './Pages/About';
|
||||
|
||||
import Dashboard from './Pages/Dashboard';
|
||||
import Profile from './Pages/Profile';
|
||||
import Admin from './Pages/Admin';
|
||||
import Login from './Pages/Login';
|
||||
import Settings from './Pages/Settings';
|
||||
import Register from './Pages/Register';
|
||||
|
||||
import Navigation from './Components/Navigation';
|
||||
|
||||
import { Route, Switch, withRouter } from 'react-router-dom';
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import './App.css';
|
||||
|
||||
const App = () => {
|
||||
let boolTrue = true
|
||||
|
@ -24,7 +25,8 @@ const App = () => {
|
|||
|
||||
<Route path="/dashboard" component={Dashboard} />
|
||||
<Route path="/profile" component={Profile} />
|
||||
<Route path="/settings" component={Settings} />
|
||||
|
||||
<Route path="/admin" component={Admin} />
|
||||
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/register" component={Register} />
|
||||
|
|
|
@ -33,10 +33,14 @@ const Navigation = () => {
|
|||
let { user, Logout } = useContext(AuthContext);
|
||||
let [collapsed, setCollapsed] = useState(true);
|
||||
|
||||
const toggleCollapsed = () => {
|
||||
setCollapsed(!collapsed)
|
||||
}
|
||||
|
||||
const renderMobileNav = () => {
|
||||
return <Navbar color="dark" dark fixed="top">
|
||||
<NavbarBrand className="mr-auto"><img src={logo} className="nav-logo" alt="logo" /> GoScrobble</NavbarBrand>
|
||||
<NavbarToggler onClick={setCollapsed(!collapsed)} className="mr-2" />
|
||||
<NavbarToggler onClick={toggleCollapsed} className="mr-2" />
|
||||
<Collapse isOpen={!collapsed} navbar>
|
||||
{user ?
|
||||
<Nav className="navLinkLoginMobile" navbar>
|
||||
|
@ -55,6 +59,12 @@ const Navigation = () => {
|
|||
style={active === "profile" ? activeStyle : {}}
|
||||
className="navLinkMobile"
|
||||
>Profile</Link>
|
||||
{user.admin &&
|
||||
<Link
|
||||
to="/admin"
|
||||
style={active === "admin" ? activeStyle : {}}
|
||||
className="navLink"
|
||||
>Admin</Link>}
|
||||
<Link to="/" className="navLink" onClick={Logout}>Logout</Link>
|
||||
</Nav>
|
||||
: <Nav className="navLinkLoginMobile" navbar>
|
||||
|
@ -126,7 +136,13 @@ const Navigation = () => {
|
|||
style={active === "profile" ? activeStyle : {}}
|
||||
className="navLink"
|
||||
>{user.username}</Link>
|
||||
<Link to="/" className="navLink" onClick={Logout}>Logout</Link>
|
||||
{user.admin &&
|
||||
<Link
|
||||
to="/admin"
|
||||
style={active === "admin" ? activeStyle : {}}
|
||||
className="navLink"
|
||||
>Admin</Link>}
|
||||
<Link to="/admin" className="navLink" onClick={Logout}>Logout</Link>
|
||||
</div>
|
||||
:
|
||||
<div className="navLinkLogin">
|
||||
|
|
15
web/src/Pages/Admin.css
Normal file
15
web/src/Pages/Admin.css
Normal file
|
@ -0,0 +1,15 @@
|
|||
.adminBody {
|
||||
padding: 20px 5px 5px 5px;
|
||||
font-size: 16pt;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.adminFields {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.admin {
|
||||
height: 50px;
|
||||
width: 100%;
|
||||
margin-top:-5px;
|
||||
}
|
107
web/src/Pages/Admin.js
Normal file
107
web/src/Pages/Admin.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
import React, { useContext, useState, useEffect } from 'react';
|
||||
import '../App.css';
|
||||
import './Login.css';
|
||||
import { Button } from 'reactstrap';
|
||||
import { Formik, Form, Field } from 'formik';
|
||||
import ScaleLoader from 'react-spinners/ScaleLoader';
|
||||
import AuthContext from '../Contexts/AuthContext';
|
||||
import { Switch } from 'formik-material-ui';
|
||||
import { getConfigs, postConfigs } from '../Api/index'
|
||||
|
||||
const Admin = () => {
|
||||
const { user } = useContext(AuthContext);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [configs, setConfigs] = useState({})
|
||||
const [toggle, setToggle] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
getConfigs()
|
||||
.then(data => {
|
||||
setConfigs(data.configs);
|
||||
setToggle(data.configs.REGISTRATION_ENABLED === "1")
|
||||
setLoading(false);
|
||||
})
|
||||
}, [])
|
||||
|
||||
if (!user || !user.admin) {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
<h1>Unauthorized</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
<ScaleLoader color="#6AD7E5" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const handleToggle = () => {
|
||||
setToggle(!toggle);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="pageWrapper">
|
||||
<h1>
|
||||
Admin Panel
|
||||
</h1>
|
||||
<div className="loginBody">
|
||||
<Formik
|
||||
initialValues={configs}
|
||||
onSubmit={(values) => postConfigs(values, toggle)}
|
||||
>
|
||||
<Form><br/>
|
||||
<label>
|
||||
<Field
|
||||
type="checkbox"
|
||||
name="REGISTRATION_ENABLED"
|
||||
onChange={handleToggle}
|
||||
component={Switch}
|
||||
checked={toggle}
|
||||
value={toggle}
|
||||
/>
|
||||
Registration Enabled
|
||||
</label><br/><br/>
|
||||
<label>
|
||||
LastFM Api Key<br/>
|
||||
<Field
|
||||
name="LASTFM_API_KEY"
|
||||
type="text"
|
||||
className="loginFields"
|
||||
/>
|
||||
</label>
|
||||
<br/>
|
||||
<label>
|
||||
Spotify App ID<br/>
|
||||
<Field
|
||||
name="SPOTIFY_APP_ID"
|
||||
type="text"
|
||||
className="loginFields"
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
Spotify App Secret<br/>
|
||||
<Field
|
||||
name="SPOTIFY_APP_SECRET"
|
||||
type="text"
|
||||
className="loginFields"
|
||||
/>
|
||||
</label>
|
||||
<br/><br/>
|
||||
<Button
|
||||
color="primary"
|
||||
type="submit"
|
||||
className="loginButton"
|
||||
disabled={loading}
|
||||
>Update</Button>
|
||||
</Form>
|
||||
</Formik>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Admin;
|
|
@ -10,7 +10,7 @@ import AuthContext from '../Contexts/AuthContext';
|
|||
const Dashboard = () => {
|
||||
const history = useHistory();
|
||||
let { user } = useContext(AuthContext);
|
||||
let [isLoading, setIsLoading] = useState(true);
|
||||
let [loading, setLoading] = useState(true);
|
||||
let [dashboardData, setDashboardData] = useState({});
|
||||
|
||||
if (!user) {
|
||||
|
@ -24,7 +24,7 @@ const Dashboard = () => {
|
|||
getRecentScrobbles(user.uuid)
|
||||
.then(data => {
|
||||
setDashboardData(data);
|
||||
setIsLoading(false);
|
||||
setLoading(false);
|
||||
})
|
||||
}, [user])
|
||||
|
||||
|
@ -33,8 +33,8 @@ const Dashboard = () => {
|
|||
<h1>
|
||||
Dashboard!
|
||||
</h1>
|
||||
{isLoading
|
||||
? <ScaleLoader color="#FFF" size={60} />
|
||||
{loading
|
||||
? <ScaleLoader color="#6AD7E5" size={60} />
|
||||
: <ScrobbleTable data={dashboardData} />
|
||||
}
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue