mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-03 14:42:18 +00:00
0.0.5
- Only allow ItemType:Audio from Jellyfin - Fix NavBar for Mobile (Ugly hack but.. TO REWORK) - Fixed registration page issues - Add functionality to pull recent scrobbles to Dashboard - Add MX record lookup validation for emails - Add username validation for a-Z 0-9 _ and . - Dashboard shows basic table of last 500 scrobbles.
This commit is contained in:
parent
7ae9a0cd66
commit
2f8aa2e502
31 changed files with 425 additions and 171 deletions
|
@ -1,6 +1,7 @@
|
|||
.homeBanner {
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
max-width: 1100px;
|
||||
}
|
||||
|
||||
.homeBannerItem {
|
||||
|
|
|
@ -39,22 +39,22 @@ class HomeBanner extends React.Component {
|
|||
<div className="homeBanner">
|
||||
<div className="homeBannerItem">
|
||||
{this.state.isLoading
|
||||
? <ClipLoader color="#6AD7E5" size="36" />
|
||||
? <ClipLoader color="#6AD7E5" size={36} />
|
||||
: <span className="homeBannerItemCount">{this.state.scrobbleCount}</span>}<br/>Scrobbles
|
||||
</div>
|
||||
<div className="homeBannerItem">
|
||||
{this.state.isLoading
|
||||
? <ClipLoader color="#6AD7E5" size="36" />
|
||||
? <ClipLoader color="#6AD7E5" size={36} />
|
||||
: <span className="homeBannerItemCount">{this.state.userCount}</span>}<br/>Users
|
||||
</div>
|
||||
<div className="homeBannerItem">
|
||||
{this.state.isLoading
|
||||
? <ClipLoader color="#6AD7E5" size="36" />
|
||||
? <ClipLoader color="#6AD7E5" size={36} />
|
||||
: <span className="homeBannerItemCount">{this.state.trackCount}</span>}<br/>Tracks
|
||||
</div>
|
||||
<div className="homeBannerItem">
|
||||
{this.state.isLoading
|
||||
? <ClipLoader color="#6AD7E5" size="36" />
|
||||
? <ClipLoader color="#6AD7E5" size={36} />
|
||||
: <span className="homeBannerItemCount">{this.state.artistCount}</span>}<br/>Artists
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -3,19 +3,33 @@
|
|||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.navLinkMobile {
|
||||
color: #CCCCCC;
|
||||
}
|
||||
|
||||
.navLink:hover {
|
||||
color: #666666;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navLinkMobile:hover {
|
||||
color: #666666;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.navLinkLogin {
|
||||
margin-left: 15px;
|
||||
padding-left: 15px;
|
||||
border-left: 1px solid #282c34;
|
||||
}
|
||||
|
||||
.navLinkLoginMobile {
|
||||
margin: 0 auto 0 auto;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-logo {
|
||||
height: 50px;
|
||||
margin: -15px 5px -15px -5px;
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import { React, Component } from 'react';
|
||||
import { Navbar, NavbarBrand } from 'reactstrap';
|
||||
import { Navbar, NavbarBrand, Collapse, Nav, NavbarToggler, NavItem } from 'reactstrap';
|
||||
import { Link } from 'react-router-dom';
|
||||
import logo from '../logo.png';
|
||||
import './Navigation.css';
|
||||
|
@ -21,12 +21,19 @@ const loggedInMenuItems = [
|
|||
'Dashboard',
|
||||
'About',
|
||||
]
|
||||
|
||||
const isMobile = () => {
|
||||
return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
|
||||
};
|
||||
|
||||
class Navigation extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.toggleNavbar = this.toggleNavbar.bind(this);
|
||||
|
||||
// Yeah I know you might not hit home.. but I can't get the
|
||||
// path based finder thing working on initial load :sweatsmile:
|
||||
this.state = { active: "Home" };
|
||||
this.state = { active: "Home", collapsed: true};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -51,84 +58,150 @@ class Navigation extends Component {
|
|||
eventBus.remove(LOGOUT);
|
||||
}
|
||||
|
||||
|
||||
_handleClick(menuItem) {
|
||||
this.setState({ active: menuItem });
|
||||
this.setState({ active: menuItem, collapsed: !this.state.collapsed });
|
||||
}
|
||||
|
||||
toggleNavbar() {
|
||||
this.setState({ collapsed: !this.state.collapsed });
|
||||
}
|
||||
|
||||
// This is a real mess. TO CLEAN UP.
|
||||
render() {
|
||||
const activeStyle = { color: '#FFFFFF' };
|
||||
|
||||
const renderAuthButtons = () => {
|
||||
if (this.state.isLoggedIn) {
|
||||
return <div className="navLinkLogin">
|
||||
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={this.toggleNavbar} className="mr-2" />
|
||||
<Collapse isOpen={!this.state.collapsed} navbar>
|
||||
{this.state.isLoggedIn ?
|
||||
<Nav className="navLinkLoginMobile" navbar>
|
||||
{loggedInMenuItems.map(menuItem =>
|
||||
<NavItem>
|
||||
<Link
|
||||
to="/profile"
|
||||
style={this.state.active === "profile" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "profile")}
|
||||
className="navLink"
|
||||
>Profile</Link>
|
||||
<Link to="/" className="navLink" onClick={logout()}>Logout</Link>
|
||||
</div>;
|
||||
} else {
|
||||
return <div className="navLinkLogin">
|
||||
<Link
|
||||
to="/login"
|
||||
style={this.state.active === "login" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "login")}
|
||||
className="navLink"
|
||||
>Login</Link>
|
||||
<Link
|
||||
to="/register"
|
||||
className="navLink"
|
||||
style={this.state.active === "register" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "register")}
|
||||
history={this.props.history}
|
||||
>Register</Link>
|
||||
</div>;
|
||||
}
|
||||
key={menuItem}
|
||||
className="navLinkMobile"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem}
|
||||
>{menuItem}</Link>
|
||||
</NavItem>
|
||||
)}
|
||||
<Link
|
||||
to="/profile"
|
||||
style={this.state.active === "profile" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "profile")}
|
||||
className="navLinkMobile"
|
||||
>Profile</Link>
|
||||
<Link to="/" className="navLink" onClick={logout()}>Logout</Link>
|
||||
</Nav>
|
||||
: <Nav className="navLinkLoginMobile" navbar>
|
||||
{menuItems.map(menuItem =>
|
||||
<NavItem>
|
||||
<Link
|
||||
key={menuItem}
|
||||
className="navLinkMobile"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem === "Home" ? "/" : menuItem}
|
||||
>
|
||||
{menuItem}
|
||||
</Link>
|
||||
</NavItem>
|
||||
)}
|
||||
<NavItem>
|
||||
<Link
|
||||
to="/login"
|
||||
style={this.state.active === "login" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "login")}
|
||||
className="navLinkMobile"
|
||||
>Login</Link>
|
||||
</NavItem>
|
||||
<NavItem>
|
||||
<Link
|
||||
to="/register"
|
||||
className="navLinkMobile"
|
||||
style={this.state.active === "register" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "register")}
|
||||
history={this.props.history}
|
||||
>Register</Link>
|
||||
</NavItem>
|
||||
</Nav>
|
||||
}
|
||||
</Collapse>
|
||||
</Navbar>
|
||||
}
|
||||
|
||||
const renderMenuButtons = () => {
|
||||
if (this.state.isLoggedIn) {
|
||||
return <div>
|
||||
{loggedInMenuItems.map(menuItem =>
|
||||
<Link
|
||||
key={menuItem}
|
||||
className="navLink"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem}
|
||||
>
|
||||
{menuItem}
|
||||
</Link>
|
||||
)}
|
||||
</div>;
|
||||
} else {
|
||||
return <div>
|
||||
{menuItems.map(menuItem =>
|
||||
<Link
|
||||
key={menuItem}
|
||||
className="navLink"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem === "Home" ? "/" : menuItem}
|
||||
>
|
||||
{menuItem}
|
||||
</Link>
|
||||
)}
|
||||
</div>;
|
||||
}
|
||||
const renderDesktopNav = () => {
|
||||
return <Navbar color="dark" dark fixed="top">
|
||||
<NavbarBrand className="mr-auto"><img src={logo} className="nav-logo" alt="logo" /> GoScrobble</NavbarBrand>
|
||||
{this.state.isLoggedIn ?
|
||||
<div>
|
||||
{loggedInMenuItems.map(menuItem =>
|
||||
<Link
|
||||
key={menuItem}
|
||||
className="navLink"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem}
|
||||
>
|
||||
{menuItem}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
: <div>
|
||||
{menuItems.map(menuItem =>
|
||||
<Link
|
||||
key={menuItem}
|
||||
className="navLink"
|
||||
style={this.state.active === menuItem ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, menuItem)}
|
||||
to={menuItem === "Home" ? "/" : menuItem}
|
||||
>
|
||||
{menuItem}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
{this.state.isLoggedIn ?
|
||||
<div className="navLinkLogin">
|
||||
<Link
|
||||
to="/profile"
|
||||
style={this.state.active === "profile" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "profile")}
|
||||
className="navLink"
|
||||
>Profile</Link>
|
||||
<Link to="/" className="navLink" onClick={logout()}>Logout</Link>
|
||||
</div>
|
||||
:
|
||||
<div className="navLinkLogin">
|
||||
<Link
|
||||
to="/login"
|
||||
style={this.state.active === "login" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "login")}
|
||||
className="navLink"
|
||||
>Login</Link>
|
||||
<Link
|
||||
to="/register"
|
||||
className="navLink"
|
||||
style={this.state.active === "register" ? activeStyle : {}}
|
||||
onClick={this._handleClick.bind(this, "register")}
|
||||
history={this.props.history}
|
||||
>Register</Link>
|
||||
</div>
|
||||
|
||||
}
|
||||
</Navbar>
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Navbar color="dark" dark fixed="top">
|
||||
<NavbarBrand className="mr-auto"><img src={logo} className="nav-logo" alt="logo" /> GoScrobble</NavbarBrand>
|
||||
{renderMenuButtons()}
|
||||
{renderAuthButtons()}
|
||||
</Navbar>
|
||||
{
|
||||
isMobile()
|
||||
? renderMobileNav()
|
||||
: renderDesktopNav()
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
43
web/src/Components/ScrobbleTable.js
Normal file
43
web/src/Components/ScrobbleTable.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
import React from "react";
|
||||
|
||||
class ScrobbleTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
data: this.props.data,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<table border={1} cellPadding={5}>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Timestamp</td>
|
||||
<td>Track</td>
|
||||
<td>Artist</td>
|
||||
<td>Album</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{
|
||||
this.state.data && this.state.data.items &&
|
||||
this.state.data.items.map(function (element) {
|
||||
return <tr>
|
||||
<td>{element.time}</td>
|
||||
<td>{element.track}</td>
|
||||
<td>{element.artist}</td>
|
||||
<td>{element.album}</td>
|
||||
</tr>;
|
||||
})
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ScrobbleTable;
|
Loading…
Add table
Add a link
Reference in a new issue