save before switch back to hooks

This commit is contained in:
Jean Jacques Avril 2022-03-08 12:29:52 +01:00
parent ea3b847268
commit d990c46a02
21 changed files with 183 additions and 82 deletions

View File

@ -1,17 +1,14 @@
import { Component, h } from "preact"; import { Component, h } from "preact";
import { Router } from "preact-router"; import { Router, route } from "preact-router";
import Header from "./header"; import Header from "./header";
import Login from "../routes/login";
import Profile from "../routes/profile";
import Menu from "./menu"; import Menu from "./menu";
import Users from "../routes/users";
import { useCallback, useState } from "preact/hooks"; import { useCallback, useState } from "preact/hooks";
import { AppData, Provider, Consumer } from '../utils' import { AppData, Provider, Consumer } from '../utils';
const App = () => { import { Home, Users, Profile, Login, Logout } from "../route";
const appdata = AppData(); class App extends Component {
let session = appdata.get("Session"); appdata = AppData();
//session.sub(forceUpdate); session = this.appdata.get("Session");
const toggleMenu = () => { toggleMenu = () => {
const [visible, setValue] = useState(false); const [visible, setValue] = useState(false);
const toggle = useCallback(() => { const toggle = useCallback(() => {
@ -20,13 +17,33 @@ const App = () => {
}, [visible]); }, [visible]);
return { visible, toggle }; return { visible, toggle };
} }
componentWillUnmount() {
//this.sub();
}
const menu = toggleMenu(); menu_items = [
{ text: "Übersicht", path: "/" },
{ text: "Benutzer", path: "/users" },
{ text: "System", path: "/system" },
{ text: "Profil", path: "/profile" },
{ text: "Abmelden", path: "/logout" }
]
handleRoute = async e => {
const isAuthed = this.session.actions.isAuth();
switch (e.url) {
default:
if (!isAuthed) route('/login', true);
break;
}
};
render() {
let menu = this.toggleMenu();
let session = this.session;
session.addAction("isAuth", () => { return session.data && session.data.username !== '' })
console.log(session.actions);
this.sub = session.sub(() => this.forceUpdate());
return ( return (
<Provider appdata={appdata} > <Provider appdata={this.appdata} >
<div id="wrapper"> <div id="wrapper">
<Consumer datapath="Session"> <Consumer datapath="Session">
{(appdata) => { {(appdata) => {
@ -34,23 +51,34 @@ const App = () => {
}} }}
</Consumer> </Consumer>
<Header menu={menu} /> <Header menu={menu} />
<Menu menu={menu} />
{!menu.visible &&
(!session.data || session.data.username === '' ? (
<Login />
) : (
<div class="page"> <div class="page">
<Router> <Menu menu={menu} items={this.menu_items} />
<Profile path="/test/" user="me" /> {!menu.visible &&
<Router onChange={this.handleRoute}>
<Home path="/" user="me" />
<Login path="login" />
<Profile path="/profile/:user" /> <Profile path="/profile/:user" />
<Logout path="/logout" />
<Users path="/users" /> <Users path="/users" />
<div class="container" default>Error 404</div> <div class="container" default>Error 404</div>
</Router> </Router>
}
</div> </div>
))} <footer>
<div className="container" style={'text-align: center; align-items: center'}>
<span>&copy; Jean Jacques Avril 2022 </span>
</div> </div>
</footer>
</div>
</Provider> </Provider>
); );
}
} }

View File

@ -1,14 +1,10 @@
import { h, forceUpdate } from 'preact';
import { Consumer } from '../../utils'
//import { Link } from 'preact-router/match';
const Header = (props, ctx) => { const Header = (props, ctx) => {
console.log(ctx.data) const session = ctx.get('Session');
return ( return (
<header className='header'> <header className='header'>
<div className="container"> <div className="container">
<h1>Login</h1> <h1>Login</h1>
{ctx.data && (<div id="hamburger-button" className={`hamburger ${props.menu.visible && 'hamburger-active'}`} {session.actions.isAuth() && (<div id="hamburger-button" className={`hamburger ${props.menu.visible && 'hamburger-active'}`}
onClick={() => props.menu.toggle()}> onClick={() => props.menu.toggle()}>
<hr /> <hr />
<hr /> <hr />

9
src/components/index.js Normal file
View File

@ -0,0 +1,9 @@
import App from "./app";
import Breadcrumbs from "./breadcrumbs";
import Pageselector from "./Pageselector";
import Header from "./header";
import UserList from "./userlist";
import Menu from "./menu";
export {App, Breadcrumbs, Pageselector, Header, UserList, Menu}
export default App

View File

@ -17,13 +17,14 @@ class Menu extends Component {
e.preventDefault(); e.preventDefault();
this.props.menu.toggle(); this.props.menu.toggle();
} }
render(props, state) { render(props) {
if(props.items)
this.menu_items = props.items;
if (props.menu.visible) if (props.menu.visible)
return ( return (
<div class="container" > <div class="container" >
<nav className='menu' > <nav className='menu' >
<ul> <ul>
<li><Link href="/test" >Test</Link></li>
{this.menu_items.map((element, i) => (<li key={i}><Link href={element.path} onClick={this.onClick} >{element.text}</Link></li>))} {this.menu_items.map((element, i) => (<li key={i}><Link href={element.path} onClick={this.onClick} >{element.text}</Link></li>))}
</ul> </ul>
</nav> </nav>

View File

@ -1,5 +1,5 @@
import './style/style.sass'; import './style/style.sass';
import App from './components/app'; import App from './components';
import { h, render } from "preact" import { h, render } from "preact"
render(<App />, document.body) render(<App />, document.body)

View File

@ -1,11 +1,10 @@
import { h } from 'preact'; import { h } from 'preact';
import style from './style.css';
const Home = () => ( function Home() {return(
<div class={style.home}> <div class="container">
<h1>Home</h1> <h1>Home</h1>
<p>This is the Home component.</p> <p>This is the Home component.</p>
</div> </div>
); );
}
export default Home; export default Home;

6
src/route/index.js Normal file
View File

@ -0,0 +1,6 @@
import Home from "./home"
import Users from './users'
import Profile from "./profile"
import Login from "./login"
import Logout from './logout'
export {Home, Users, Profile, Login, Logout }

View File

@ -1,40 +1,48 @@
import { h } from 'preact'; import { h } from 'preact';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import { route } from 'preact-router';
import Breadcrumbs from '../../components/breadcrumbs'; import Breadcrumbs from '../../components/breadcrumbs';
const Login = (props,ctx) => { function Login(props, ctx) {
const [val,set] = useState({ username: '', password: '' }); const [val, set] = useState({ username: '', password: '', error: null });
const navigation = ["Login"]; const navigation = ["Login"];
const session = ctx.get('Session'); const session = ctx.get('Session');
function onSubmit (e) { function onSubmit(e) {
e.preventDefault(); e.preventDefault();
//sucess
if (val.username === 'admin') {
session.data = val; session.data = val;
console.log(session.data); route('/', true);
set({username: '', password: '' });
} }
else {
return (<div id="login-screen" class="page"> set({ ...val, error: "user" });
}
set({ username: '', password: '' });
}
return (
<div class="container"> <div class="container">
<Breadcrumbs items={navigation} /> <Breadcrumbs items={navigation} />
<form id="login_form" onSubmit={onSubmit} > <form id="login_form" onSubmit={onSubmit} >
<p> <p >
Bitte melden Sie sich mit ihren Nutzerdaten an. Bitte melden Sie sich mit ihren Nutzerdaten an.
</p> </p>
{val.error !== null && <span style={'color: red'}>Fehler: Ungültige Anmeldedaten.</span>}
<div class="input-box"> <div class="input-box">
<input id="name" type="text" placeholder="Username" onInput={e => set( {...val, username: e.target.value} )} value={val.username} /> <input id="name" type="text" placeholder="Username" onInput={e => set({ ...val, username: e.target.value })} value={val.username} />
<label for="name">Benutzername</label> <label for="name">Benutzername</label>
</div> </div>
<div class="input-box"> <div class="input-box">
<input id="pass" type="password" placeholder="Passwort" onInput={e => set( {...val, password: e.target.value} )} value={val.password} /> <input id="pass" type="password" placeholder="Passwort" onInput={e => set({ ...val, password: e.target.value })} value={val.password} />
<label for="pass">Password</label> <label for="pass">Password</label>
</div> </div>
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />
</form> </form>
</div> </div>
</div>); );
} }

View File

@ -0,0 +1,30 @@
import { h } from 'preact';
import { Link } from 'preact-router';
import { Breadcrumbs } from '../../components';
function Logout (props, ctx) {
const navigation = ["Logout"];
const session = ctx.get('Session');
this.shouldComponentUpdate = function(){
console.log('functional component vs closures');
}
if (session.actions.isAuth()) {
session.data = { username: '', password: '' };
}
return (
<div class="container">
<Breadcrumbs items={navigation} />
<p>
Erfolgreich abgemeldet.
<Link href="/login">Erneut Anmelden</Link>
</p>
</div>
);
}
export default Logout;

View File

@ -1,5 +1,5 @@
import { h } from 'preact'; import { h } from 'preact';
import {useEffect, useState} from "preact/hooks"; import { useEffect, useState } from "preact/hooks";
import style from './style.css'; import style from './style.css';
// Note: `user` comes from the URL, courtesy of our router // Note: `user` comes from the URL, courtesy of our router
@ -13,9 +13,10 @@ const Profile = ({ user }) => {
}, []); }, []);
return ( return (
<div className='container'>
<div class={style.profile}> <div class={style.profile}>
<h1>Profile: {user}</h1> <h1>Profile: {user}</h1>
<p>This is the user profile for a user named { user }.</p> <p>This is the user profile for a user named {user}.</p>
<div>Current time: {new Date(time).toLocaleString()}</div> <div>Current time: {new Date(time).toLocaleString()}</div>
@ -25,6 +26,7 @@ const Profile = ({ user }) => {
Clicked {count} times. Clicked {count} times.
</p> </p>
</div> </div>
</div>
); );
} }

View File

View File

@ -1,5 +0,0 @@
.home {
padding: 56px 20px;
min-height: 100%;
width: 100%;
}

View File

@ -1,10 +1,11 @@
@mixin breadcrumbs @mixin breadcrumbs
padding: 1em 0 padding-top: 1rem
ul ul
display: flex display: flex
background: #eee background: #eee
box-shadow: inset 0 0 .3em #ccc, 0 0 .5em #ddd box-shadow: inset 0 0 .3em #ccc, 0 0 .5em #ddd
padding: .3em padding: .3em
margin: 0
border: 0.05em solid #fff border: 0.05em solid #fff
border-radius: .3em border-radius: .3em
list-style-type: none list-style-type: none

9
src/style/_footer.sass Normal file
View File

@ -0,0 +1,9 @@
@mixin footer
display: block
background: #bbb
text-shadow: 0 0 .2em #34d
color: white
flex-shrink: 0
padding: 0.5rem 0
margin-top: 1rem
width: 100%

View File

@ -16,6 +16,9 @@
//text-shadow: 0 0 .2em #000 //text-shadow: 0 0 .2em #000
width: 100% width: 100%
//background: #ccc //background: #ccc
&:hover
background: #bbb
color: #333
&::after &::after
top: 100% top: 100%
left: 0 left: 0

View File

@ -3,18 +3,19 @@
@use 'login' @use 'login'
@use 'breadcrumbs' @use 'breadcrumbs'
@use 'pageselector' @use 'pageselector'
@use 'footer'
* *
//border: red 1px dotted
box-sizing: border-box box-sizing: border-box
html html
font-family: Helvetica, sans-serif font-family: Helvetica, sans-serif
font-size: 16px font-size: 16px
height: 100%
body body
margin: 0 margin: 0
padding: 0 padding: 0
background-color: white background-color: white
//min-height: 100vh height: 100%
width: 100% width: 100%
#wrapper #wrapper
display: flex display: flex
@ -22,12 +23,14 @@ body
justify-content: flex-start justify-content: flex-start
align-items: stretch align-items: stretch
min-height: 100% min-height: 100%
//margin-bottom: -2rem
width: 100% width: 100%
.header .header
z-index: 100 z-index: 100
position: fixed position: fixed
top: 0em
width: 100% width: 100%
height: 4em height: 4rem
display: flex display: flex
flex-direction: column flex-direction: column
justify-content: flex-end justify-content: flex-end
@ -54,7 +57,9 @@ body
display: flex display: flex
background: white background: white
width: 100% width: 100%
padding-top: 6em flex: 1
margin-top: 4rem
.menu .menu
@include menu.nav @include menu.nav
@ -124,3 +129,6 @@ body
.btn-edit .btn-edit
@include button() @include button()
background-image: url("../assets/icons/edit-icon3.svg") background-image: url("../assets/icons/edit-icon3.svg")
footer
@include footer.footer

View File

@ -16,15 +16,20 @@ function getStore(path){
} }
return current; return current;
} }
function addAction(name, f){
this._actions[name] = f.bind(this._data);
}
function ObservableData() { function ObservableData() {
this.observers = []; this.observers = [];
this.tree = {}; this.tree = {};
this._data = {}; this._data = {};
this._actions = {};
const dispatchChange = () => { const dispatchChange = () => {
this.observers.map(o => o()); this.observers.map(o => o());
} }
return { return {
tree:this.tree, tree:this.tree,
addAction: addAction.bind(this),
sub: subscribe.bind(this), sub: subscribe.bind(this),
get: getStore.bind(this), get: getStore.bind(this),
get data() { get data() {
@ -34,6 +39,7 @@ function ObservableData() {
this._data = val; this._data = val;
dispatchChange(); dispatchChange();
}, },
actions: this._actions,
} }
} }

View File

View File