Merge branch 'main' of git.odit.services:lfk/kiosk
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
Nicolai Ort 2023-11-06 20:07:16 +01:00
commit 72ace57cb3
Signed by: niggl
GPG Key ID: 13AFA55AF62F269F
12 changed files with 313 additions and 328 deletions

View File

@ -2,8 +2,36 @@
All notable changes to this project will be documented in this file. Dates are displayed in UTC. All notable changes to this project will be documented in this file. Dates are displayed in UTC.
#### [1.0.0](https://git.odit.services/lfk/kiosk/compare/0.6.0...1.0.0)
- feat: footer [`115767c`](https://git.odit.services/lfk/kiosk/commit/115767c656381336257c23ee30a130e7e9c60144)
- refactor: drop footer [`e512325`](https://git.odit.services/lfk/kiosk/commit/e5123251155f58e83f36c091b671acc73167ce68)
- feat: prevent F1 + F5 [`bb3c801`](https://git.odit.services/lfk/kiosk/commit/bb3c80190834be6d43f50cdb6eeb09ac75868259)
#### [0.6.0](https://git.odit.services/lfk/kiosk/compare/0.5.0...0.6.0)
> 19 April 2023
- feat!: move to single route application for kiosk mode [`bf8b351`](https://git.odit.services/lfk/kiosk/commit/bf8b351b644174a2dd39d38208a03a067de387be)
- refactor!: cleanup userdata localstorage + components [`c7c1c6d`](https://git.odit.services/lfk/kiosk/commit/c7c1c6dc41afc6ca3e66b507fd1ff50185f4e1be)
- 🚀Bumped version to 0.6.0 [`aa7d2db`](https://git.odit.services/lfk/kiosk/commit/aa7d2dbe1b67b33a59093bc53aa944cb6473ef03)
- add chrome kiosk command to readme [`01cd8d4`](https://git.odit.services/lfk/kiosk/commit/01cd8d4b78b3898d2f74f2b27cdad9e9745c1e33)
#### [0.5.0](https://git.odit.services/lfk/kiosk/compare/0.4.4...0.5.0)
> 19 April 2023
- feat(registration): autofocus input fields + done button [`cbfbd92`](https://git.odit.services/lfk/kiosk/commit/cbfbd92d0e4f9735a2192125f267f651ed36c9b1)
- 🚀Bumped version to 0.5.0 [`58830c5`](https://git.odit.services/lfk/kiosk/commit/58830c5db3d9903d590f535a4099ad93a8ff6519)
- feat(registration): disabled done button for 7.5s [`5f5b03a`](https://git.odit.services/lfk/kiosk/commit/5f5b03a8a086799543cf675ccc3a973b781d1987)
- feat(registration): support next input element with ENTER key [`066e67c`](https://git.odit.services/lfk/kiosk/commit/066e67c64f48b00673f2de7727acb230c94c3c13)
- feat(registration): disable text select [`418fe77`](https://git.odit.services/lfk/kiosk/commit/418fe7773fbc981186909a1f7c262c3c1fa1ece2)
#### [0.4.4](https://git.odit.services/lfk/kiosk/compare/0.4.3...0.4.4) #### [0.4.4](https://git.odit.services/lfk/kiosk/compare/0.4.3...0.4.4)
> 19 April 2023
- 🚀Bumped version to 0.4.4 [`4b6e11d`](https://git.odit.services/lfk/kiosk/commit/4b6e11d8d271c638b3c2e4cd3dc887680023dd5e)
- fix(registration): Added missing dark styling [`0698038`](https://git.odit.services/lfk/kiosk/commit/06980385230e32dffe1083ceb4f88e86a9197aef) - fix(registration): Added missing dark styling [`0698038`](https://git.odit.services/lfk/kiosk/commit/06980385230e32dffe1083ceb4f88e86a9197aef)
#### [0.4.3](https://git.odit.services/lfk/kiosk/compare/0.4.2...0.4.3) #### [0.4.3](https://git.odit.services/lfk/kiosk/compare/0.4.2...0.4.3)

View File

@ -25,3 +25,8 @@ pnpm build
docker build . docker build .
docker-compose up docker-compose up
``` ```
## Kiosk Google Chrome
```
chrome https://run.lauf-fuer-kaya.de/kiosk/ -kiosk
```

View File

@ -1,6 +1,6 @@
{ {
"name": "@lfk/kiosk", "name": "@lfk/kiosk",
"version": "0.4.4", "version": "1.0.0",
"private": false, "private": false,
"license": "MIT", "license": "MIT",
"repository": "https://git.odit.services/lfk/kiosk", "repository": "https://git.odit.services/lfk/kiosk",

View File

@ -1,49 +0,0 @@
<footer class="mt-auto w-full max-w-[85rem] py-10 px-4 sm:px-6 lg:px-8 mx-auto">
<!-- Grid -->
<div class="text-center">
<div>
<a
class="flex-none text-xl font-semibold text-black dark:text-white"
href="/"
aria-label="Brand">LfK Kiosk</a
>
</div>
<!-- End Col -->
<div class="mt-3">
<p class="text-gray-500">
Powered by <a
class="font-semibold text-blue-600 hover:text-blue-700 dark:text-blue-500 dark:hover:text-blue-400"
target="_blank"
rel="noreferrer"
href="https://odit.services/?ref=lfks">ODIT.Services</a
>
</p>
<p class="text-gray-500">© {new Date().getFullYear()} ODIT.Services</p>
</div>
<div class="mt-3 space-x-2">
<a
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
target="_blank"
rel="noreferrer"
href="https://lauf-fuer-kaya.de/impressum"
>
Impressum
</a>
<p
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
>
|
</p>
<a
class="inline-flex justify-center items-center text-center text-gray-500 hover:bg-gray-100 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white transition dark:text-gray-500 dark:hover:text-gray-200 dark:hover:bg-gray-800"
target="_blank"
rel="noreferrer"
href="https://lauf-fuer-kaya.de/datenschutz"
>
Datenschutz
</a>
</div>
</div>
</footer>

View File

@ -2,93 +2,69 @@ import { AuthService, OpenAPI, type ResponseAuth } from '@odit/lfk-client-js';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
type UserState = { type UserState = {
access_token: string; access_token: string;
refresh_token: string; refresh_token: string;
isLoggedIn: boolean; isLoggedIn: boolean;
refreshInterval: NodeJS.Timer | undefined refreshInterval: NodeJS.Timer | undefined;
}; };
const state: UserState = {
const userStore = () => { access_token: '',
const state: UserState = { refresh_token: '',
access_token: '', isLoggedIn: false,
refresh_token: '', refreshInterval: undefined
isLoggedIn: false,
refreshInterval: undefined
};
const { subscribe, set, update } = writable(state);
const methods = {
async login(resAuth: ResponseAuth) {
update((state: UserState) => {
if (!resAuth) {
return state;
}
state.access_token = resAuth.access_token;
state.refresh_token = resAuth.refresh_token;
state.isLoggedIn = true;
state.refreshInterval = setInterval(() => {
this.refreshAuth();
}, 2 * 60000)
localStorage.setItem('kiosk-userdata', JSON.stringify(state));
localStorage.setItem('kiosk-access_token', state.access_token);
OpenAPI.TOKEN = resAuth.access_token;
return state;
});
},
async refreshAuth() {
try {
const authRes = await AuthService.authControllerRefresh({ token: state.refresh_token }) as ResponseAuth;
OpenAPI.TOKEN = authRes.access_token;
} catch {
this.logout();
}
},
async loginFromStorage() {
console.log('loginFromStorage');
const access_token = localStorage.getItem('kiosk-access_token');
if (!access_token) {
throw new Error('Unauthorized');
}
const storagedata = localStorage.getItem('kiosk-userdata');
const userdata = JSON.parse(storagedata || '{}') as UserState;
update((state: UserState) => {
state.access_token = access_token;
state.refresh_token = userdata.refresh_token;
state.isLoggedIn = true;
state.refreshInterval = setInterval(() => {
this.refreshAuth();
}, 2 * 60000);
OpenAPI.TOKEN = userdata.access_token;
return state;
});
await this.refreshAuth();
},
async logout() {
update((state: UserState) => {
state.isLoggedIn = false;
state.access_token = '';
state.refresh_token = '';
state.refreshInterval = undefined;
localStorage.clear();
return state;
});
}
};
return {
subscribe,
set,
update,
state,
...methods
};
}; };
const userState = writable(state);
async function auth_login(resAuth: ResponseAuth) {
if (!resAuth) {
return state;
}
export default userStore(); state.access_token = resAuth.access_token;
state.refresh_token = resAuth.refresh_token;
state.isLoggedIn = true;
state.refreshInterval = setInterval(() => {
refreshAuth();
}, 2 * 60000);
localStorage.setItem('kiosk-userdata', JSON.stringify(state));
OpenAPI.TOKEN = resAuth.access_token;
userState.set(state);
return state;
}
async function refreshAuth() {
try {
const authRes = (await AuthService.authControllerRefresh({
token: state.refresh_token
})) as ResponseAuth;
OpenAPI.TOKEN = authRes.access_token;
} catch {
logout();
}
}
async function loginFromStorage() {
const storagedata = localStorage.getItem('kiosk-userdata');
const userdata = JSON.parse(storagedata || '{}') as UserState;
if (!userdata.access_token) {
throw new Error('Unauthorized');
}
state.access_token = userdata.access_token;
state.refresh_token = userdata.refresh_token;
state.isLoggedIn = true;
state.refreshInterval = setInterval(() => {
refreshAuth();
}, 2 * 60000);
OpenAPI.TOKEN = userdata.access_token;
userState.set(state);
return state;
}
async function logout() {
state.isLoggedIn = false;
state.access_token = '';
state.refresh_token = '';
state.refreshInterval = undefined;
localStorage.clear();
return state;
}
export { auth_login, logout, loginFromStorage, refreshAuth, userState };

View File

@ -2,10 +2,18 @@
import { OpenAPI } from '@odit/lfk-client-js'; import { OpenAPI } from '@odit/lfk-client-js';
import { env } from '$env/dynamic/public'; import { env } from '$env/dynamic/public';
import '../app.postcss'; import '../app.postcss';
import "@fontsource/athiti" import '@fontsource/athiti';
import Footer from '../components/footer.svelte'; import { onMount } from 'svelte';
OpenAPI.BASE = env.PUBLIC_BASE_URL || 'https://run.lauf-fuer-kaya.de'; OpenAPI.BASE = env.PUBLIC_BASE_URL || 'https://run.lauf-fuer-kaya.de';
onMount(() => {
window.addEventListener('keydown', (e) => {
// F1
if (e.keyCode === 112) e.preventDefault();
// F5
if (e.keyCode === 116) e.preventDefault();
});
});
</script> </script>
<div class="dark:bg-slate-900 flex flex-col h-screen"> <div class="dark:bg-slate-900 flex flex-col h-screen">

View File

@ -1,41 +1,45 @@
<!-- Hero --> <script lang="ts">
<div import { loginFromStorage, userState } from '$lib/userstore';
class="relative overflow-hidden before:absolute before:top-0 before:left-1/2 before:bg-[url('/assets/polygon.svg')] before:bg-no-repeat before:bg-top before:bg-cover before:w-full before:h-full before:-z-[1] before:transform before:-translate-x-1/2 dark:before:bg-[url('/assets/polygon-dark.svg')]" import Register from './Register.svelte';
> import { onMount } from 'svelte';
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10"> import Login from './Login.svelte';
<!-- Title -->
<div class="mt-5 max-w-2xl text-center mx-auto">
<h1 class="block font-bold text-gray-800 text-4xl md:text-5xl lg:text-6xl dark:text-gray-200">
LfK! Selfservice
<span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent"
>Kiosk</span
>
</h1>
</div>
<!-- End Title -->
<div class="mt-5 max-w-3xl text-center mx-auto"> onMount(() => {
<p class="text-lg text-gray-600 dark:text-gray-400">Für die Anmeldung vor Ort</p> loginFromStorage();
</div> });
</script>
<!-- Buttons --> {#if $userState.isLoggedIn}
<div class="mt-8 grid gap-3 w-full sm:inline-flex sm:justify-center"> <Register />
<a {:else}
class="inline-flex justify-center items-center gap-x-3 text-center bg-gradient-to-tl from-blue-600 to-violet-600 hover:from-violet-600 hover:to-blue-600 border border-transparent text-white text-sm font-medium rounded-md focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2 focus:ring-offset-white py-3 px-4 dark:focus:ring-offset-gray-800" <Login />
href="./login" {/if}
> <div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white select-none">
Kiosk starten {#if $userState.isLoggedIn}
<svg class="w-3 h-3" width="16" height="16" viewBox="0 0 16 16" fill="none"> <b class="font-bold">LfK!2023</b> powered by
<path <b class="font-bold">ODIT.Services</b>
d="M5.27921 2L10.9257 7.64645C11.1209 7.84171 11.1209 8.15829 10.9257 8.35355L5.27921 14" {:else}
stroke="currentColor" <a
stroke-width="2" rel="noopener noreferrer"
stroke-linecap="round" target="_blank"
/> href="https://lauf-fuer-kaya.de/datenschutz/"
</svg> class="underline">Datenschutzerklärung</a
</a> >
</div> |
<!-- End Buttons --> <a
</div> rel="noopener noreferrer"
target="_blank"
href="https://lauf-fuer-kaya.de/impressum/"
class="underline">Impressum</a
>
<br />
<br />
<b class="font-bold">LfK!2023</b> powered by
<a
rel="noopener noreferrer"
target="_blank"
href="https://odit.services?ref=lfk"
class="underline">ODIT.Services</a
>
{/if}
</div> </div>
<!-- End Hero -->

120
src/routes/Login.svelte Normal file
View File

@ -0,0 +1,120 @@
<script lang="ts">
import { auth_login, loginFromStorage } from '$lib/userstore';
import { AuthService } from '@odit/lfk-client-js';
import { onMount } from 'svelte';
$: username = '';
$: password = '';
$: loginError = false;
onMount(() => {
loginFromStorage();
});
async function login() {
try {
const auth = (await AuthService.authControllerLogin({
username,
password
})) as import('@odit/lfk-client-js').ResponseAuth;
loginError = false;
auth_login(auth);
} catch (error) {
loginError = true;
}
}
</script>
<!-- -->
<div
class="relative overflow-hidden before:absolute before:top-0 before:left-1/2 before:bg-[url('/assets/polygon.svg')] before:bg-no-repeat before:bg-top before:bg-cover before:w-full before:h-full before:-z-[1] before:transform before:-translate-x-1/2 dark:before:bg-[url('/assets/polygon-dark.svg')]"
>
<div class="max-w-[85rem] mx-auto px-4 sm:px-6 lg:px-8 pt-24 pb-10">
<!-- Title -->
<div class="mt-5 max-w-2xl text-center mx-auto">
<h1 class="block font-bold text-gray-800 text-4xl md:text-5xl lg:text-6xl dark:text-gray-200">
LfK! Selfservice
<span class="bg-clip-text bg-gradient-to-tl from-blue-600 to-violet-600 text-transparent"
>Kiosk</span
>
</h1>
</div>
<!-- End Title -->
<div class="mt-5 max-w-3xl text-center mx-auto">
<p class="text-lg text-gray-600 dark:text-gray-400">Für die Anmeldung vor Ort</p>
</div>
<div class="w-full max-w-md mx-auto p-6">
<div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700"
>
<div class="p-4 sm:p-7">
<div class="text-center mb-8">
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Anmeldung</h1>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Hierfür wird ein LfK Läufersystem Account benötigt
</p>
</div>
{#if loginError}
<div
class="bg-red-500 text-sm text-white text-center font-semibold rounded-md shadow-lg mb-8"
role="alert"
>
<div class="p-4">Falscher Nutzername oder falsches Passwort</div>
</div>
{/if}
<!-- Form -->
<form on:submit|preventDefault={login}>
<div class="grid gap-y-4">
<!-- Form Group -->
<div>
<label for="username" class="block text-sm mb-2 dark:text-white">Benutzername</label
>
<div class="relative">
<input
bind:value={username}
type="username"
id="username"
name="username"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="username-error"
/>
</div>
</div>
<!-- End Form Group -->
<!-- Form Group -->
<div>
<div class="flex justify-between items-center">
<label for="password" class="block text-sm mb-2 dark:text-white">Passwort</label>
</div>
<div class="relative">
<input
bind:value={password}
type="password"
id="password"
name="password"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="password-error"
/>
</div>
</div>
<!-- End Form Group -->
<button
type="submit"
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Anmelden</button
>
</div>
</form>
<!-- End Form -->
</div>
</div>
</div>
</div>
</div>

View File

@ -2,15 +2,33 @@
import { RunnerService, type ResponseRunner } from '@odit/lfk-client-js'; import { RunnerService, type ResponseRunner } from '@odit/lfk-client-js';
import bwipjs from 'bwip-js'; import bwipjs from 'bwip-js';
import lfkbackground from './background.png'; import lfkbackground from './background.png';
import { onMount } from 'svelte';
$: firstname = ''; $: firstname = '';
$: lastname = ''; $: lastname = '';
$: doneButtonEnabled = false;
$: showResult = false; $: showResult = false;
$: showError = false;
let response: ResponseRunner; let response: ResponseRunner;
const group = 1; //Default to Bürgerlauf const group = 1; //Default to Bürgerlauf
function focusFirstName() {
setTimeout(() => {
document.getElementById('firstname')?.focus();
}, 50);
setTimeout(() => {
document.getElementById('firstname')?.focus();
}, 100);
}
function focusDoneButton() {
setTimeout(() => {
document.getElementById('done')?.focus();
}, 50);
setTimeout(() => {
document.getElementById('done')?.focus();
}, 100);
}
async function register() { async function register() {
try { try {
response = (await RunnerService.runnerControllerPost({ response = (await RunnerService.runnerControllerPost({
@ -18,12 +36,18 @@
lastname, lastname,
group group
})) as ResponseRunner; })) as ResponseRunner;
showError = false;
showResult = true; showResult = true;
setTimeout(() => {
doneButtonEnabled = true;
setTimeout(() => {
focusDoneButton();
}, 25);
}, 7500);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
showError = true;
showResult = false; showResult = false;
localStorage.clear();
location.reload();
} }
firstname = ''; firstname = '';
lastname = ''; lastname = '';
@ -46,10 +70,14 @@
}); });
return canvas.toDataURL('image/png'); return canvas.toDataURL('image/png');
} }
onMount(() => {
focusFirstName();
});
</script> </script>
<div <div
class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16" class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16 select-none"
style="background: url({lfkbackground});background-position: center center!important;background-size: contain!important;background-repeat: no-repeat!important;" style="background: url({lfkbackground});background-position: center center!important;background-size: contain!important;background-repeat: no-repeat!important;"
> >
<div class="w-full max-w-md mx-auto p-6"> <div class="w-full max-w-md mx-auto p-6">
@ -72,6 +100,11 @@
<label for="firstname" class="block text-lg font-bold mb-2 sr-only">Vorname</label> <label for="firstname" class="block text-lg font-bold mb-2 sr-only">Vorname</label>
<div class="relative"> <div class="relative">
<input <input
on:keydown={(e) => {
if (e.keyCode === 13) {
document.getElementById('lastname')?.focus();
}
}}
type="text" type="text"
id="firstname" id="firstname"
name="firstname" name="firstname"
@ -154,7 +187,7 @@
<button <button
type="submit" type="submit"
disabled={!firstname || !lastname} disabled={!firstname || !lastname}
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold disabled:opacity-70 bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all dark:focus:ring-offset-gray-800" class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold disabled:opacity-70 bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all dark:focus:ring-offset-gray-800"
>Anmelden</button >Anmelden</button
> >
</div> </div>
@ -178,8 +211,13 @@
<div class="mx-auto text-center items-center"> <div class="mx-auto text-center items-center">
<button <button
class:opacity-50={!doneButtonEnabled}
disabled={!doneButtonEnabled}
id="done"
on:click={() => { on:click={() => {
doneButtonEnabled = false;
showResult = false; showResult = false;
focusFirstName();
}} }}
class="w-full py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800" class="w-full py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Fertig</button >Fertig</button
@ -191,27 +229,3 @@
</div> </div>
</div> </div>
</div> </div>
<div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white">
<a
rel="noopener noreferrer"
target="_blank"
href="https://lauf-fuer-kaya.de/datenschutz/"
class="underline">Datenschutzerklärung</a
>
|
<a
rel="noopener noreferrer"
target="_blank"
href="https://lauf-fuer-kaya.de/impressum/"
class="underline">Impressum</a
>
<br />
<br />
<b class="font-bold">LfK!2023</b> powered by
<a
rel="noopener noreferrer"
target="_blank"
href="https://odit.services?ref=lfk"
class="underline">ODIT.Services</a
>
</div>

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -1,95 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import userstore from '$lib/userstore';
import { AuthService } from '@odit/lfk-client-js';
$: username = '';
$: password = '';
$: loginError = false;
async function login() {
try {
const auth = (await AuthService.authControllerLogin({
username,
password
})) as import('@odit/lfk-client-js').ResponseAuth;
loginError=false;
await userstore.login(auth);
goto('./registration', {replaceState: true})
} catch (error) {
console.log(error);
loginError = true;
}
}
</script>
<div class="dark:bg-slate-900 bg-gray-100 flex h-full items-center py-16">
<div class="w-full max-w-md mx-auto p-6">
<div
class="mt-7 bg-white border border-gray-200 rounded-xl shadow-sm dark:bg-gray-800 dark:border-gray-700"
>
<div class="p-4 sm:p-7">
<div class="text-center mb-8">
<h1 class="block text-2xl font-bold text-gray-800 dark:text-white">Anmeldung</h1>
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">
Hierfür wird ein LfK Läufersystem Account benötigt
</p>
</div>
{#if loginError}
<div class="bg-red-500 text-sm text-white text-center font-semibold rounded-md shadow-lg mb-8" role="alert">
<div class="p-4">Falscher Nutzername oder falsches Passwort</div>
</div>
{/if}
<!-- Form -->
<form on:submit|preventDefault={login}>
<div class="grid gap-y-4">
<!-- Form Group -->
<div>
<label for="username" class="block text-sm mb-2 dark:text-white">Benutzername</label>
<div class="relative">
<input
bind:value={username}
type="username"
id="username"
name="username"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="username-error"
/>
</div>
</div>
<!-- End Form Group -->
<!-- Form Group -->
<div>
<div class="flex justify-between items-center">
<label for="password" class="block text-sm mb-2 dark:text-white">Passwort</label>
</div>
<div class="relative">
<input
bind:value={password}
type="password"
id="password"
name="password"
class="py-3 px-4 block w-full border-gray-200 rounded-md text-sm focus:border-blue-500 focus:ring-blue-500 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 border"
required
aria-describedby="password-error"
/>
</div>
</div>
<!-- End Form Group -->
<button
type="submit"
class="py-3 px-4 inline-flex justify-center items-center gap-2 rounded-md border border-transparent font-semibold bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-all text-sm dark:focus:ring-offset-gray-800"
>Anmelden</button
>
</div>
</form>
<!-- End Form -->
</div>
</div>
</div>
</div>

View File

@ -1,26 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
import userstore from '$lib/userstore';
import { onMount } from 'svelte';
$: loginRendered = false;
onMount(async () => {
try {
await userstore.loginFromStorage();
loginRendered = true;
} catch (error) {
console.log(error);
userstore.logout();
goto('./login', {replaceState: true})
}
});
</script>
{#if loginRendered}
<slot />
{:else}
<div class="mx-auto mt-20">
<h1 class="block text-center text-2xl font-bold text-gray-800 dark:text-white">Lade Anmeldedaten...</h1>
</div>
{/if}