const {h, render, Component} = preact; const html = htm.bind(h); class Login extends Component { state = {user: '', pass: ''}; onclick = (app) => { const authhdr = 'Basic ' + btoa(this.state.user + ':' + this.state.pass); const headers = {Authorization: authhdr}; return axios.get('/api/login', {headers}) .then(res => app.setUser(res.data.token)) .catch(err => alert('Login failed')); }; onpassinput = (ev) => this.setState({pass: ev.target.value}); onuserinput = (ev) => this.setState({user: ev.target.value}); render({app}, {user, pass, signup}) { return html`

Login

this.onclick(app)} />
Valid logins: admin:admin, user1:pass1, user2:pass2
` } }; class Dropdown extends Component { state = {show: false}; render(props, state) { const onclick = x => this.setState({show: x}); const show = state.show ? 'show' : ''; return html` `; } }; const NavLink = ({href, title, url}) => html`${title}`; class Header extends Component { state = {expanded: false}; ontoggle = () => this.setState({expanded: !this.state.expanded}); render(props, state) { const u = props.app.state.user || {}; return html` ` } }; class AdminDashboard extends Component { state = {udata: '', adata: ''}; componentDidMount() { axios.get('/api/user/data').then(r => this.setState({udata: r.data})); axios.get('/api/admin/data').then(r => this.setState({adata: r.data})); } render(props, state) { console.log('-->', state); return html`
this is admin page
admin data, returned by server: ${JSON.stringify(state.adata)}
user data, returned by server: ${JSON.stringify(state.udata)}
` } } class UserDashboard extends Component { state = {udata: ''}; componentDidMount() { axios.get('/api/user/data').then(r => this.setState({udata: r.data})); axios.get('/api/admin/data').then(r => this.setState({adata: r.data})); } render(props, state) { return html`
admin data, returned by server (must be empty and dev tools should show 403): ${JSON.stringify(state.adata)}
user data, returned by server: ${JSON.stringify(state.udata)}
` } } class Settings extends Component { state = {}; render(props, state) { return html`
settings page
` } } class App extends Component { state = {user: null, url: '/'}; setUser(token) { const maxAge = token ? 86400 : 0; document.cookie = `access_token=${token};path=/;max-age=${maxAge}`; // this.setState({token}); return axios.get('/api/login') .then(res => this.setState({user: res.data})) .catch(err => this.setState({user: {}})); } componentDidMount() { const getCookie = name => { var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); return v ? v[2] : ''; }; this.setUser(getCookie('access_token')); // Move from state1 to 2 or 3 } render(props, state) { // We have three states: // 1. Beginning. We don't know if we have a valid auth token or not // 2. We sent an /api/login request, and failed to login // 3. We sent an /api/login request, and succeeded to login if (!state.user) return ''; // State 1 if (!state.user.user) return h(Login, {app: this}); // State 2 return h( // State 3 'div', {}, h(Header, {url: state.url, app: this}), h(preactRouter.Router, { history: History.createHashHistory(), onChange: ev => this.setState({url: ev.url}), }, h(state.user.user == 'admin' ? AdminDashboard : UserDashboard, {default: true, app: this}), h(Settings, {path: 'settings', app: this}))); } }; window.onload = () => render(h(App), document.body);