Merge branch 'main' of git.odit.services:lfk/kiosk
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				ci/woodpecker/push/build Pipeline was successful
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	ci/woodpecker/push/build Pipeline was successful
				
			This commit is contained in:
		
							
								
								
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -2,8 +2,36 @@
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
> 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)
 | 
			
		||||
 | 
			
		||||
#### [0.4.3](https://git.odit.services/lfk/kiosk/compare/0.4.2...0.4.3)
 | 
			
		||||
 
 | 
			
		||||
@@ -25,3 +25,8 @@ pnpm build
 | 
			
		||||
docker build .
 | 
			
		||||
docker-compose up
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Kiosk Google Chrome
 | 
			
		||||
```
 | 
			
		||||
chrome https://run.lauf-fuer-kaya.de/kiosk/ -kiosk
 | 
			
		||||
```
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "@lfk/kiosk",
 | 
			
		||||
	"version": "0.4.4",
 | 
			
		||||
	"version": "1.0.0",
 | 
			
		||||
	"private": false,
 | 
			
		||||
	"license": "MIT",
 | 
			
		||||
	"repository": "https://git.odit.services/lfk/kiosk",
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
@@ -5,22 +5,16 @@ type UserState = {
 | 
			
		||||
	access_token: string;
 | 
			
		||||
	refresh_token: string;
 | 
			
		||||
	isLoggedIn: boolean;
 | 
			
		||||
    refreshInterval: NodeJS.Timer | undefined
 | 
			
		||||
	refreshInterval: NodeJS.Timer | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const userStore = () => {
 | 
			
		||||
const state: UserState = {
 | 
			
		||||
	access_token: '',
 | 
			
		||||
	refresh_token: '',
 | 
			
		||||
	isLoggedIn: false,
 | 
			
		||||
	refreshInterval: undefined
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    const { subscribe, set, update } = writable(state);
 | 
			
		||||
 | 
			
		||||
    const methods = {
 | 
			
		||||
        async login(resAuth: ResponseAuth) {
 | 
			
		||||
            update((state: UserState) => {
 | 
			
		||||
const userState = writable(state);
 | 
			
		||||
async function auth_login(resAuth: ResponseAuth) {
 | 
			
		||||
	if (!resAuth) {
 | 
			
		||||
		return state;
 | 
			
		||||
	}
 | 
			
		||||
@@ -29,66 +23,48 @@ const userStore = () => {
 | 
			
		||||
	state.refresh_token = resAuth.refresh_token;
 | 
			
		||||
	state.isLoggedIn = true;
 | 
			
		||||
	state.refreshInterval = setInterval(() => {
 | 
			
		||||
                    this.refreshAuth();
 | 
			
		||||
                }, 2 * 60000)
 | 
			
		||||
		refreshAuth();
 | 
			
		||||
	}, 2 * 60000);
 | 
			
		||||
 | 
			
		||||
	localStorage.setItem('kiosk-userdata', JSON.stringify(state));
 | 
			
		||||
                localStorage.setItem('kiosk-access_token', state.access_token);
 | 
			
		||||
	OpenAPI.TOKEN = resAuth.access_token;
 | 
			
		||||
	userState.set(state);
 | 
			
		||||
	return state;
 | 
			
		||||
            });
 | 
			
		||||
        },
 | 
			
		||||
        async refreshAuth() {
 | 
			
		||||
}
 | 
			
		||||
async function refreshAuth() {
 | 
			
		||||
	try {
 | 
			
		||||
                const authRes = await AuthService.authControllerRefresh({ token: state.refresh_token }) as ResponseAuth;
 | 
			
		||||
		const authRes = (await AuthService.authControllerRefresh({
 | 
			
		||||
			token: state.refresh_token
 | 
			
		||||
		})) as ResponseAuth;
 | 
			
		||||
		OpenAPI.TOKEN = authRes.access_token;
 | 
			
		||||
	} catch {
 | 
			
		||||
                this.logout();
 | 
			
		||||
		logout();
 | 
			
		||||
	}
 | 
			
		||||
        },
 | 
			
		||||
        async loginFromStorage() {
 | 
			
		||||
            console.log('loginFromStorage');
 | 
			
		||||
            const access_token = localStorage.getItem('kiosk-access_token');
 | 
			
		||||
            if (!access_token) {
 | 
			
		||||
}
 | 
			
		||||
async function loginFromStorage() {
 | 
			
		||||
	const storagedata = localStorage.getItem('kiosk-userdata');
 | 
			
		||||
	const userdata = JSON.parse(storagedata || '{}') as UserState;
 | 
			
		||||
	if (!userdata.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.access_token = userdata.access_token;
 | 
			
		||||
	state.refresh_token = userdata.refresh_token;
 | 
			
		||||
	state.isLoggedIn = true;
 | 
			
		||||
	state.refreshInterval = setInterval(() => {
 | 
			
		||||
                    this.refreshAuth();
 | 
			
		||||
		refreshAuth();
 | 
			
		||||
	}, 2 * 60000);
 | 
			
		||||
	OpenAPI.TOKEN = userdata.access_token;
 | 
			
		||||
 | 
			
		||||
	userState.set(state);
 | 
			
		||||
	return state;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            await this.refreshAuth();
 | 
			
		||||
        },
 | 
			
		||||
        async logout() {
 | 
			
		||||
            update((state: UserState) => {
 | 
			
		||||
}
 | 
			
		||||
async function logout() {
 | 
			
		||||
	state.isLoggedIn = false;
 | 
			
		||||
	state.access_token = '';
 | 
			
		||||
	state.refresh_token = '';
 | 
			
		||||
	state.refreshInterval = undefined;
 | 
			
		||||
	localStorage.clear();
 | 
			
		||||
	return state;
 | 
			
		||||
            });
 | 
			
		||||
}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        subscribe,
 | 
			
		||||
        set,
 | 
			
		||||
        update,
 | 
			
		||||
        state,
 | 
			
		||||
        ...methods
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default userStore();
 | 
			
		||||
export { auth_login, logout, loginFromStorage, refreshAuth, userState };
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,18 @@
 | 
			
		||||
	import { OpenAPI } from '@odit/lfk-client-js';
 | 
			
		||||
	import { env } from '$env/dynamic/public';
 | 
			
		||||
	import '../app.postcss';
 | 
			
		||||
	import "@fontsource/athiti"
 | 
			
		||||
	import Footer from '../components/footer.svelte';
 | 
			
		||||
	import '@fontsource/athiti';
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
 | 
			
		||||
	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>
 | 
			
		||||
 | 
			
		||||
<div class="dark:bg-slate-900 flex flex-col h-screen">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,41 +1,45 @@
 | 
			
		||||
<!-- Hero -->
 | 
			
		||||
<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 -->
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import { loginFromStorage, userState } from '$lib/userstore';
 | 
			
		||||
	import Register from './Register.svelte';
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
	import Login from './Login.svelte';
 | 
			
		||||
 | 
			
		||||
		<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>
 | 
			
		||||
	onMount(() => {
 | 
			
		||||
		loginFromStorage();
 | 
			
		||||
	});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
		<!-- Buttons -->
 | 
			
		||||
		<div class="mt-8 grid gap-3 w-full sm:inline-flex sm:justify-center">
 | 
			
		||||
{#if $userState.isLoggedIn}
 | 
			
		||||
	<Register />
 | 
			
		||||
{:else}
 | 
			
		||||
	<Login />
 | 
			
		||||
{/if}
 | 
			
		||||
<div class="fixed bottom-0 w-full text-center text-xl p-4 dark:text-white select-none">
 | 
			
		||||
	{#if $userState.isLoggedIn}
 | 
			
		||||
		<b class="font-bold">LfK!2023</b> powered by
 | 
			
		||||
		<b class="font-bold">ODIT.Services</b>
 | 
			
		||||
	{:else}
 | 
			
		||||
		<a
 | 
			
		||||
				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"
 | 
			
		||||
				href="./login"
 | 
			
		||||
			rel="noopener noreferrer"
 | 
			
		||||
			target="_blank"
 | 
			
		||||
			href="https://lauf-fuer-kaya.de/datenschutz/"
 | 
			
		||||
			class="underline">Datenschutzerklärung</a
 | 
			
		||||
		>
 | 
			
		||||
				Kiosk starten
 | 
			
		||||
				<svg class="w-3 h-3" width="16" height="16" viewBox="0 0 16 16" fill="none">
 | 
			
		||||
					<path
 | 
			
		||||
						d="M5.27921 2L10.9257 7.64645C11.1209 7.84171 11.1209 8.15829 10.9257 8.35355L5.27921 14"
 | 
			
		||||
						stroke="currentColor"
 | 
			
		||||
						stroke-width="2"
 | 
			
		||||
						stroke-linecap="round"
 | 
			
		||||
					/>
 | 
			
		||||
				</svg>
 | 
			
		||||
			</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
 | 
			
		||||
		>
 | 
			
		||||
	{/if}
 | 
			
		||||
</div>
 | 
			
		||||
		<!-- End Buttons -->
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
<!-- End Hero -->
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										120
									
								
								src/routes/Login.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/routes/Login.svelte
									
									
									
									
									
										Normal 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>
 | 
			
		||||
@@ -2,15 +2,33 @@
 | 
			
		||||
	import { RunnerService, type ResponseRunner } from '@odit/lfk-client-js';
 | 
			
		||||
	import bwipjs from 'bwip-js';
 | 
			
		||||
	import lfkbackground from './background.png';
 | 
			
		||||
	import { onMount } from 'svelte';
 | 
			
		||||
 | 
			
		||||
	$: firstname = '';
 | 
			
		||||
	$: lastname = '';
 | 
			
		||||
	$: doneButtonEnabled = false;
 | 
			
		||||
	$: showResult = false;
 | 
			
		||||
	$: showError = false;
 | 
			
		||||
 | 
			
		||||
	let response: ResponseRunner;
 | 
			
		||||
	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() {
 | 
			
		||||
		try {
 | 
			
		||||
			response = (await RunnerService.runnerControllerPost({
 | 
			
		||||
@@ -18,12 +36,18 @@
 | 
			
		||||
				lastname,
 | 
			
		||||
				group
 | 
			
		||||
			})) as ResponseRunner;
 | 
			
		||||
			showError = false;
 | 
			
		||||
			showResult = true;
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				doneButtonEnabled = true;
 | 
			
		||||
				setTimeout(() => {
 | 
			
		||||
					focusDoneButton();
 | 
			
		||||
				}, 25);
 | 
			
		||||
			}, 7500);
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.log(error);
 | 
			
		||||
			showError = true;
 | 
			
		||||
			showResult = false;
 | 
			
		||||
			localStorage.clear();
 | 
			
		||||
			location.reload();
 | 
			
		||||
		}
 | 
			
		||||
		firstname = '';
 | 
			
		||||
		lastname = '';
 | 
			
		||||
@@ -46,10 +70,14 @@
 | 
			
		||||
		});
 | 
			
		||||
		return canvas.toDataURL('image/png');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	onMount(() => {
 | 
			
		||||
		focusFirstName();
 | 
			
		||||
	});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<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;"
 | 
			
		||||
>
 | 
			
		||||
	<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>
 | 
			
		||||
								<div class="relative">
 | 
			
		||||
									<input
 | 
			
		||||
										on:keydown={(e) => {
 | 
			
		||||
											if (e.keyCode === 13) {
 | 
			
		||||
												document.getElementById('lastname')?.focus();
 | 
			
		||||
											}
 | 
			
		||||
										}}
 | 
			
		||||
										type="text"
 | 
			
		||||
										id="firstname"
 | 
			
		||||
										name="firstname"
 | 
			
		||||
@@ -178,8 +211,13 @@
 | 
			
		||||
 | 
			
		||||
					<div class="mx-auto text-center items-center">
 | 
			
		||||
						<button
 | 
			
		||||
							class:opacity-50={!doneButtonEnabled}
 | 
			
		||||
							disabled={!doneButtonEnabled}
 | 
			
		||||
							id="done"
 | 
			
		||||
							on:click={() => {
 | 
			
		||||
								doneButtonEnabled = 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"
 | 
			
		||||
							>Fertig</button
 | 
			
		||||
@@ -191,27 +229,3 @@
 | 
			
		||||
		</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>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB  | 
@@ -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>
 | 
			
		||||
@@ -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}
 | 
			
		||||
		Reference in New Issue
	
	Block a user