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:
commit
72ace57cb3
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.
|
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)
|
||||||
|
@ -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
|
||||||
|
```
|
@ -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",
|
||||||
|
@ -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>
|
|
@ -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 };
|
||||||
|
@ -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">
|
||||||
|
@ -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
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 { 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>
|
|
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}
|
|
Loading…
x
Reference in New Issue
Block a user