Compare commits

..

No commits in common. "68501897e4255c72922a8004cdba5c0ca2f6382b" and "642083bad64b25b4e2a61b842c03a0c32e4bd015" have entirely different histories.

22 changed files with 157 additions and 262 deletions

View File

@ -1 +0,0 @@
[{"timestamp":1646751614979,"files":[{"filename":"bundle.2a54a.css","previous":0,"size":1709,"diff":1709},{"filename":"bundle.*****.esm.js","previous":0,"size":9856,"diff":9856},{"filename":"polyfills.*****.esm.js","previous":0,"size":2187,"diff":2187},{"filename":"sw.js","previous":0,"size":10599,"diff":10599},{"filename":"sw-esm.js","previous":0,"size":10603,"diff":10603},{"filename":"bundle.1a7a6.js","previous":0,"size":11947,"diff":11947},{"filename":"polyfills.058fb.js","previous":0,"size":2288,"diff":2288},{"filename":"index.html","previous":0,"size":536,"diff":536},{"filename":"200.html","previous":0,"size":536,"diff":536}]}]

View File

@ -1,57 +1,57 @@
import { h } from "preact"; import { Component, createRef, h } from "preact";
import { Router, route } from "preact-router"; import { Router } from "preact-router";
import {Header, Menu} from "./"; import Header from "./header";
import { menuReducer, sessionReducer } from "../store/reducers"; import Login from "../routes/login";
import { useReducer } from "preact/hooks"; import Profile from "../routes/profile";
import { Home, Users, Profile, Login, Logout } from "../route"; import Menu from "./menu";
import { AppStateProvider } from "../store/AppState"; import Users from "../routes/users";
function App() { import { useCallback, useState } from "preact/hooks";
// useReducer const menu = createRef();
const menu = useReducer(menuReducer, false); class App extends Component {
const session = useReducer(sessionReducer, {active: true}); toggleMenu() {
this.menu_items = [ const [visible, setValue] = useState(false);
{ text: "Übersicht", path: "/" }, const toggle = useCallback(() => {
{ text: "Benutzer", path: "/users" }, setValue(!visible);
{ text: "System", path: "/system" }, return !visible;
{ text: "Profil", path: "/profile" }, }, [visible]);
{ text: "Abmelden", path: "/logout" } return { visible, toggle };
] }
this.handleRoute = async e => { authenticateUser() {
switch (e.url) { const [session, setValue] = useState({ token: null });
default: const login = (username, password) => {
if (!session[0].active) route('/login', true); if (username == "admin" && password == "admin") {
break; setValue({ ...session, token: "ABCDEFG" });
} return true;
}; }
return ( };
const logout = () => setValue({ ...session, token: null });
const isAuthenticated = () => session.token != null;
return { login, logout, isAuthenticated };
}
<AppStateProvider value={{ menu, session}} > render() {
<div id="wrapper"> const menu = this.toggleMenu();
<Header /> const auth = this.authenticateUser();
<div class="page"> return (
<Menu items={this.menu_items} /> <div id="wrapper">
{!menu[0] && <Header menu={menu} auth={auth} />
<Menu menu={menu} />
<Router onChange={this.handleRoute}> {!menu.visible &&
<Home path="/" user="me" /> (!auth.isAuthenticated() ? (
<Login path="login" /> <Login auth={auth} />
<Profile path="/profile" /> ) : (
<Logout path="/logout" /> <div class="page">
<Router>
<Profile path="/test/" user="me" />
<Profile path="/profile/:user" />
<Users path="/users" /> <Users path="/users" />
<div class="container" default>Error 404</div> <div class="container" default>Error 404</div>
</Router> </Router>
}
</div>
<footer>
<div className="container" style={'text-align: center; align-items: center'}>
<span>&copy; Jean Jacques Avril 2022 </span>
</div> </div>
))}
</footer> </div>
</div> );
</AppStateProvider> }
);
} }
export default App; export default App;

View File

@ -1,23 +1,20 @@
import { useContext } from 'preact/hooks'; import { Component, createRef, h } from 'preact';
import AppState from '../../store/AppState'; //import { Link } from 'preact-router/match';
const Header = () => {
let { menu, session } = useContext(AppState); const Header = (props) => (
let [menu_shown, toggle_menu] = menu; <header className='header'>
let [sessiondata] = session; <div className="container">
return ( <h1>Login</h1>
<header className='header'> {props.auth.isAuthenticated() && (<div id="hamburger-button" className={`hamburger ${props.menu.visible && 'hamburger-active'}`}
<div className="container"> onClick={() => props.menu.toggle()}>
<h1>Login</h1> <hr />
{ sessiondata.active &&(<div id="hamburger-button" className={`hamburger ${menu_shown && 'hamburger-active'}`} <hr />
onClick={() => toggle_menu('toggle')}> <hr />
<hr /> </div>)}
<hr /> </div>
<hr /> </header>
</div>)} );
</div>
</header>
);
}

View File

@ -1,9 +0,0 @@
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

@ -1,10 +1,8 @@
import { h } from 'preact'; import { Component, h } from 'preact';
import { Link } from 'preact-router'; import { Link } from 'preact-router';
import { useContext } from 'preact/hooks'; class Menu extends Component {
import AppState from '../../store/AppState';
function Menu({items}) { menu_items = [
let [ menu_shown, toggle_menu ] = useContext(AppState).menu;
let menu_items = [
{ text: "Übersicht", path: "/" }, { text: "Übersicht", path: "/" },
{ text: "Benutzer", path: "/users" }, { text: "Benutzer", path: "/users" },
{ text: "System", path: "/system" }, { text: "System", path: "/system" },
@ -12,25 +10,26 @@ function Menu({items}) {
{ text: "Abmelden", path: "/logout" } { text: "Abmelden", path: "/logout" }
] ]
getAlert() {
const onClick = (e) => { alert("getAlert from Child");
e.preventDefault();
toggle_menu('hide');
} }
onClick = (e) => {
e.preventDefault();
this.props.menu.toggle();
}
render(props, state) {
if (props.menu.visible)
return (
<div class="container" >
<nav className='menu' >
<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>))}
</ul>
</nav>
if (items) </div>)
menu_items = items; }
if (menu_shown)
return (
<div class="container" >
<nav className='menu' >
<ul>
{menu_items.map((element, i) => (<li key={i}><Link href={element.path} onClick={onClick} >{element.text}</Link></li>))}
</ul>
</nav>
</div>)
} }
export default Menu; export default Menu;

View File

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

View File

@ -1,6 +0,0 @@
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,55 +0,0 @@
import { h } from 'preact';
import { route } from 'preact-router';
import { useContext,useState } from 'preact/hooks';
import AppState from '../../store/AppState';
import Breadcrumbs from '../../components/breadcrumbs';
function Login() {
let [sessiondata, setsession]= useContext(AppState).session;
const [val, set] = useState({ username: '', password: '', error: null });
const navigation = ["Login"];
if(sessiondata.active)
route('/', true);
function onSubmit(e) {
e.preventDefault();
//sucess
if (val.username === 'admin') {
let newsession = {
type: 'start',
username: 'affe',
token: 'dsf4w3qr'
}
setsession(newsession);
}
else {
set({ ...val, error: "user" });
}
set({ username: '', password: '' });
}
return (
<div class="container">
<Breadcrumbs items={navigation} />
<form id="login_form" onSubmit={onSubmit} >
<p >
Bitte melden Sie sich mit ihren Nutzerdaten an.
</p>
{val.error !== null && <span style={'color: red'}>Fehler: Ungültige Anmeldedaten.</span>}
<div class="input-box">
<input id="name" type="text" placeholder="Username" onInput={e => set({ ...val, username: e.target.value })} value={val.username} />
<label for="name">Benutzername</label>
</div>
<div class="input-box">
<input id="pass" type="password" placeholder="Passwort" onInput={e => set({ ...val, password: e.target.value })} value={val.password} />
<label for="pass">Password</label>
</div>
<input type="submit" value="Submit" />
</form>
</div>
);
}
export default Login;

View File

@ -1,32 +0,0 @@
import { h } from 'preact';
import { Link } from 'preact-router';
import { useContext } from 'preact/hooks';
import AppState from '../../store/AppState';
import { Breadcrumbs } from '../../components';
function Logout() {
const navigation = ["Logout"];
let [sessiondata, setsession] = useContext(AppState).session;
this.shouldComponentUpdate = function () {
console.log('functional component vs closures');
}
if (sessiondata.active) {
setsession({ type: 'end' })
}
return (
<div class="container">
<Breadcrumbs items={navigation} />
<p>
Erfolgreich abgemeldet.
<Link href="/login">Erneut Anmelden</Link>
</p>
</div>
);
}
export default Logout;

View File

@ -1,10 +1,11 @@
import { h } from 'preact'; import { h } from 'preact';
import style from './style.css';
function Home() {return( const Home = () => (
<div class="container"> <div class={style.home}>
<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;

View File

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

View File

@ -0,0 +1,41 @@
import { Component, h } from 'preact';
import Breadcrumbs from '../../components/breadcrumbs';
class Login extends Component {
state = { username: '', password: '' };
navigation = ["Login"];
onSubmit = (e) => {
e.preventDefault();
console.log(this.state);
this.setState({ username: '', password: '' });
if(!this.props.auth.login(this.state.username,this.state.password))
alert("Wrong login")
}
render() {
return (<div id="login-screen" class="page">
<div class="container">
<Breadcrumbs items={this.navigation} />
<form id="login_form" onSubmit={this.onSubmit} >
<p>
Bitte melden Sie sich mit ihren Nutzerdaten an.
</p>
<div class="input-box">
<input id="name" type="text" placeholder="Username" onInput={e => this.setState(prev => ({ ...prev, username: e.target.value }))} value={this.state.username} />
<label for="name">Benutzername</label>
</div>
<div class="input-box">
<input id="pass" type="password" placeholder="Passwort" onInput={e => this.setState(prev => ({ ...prev, password: e.target.value }))} value={this.state.password} />
<label for="pass">Password</label>
</div>
<input type="submit" value="Submit" />
</form>
</div>
</div>);
}
}
export default Login;

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,19 +13,17 @@ 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>
<p> <p>
<button onClick={() => setCount((count) => count + 1)}>Click Me</button> <button onClick={() => setCount((count) => count + 1)}>Click Me</button>
{' '} {' '}
Clicked {count} times. Clicked {count} times.
</p> </p>
</div>
</div> </div>
); );
} }

View File

@ -1,6 +0,0 @@
import { createContext } from "preact";
const AppState = createContext({});
export const AppStateProvider = AppState.Provider;
export default AppState;

View File

@ -1,16 +0,0 @@
export const menuReducer = (state, action) => {
switch (action) {
case 'show': return true;
case 'hide': return false;
case 'toggle': return !state;
default: throw new Error("menustate unknown to reducer");
}
}
export const sessionReducer = (state, action) => {
switch (action.type) {
case 'start': return {active: true, token: action.token, username: action.username}
case 'end': return {active: false, token: null, username: null, exiry: null}
default: throw new Error("action type unknown to session reducer");
}
}

View File

@ -1,11 +1,10 @@
@mixin breadcrumbs @mixin breadcrumbs
padding-top: 1rem padding: 1em 0
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

View File

@ -1,9 +0,0 @@
@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,9 +16,6 @@
//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,19 +3,18 @@
@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
height: 100% //min-height: 100vh
width: 100% width: 100%
#wrapper #wrapper
display: flex display: flex
@ -23,14 +22,12 @@ 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: 4rem height: 4em
display: flex display: flex
flex-direction: column flex-direction: column
justify-content: flex-end justify-content: flex-end
@ -57,9 +54,7 @@ body
display: flex display: flex
background: white background: white
width: 100% width: 100%
flex: 1 padding-top: 6em
margin-top: 4rem
.menu .menu
@include menu.nav @include menu.nav
@ -129,6 +124,3 @@ 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