- Added Admin/Site config page in frontend for admin users
- Added API POST/GET /config endpoint
This commit is contained in:
Daniel Mason 2021-03-31 21:40:20 +13:00
parent 8be4a190a6
commit af02bd99cc
Signed by: idanoo
GPG key ID: 387387CDBC02F132
17 changed files with 826 additions and 24 deletions

View file

@ -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');
});
};

View file

@ -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} />

View file

@ -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
View 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
View 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;

View file

@ -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>