react fixes

This commit is contained in:
Roman Hergenreder 2020-06-15 00:00:15 +02:00
parent 95b803a1e4
commit dfc9697ed8
7 changed files with 108 additions and 98 deletions

8
admin/dist/main.js vendored

File diff suppressed because one or more lines are too long

@ -33,4 +33,8 @@ export default class API {
async logout() { async logout() {
return this.apiCall("user/logout"); return this.apiCall("user/logout");
} }
async getNotifications() {
return this.apiCall("notifications/fetch");
}
}; };

@ -1,24 +1,11 @@
import React, {useEffect, useState} from "react"; import React from "react";
function useStateFromProp(initialValue) {
const [value, setValue] = useState(initialValue);
useEffect(() => setValue(initialValue), [initialValue]);
return [value, setValue];
}
export default function Dialog(props) { export default function Dialog(props) {
const [value, setValue] = useStateFromProp(props); const show = props.show;
function onClose() {
setValue({ });
}
const show = typeof value.message !== "undefined";
const classes = "modal fade" + (show ? " show" : ""); const classes = "modal fade" + (show ? " show" : "");
const style = { paddingRight: "12px", display: (show ? "block" : "none") }; const style = { paddingRight: "12px", display: (show ? "block" : "none") };
const onClose = props.onClose || function() { };
return ( return (
<div className={classes} id="modal-default" style={style} aria-modal="true" onClick={() => onClose()}> <div className={classes} id="modal-default" style={style} aria-modal="true" onClick={() => onClose()}>

@ -18,17 +18,38 @@ class AdminDashboard extends React.Component {
this.state = { this.state = {
currentView: "dashboard", currentView: "dashboard",
loaded: false, loaded: false,
dialog: { } dialog: { onClose: () => this.hideDialog() },
notifications: { }
}; };
} }
onChangeView(view) { onUpdate() {
this.setState({ ...this.state, currentView: view || "dashboard", dialog: { } }); if (this.state.loaded) {
this.fetchNotifications();
}
} }
showDialog(props) { onChangeView(view) {
props = props || { }; this.setState({ ...this.state, currentView: view || "dashboard" });
this.setState({ ...this.state, dialog: props }); }
showDialog(message, title) {
const props = { show: true, message: message, title: title };
this.setState({ ...this.state, dialog: { ...this.state.dialog, ...props } });
}
hideDialog() {
this.setState({ ...this.state, dialog: { ...this.state.dialog, show: false } });
}
fetchNotifications() {
this.api.getNotifications().then((res) => {
if (!res.success) {
this.showDialog("Error fetching notifications: " + res.msg, "Error fetching notifications");
} else {
this.setState({...this.state, notifications: res.notifications});
}
});
} }
render() { render() {
@ -38,16 +59,17 @@ class AdminDashboard extends React.Component {
if (!Success) { if (!Success) {
document.location = "/admin"; document.location = "/admin";
} else { } else {
this.fetchNotifications();
setInterval(this.onUpdate.bind(this), 60000);
this.setState({...this.state, loaded: true}); this.setState({...this.state, loaded: true});
} }
}); });
return <b>Loading <Icon icon={"spinner"} /></b> return <b>Loading <Icon icon={"spinner"} /></b>
} }
console.log("index.render, state=", this.state);
return <> return <>
<Header /> <Header />
<Sidebar currentView={this.state.currentView} onChangeView={this.onChangeView.bind(this)} showDialog={this.showDialog.bind(this)} api={this.api} /> <Sidebar currentView={this.state.currentView} notifications={this.state.notifications} onChangeView={this.onChangeView.bind(this)} showDialog={this.showDialog.bind(this)} api={this.api} />
<div className={"content-wrapper p-2"}> <div className={"content-wrapper p-2"}>
<section className={"content"}> <section className={"content"}>
{this.createContent()} {this.createContent()}

@ -1,78 +1,76 @@
import React from 'react'; import React from 'react';
import Icon from "./icon"; import Icon from "./icon";
export default class Sidebar extends React.Component { export default function Sidebar(props) {
constructor(props) { let parent = {
super(props); onChangeView: props.onChangeView || function() { },
this.parent = { showDialog: props.showDialog || function() {},
onChangeView: props.onChangeView || function() { }, api: props.api
showDialog: props.showDialog || function() {}, };
api: props.api
}; function onChangeView(view) {
this.state = { currentView: props.currentView, } parent.onChangeView(view);
} }
onChangeView(view) { function onLogout() {
this.setState({ ...this.state, currentView: view }); parent.api.logout().then(obj => {
this.parent.onChangeView(view); if (obj.success) {
} document.location = "/admin";
} else {
onLogout() { parent.showDialog("Error logging out: " + obj.msg, "Error logging out");
this.parent.api.logout().then(obj => { }
if (obj.success) {
document.location = "/admin";
} else {
this.parent.showDialog({message: "Error logging out: " + obj.msg, title: "Error logging out"});
}
}); });
} }
render() { const menuItems = {
"dashboard": {
"name": "Dashboard",
"icon": "tachometer-alt"
},
"users": {
"name": "Users",
"icon": "users"
},
"settings": {
"name": "Settings",
"icon": "tools"
},
"help": {
"name": "Help",
"icon": "question-circle"
},
};
const menuItems = { let numNotifications = Object.keys(props.notifications).length;
"dashboard": { if (numNotifications > 0) {
"name": "Dashboard", if (numNotifications > 9) numNotifications = "9+";
"icon": "tachometer-alt" menuItems["dashboard"]["badge"] = { type: "warning", value: numNotifications };
}, }
"users": {
"name": "Users",
"icon": "users"
},
"settings": {
"name": "Settings",
"icon": "tools"
},
"help": {
"name": "Help",
"icon": "question-circle"
},
};
let li = []; let li = [];
// li.push(<li className={"nav-item"} key={"logged-in-as"}><span className={""}>Logged in as: {this.parent.api.user.name}</span><hr/></li>); for (let id in menuItems) {
// li.push(<li key={"hr"}><hr/></li>); let obj = menuItems[id];
// li.push(<li key={"header"} className={"header"}>MAIN NAVIGATION</li>); let active = props.currentView === id ? " active" : "";
const badge = (obj.badge ? <span className={"right badge badge-" + obj.badge.type}>{obj.badge.value}</span> : <></>);
for (let id in menuItems) { li.push(<li key={id} className={"nav-item"}>
let obj = menuItems[id]; <a href={"#"} onClick={() => onChangeView(id)} className={"nav-link" + active}>
let active = this.state.currentView === id ? " active" : ""; <Icon icon={obj.icon} classes={"nav-icon"} /><p>{obj.name}{badge}</p>
li.push(<li key={id} className={"nav-item"}>
<a href={"#"} onClick={() => this.onChangeView(id)} className={"nav-link" + active}>
<Icon icon={obj.icon} classes={"nav-icon"} /><p>{obj.name}</p>
</a>
</li>);
}
li.push(<li className={"nav-item"} key={"logout"}>
<a href={"#"} onClick={() => this.onLogout()} className={"nav-link"}>
<Icon icon={"arrow-left"} classes={"nav-icon"} />
<p>Logout</p>
</a> </a>
</li>); </li>);
}
return <aside className={"main-sidebar sidebar-dark-primary elevation-4"}>
<a href={"#"} className={"brand-link"} onClick={() => this.onChangeView("dashboard")}> li.push(<li className={"nav-item"} key={"logout"}>
<a href={"#"} onClick={() => onLogout()} className={"nav-link"}>
<Icon icon={"arrow-left"} classes={"nav-icon"} />
<p>Logout</p>
</a>
</li>);
return (
<aside className={"main-sidebar sidebar-dark-primary elevation-4"}>
<a href={"#"} className={"brand-link"} onClick={() => onChangeView("dashboard")}>
<img src={"/img/icons/logo.png"} alt={"Logo"} className={"brand-image img-circle elevation-3"} style={{opacity: ".8"}} /> <img src={"/img/icons/logo.png"} alt={"Logo"} className={"brand-image img-circle elevation-3"} style={{opacity: ".8"}} />
<span className={"brand-text font-weight-light ml-2"}>WebBase</span> <span className={"brand-text font-weight-light ml-2"}>WebBase</span>
</a> </a>
@ -93,7 +91,7 @@ export default class Sidebar extends React.Component {
{/* LOGGED IN AS */} {/* LOGGED IN AS */}
<div className="user-panel mt-3 pb-3 mb-3 d-flex"> <div className="user-panel mt-3 pb-3 mb-3 d-flex">
<div className="info"> <div className="info">
<a href="#" className="d-block">Logged in as: {this.parent.api.user.name}</a> <a href="#" className="d-block">Logged in as: {parent.api.user.name}</a>
</div> </div>
</div> </div>
@ -109,6 +107,5 @@ export default class Sidebar extends React.Component {
</div> </div>
</div> </div>
</aside> </aside>
} )
}
};

@ -15,8 +15,8 @@ class LoginBody extends Body {
public function loadView() { public function loadView() {
parent::loadView(); parent::loadView();
$head = $this->getDocument()->getHead(); $head = $this->getDocument()->getHead();
$head->loadBootstrap();
$head->loadJQuery(); $head->loadJQuery();
$head->loadBootstrap();
$head->addJS(Script::CORE); $head->addJS(Script::CORE);
$head->addCSS(Link::CORE); $head->addCSS(Link::CORE);
$head->addJS(Script::ADMIN); $head->addJS(Script::ADMIN);

8
js/admin.min.js vendored

File diff suppressed because one or more lines are too long