Compare commits
	
		
			4 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e2d7de1e9e | |||
| d7c9c27ec7 | |||
| 153b1b3c2b | |||
| ec63c7c1c5 | 
							
								
								
									
										14
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -2,9 +2,23 @@ | |||||||
|  |  | ||||||
| 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.9.10](https://git.odit.services/lfk/frontend/compare/1.9.9...1.9.10) | ||||||
|  |  | ||||||
|  | - feat: add experimental ui for mobile card assignment [`d7c9c27`](https://git.odit.services/lfk/frontend/commit/d7c9c27ec7a1fea1cbaf26914843d044bbae32fe) | ||||||
|  |  | ||||||
|  | #### [1.9.9](https://git.odit.services/lfk/frontend/compare/1.9.8...1.9.9) | ||||||
|  |  | ||||||
|  | > 4 April 2025 | ||||||
|  |  | ||||||
|  | - chore(release): 1.9.9 [`153b1b3`](https://git.odit.services/lfk/frontend/commit/153b1b3c2badee4826be614c3dbaafc10e1fbfea) | ||||||
|  | - fix(CopyScanStationTokenModal): code sizes [`ec63c7c`](https://git.odit.services/lfk/frontend/commit/ec63c7c1c51ccaf25bdd1eacffda66c820003a4c) | ||||||
|  |  | ||||||
| #### [1.9.8](https://git.odit.services/lfk/frontend/compare/1.9.7...1.9.8) | #### [1.9.8](https://git.odit.services/lfk/frontend/compare/1.9.7...1.9.8) | ||||||
|  |  | ||||||
|  | > 2 April 2025 | ||||||
|  |  | ||||||
| - feat(GenerateSponsoringContracts): show download progress [`e261d5e`](https://git.odit.services/lfk/frontend/commit/e261d5e345f3175672bf86646ed838dd23400e50) | - feat(GenerateSponsoringContracts): show download progress [`e261d5e`](https://git.odit.services/lfk/frontend/commit/e261d5e345f3175672bf86646ed838dd23400e50) | ||||||
|  | - chore(release): 1.9.8 [`05c2535`](https://git.odit.services/lfk/frontend/commit/05c253569877a45f3c4759262255ca70aa9ee4a3) | ||||||
|  |  | ||||||
| #### [1.9.7](https://git.odit.services/lfk/frontend/compare/1.9.6...1.9.7) | #### [1.9.7](https://git.odit.services/lfk/frontend/compare/1.9.6...1.9.7) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
|  |  | ||||||
|   <body> |   <body> | ||||||
|     <span style="display: none; visibility: hidden" id="buildinfo" |     <span style="display: none; visibility: hidden" id="buildinfo" | ||||||
|       >RELEASE_INFO-1.9.8-RELEASE_INFO</span |       >RELEASE_INFO-1.9.10-RELEASE_INFO</span | ||||||
|     > |     > | ||||||
|     <noscript>You need to enable JavaScript to run this app.</noscript> |     <noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
|     <script src="/env.js"></script> |     <script src="/env.js"></script> | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "@odit/lfk-frontend", |   "name": "@odit/lfk-frontend", | ||||||
|   "version": "1.9.8", |   "version": "1.9.10", | ||||||
|   "type": "module", |   "type": "module", | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "i18n-order": "node order.js", |     "i18n-order": "node order.js", | ||||||
| @@ -49,6 +49,7 @@ | |||||||
|     "bwip-js": "3.4.0", |     "bwip-js": "3.4.0", | ||||||
|     "check-password-strength": "2.0.10", |     "check-password-strength": "2.0.10", | ||||||
|     "csvtojson": "2.0.10", |     "csvtojson": "2.0.10", | ||||||
|  |     "html5-qrcode": "^2.3.8", | ||||||
|     "localforage": "1.10.0", |     "localforage": "1.10.0", | ||||||
|     "marked": "4.3.0", |     "marked": "4.3.0", | ||||||
|     "svelte": "3.58.0", |     "svelte": "3.58.0", | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										26
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							| @@ -29,6 +29,9 @@ importers: | |||||||
|       csvtojson: |       csvtojson: | ||||||
|         specifier: 2.0.10 |         specifier: 2.0.10 | ||||||
|         version: 2.0.10 |         version: 2.0.10 | ||||||
|  |       html5-qrcode: | ||||||
|  |         specifier: ^2.3.8 | ||||||
|  |         version: 2.3.8 | ||||||
|       localforage: |       localforage: | ||||||
|         specifier: 1.10.0 |         specifier: 1.10.0 | ||||||
|         version: 1.10.0 |         version: 1.10.0 | ||||||
| @@ -77,7 +80,7 @@ importers: | |||||||
|         version: 3.3.3(prettier@3.5.3)(svelte@3.58.0) |         version: 3.3.3(prettier@3.5.3)(svelte@3.58.0) | ||||||
|       release-it: |       release-it: | ||||||
|         specifier: 17.10.0 |         specifier: 17.10.0 | ||||||
|         version: 17.10.0 |         version: 17.10.0(typescript@5.8.3) | ||||||
|       svelte-select: |       svelte-select: | ||||||
|         specifier: 3.17.0 |         specifier: 3.17.0 | ||||||
|         version: 3.17.0 |         version: 3.17.0 | ||||||
| @@ -924,6 +927,9 @@ packages: | |||||||
|     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} |     resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} | ||||||
|     engines: {node: '>= 0.4'} |     engines: {node: '>= 0.4'} | ||||||
|  |  | ||||||
|  |   html5-qrcode@2.3.8: | ||||||
|  |     resolution: {integrity: sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==} | ||||||
|  |  | ||||||
|   http-proxy-agent@7.0.2: |   http-proxy-agent@7.0.2: | ||||||
|     resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} |     resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} | ||||||
|     engines: {node: '>= 14'} |     engines: {node: '>= 14'} | ||||||
| @@ -1794,6 +1800,11 @@ packages: | |||||||
|   type@2.7.2: |   type@2.7.2: | ||||||
|     resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} |     resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==} | ||||||
|  |  | ||||||
|  |   typescript@5.8.3: | ||||||
|  |     resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} | ||||||
|  |     engines: {node: '>=14.17'} | ||||||
|  |     hasBin: true | ||||||
|  |  | ||||||
|   uglify-js@3.19.3: |   uglify-js@3.19.3: | ||||||
|     resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} |     resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} | ||||||
|     engines: {node: '>=0.8.0'} |     engines: {node: '>=0.8.0'} | ||||||
| @@ -2439,12 +2450,14 @@ snapshots: | |||||||
|       graceful-fs: 4.2.11 |       graceful-fs: 4.2.11 | ||||||
|       xdg-basedir: 5.1.0 |       xdg-basedir: 5.1.0 | ||||||
|  |  | ||||||
|   cosmiconfig@9.0.0: |   cosmiconfig@9.0.0(typescript@5.8.3): | ||||||
|     dependencies: |     dependencies: | ||||||
|       env-paths: 2.2.1 |       env-paths: 2.2.1 | ||||||
|       import-fresh: 3.3.0 |       import-fresh: 3.3.0 | ||||||
|       js-yaml: 4.1.0 |       js-yaml: 4.1.0 | ||||||
|       parse-json: 5.2.0 |       parse-json: 5.2.0 | ||||||
|  |     optionalDependencies: | ||||||
|  |       typescript: 5.8.3 | ||||||
|  |  | ||||||
|   crc-32@1.2.2: {} |   crc-32@1.2.2: {} | ||||||
|  |  | ||||||
| @@ -2765,6 +2778,8 @@ snapshots: | |||||||
|     dependencies: |     dependencies: | ||||||
|       function-bind: 1.1.2 |       function-bind: 1.1.2 | ||||||
|  |  | ||||||
|  |   html5-qrcode@2.3.8: {} | ||||||
|  |  | ||||||
|   http-proxy-agent@7.0.2: |   http-proxy-agent@7.0.2: | ||||||
|     dependencies: |     dependencies: | ||||||
|       agent-base: 7.1.1 |       agent-base: 7.1.1 | ||||||
| @@ -3322,14 +3337,14 @@ snapshots: | |||||||
|     dependencies: |     dependencies: | ||||||
|       rc: 1.2.8 |       rc: 1.2.8 | ||||||
|  |  | ||||||
|   release-it@17.10.0: |   release-it@17.10.0(typescript@5.8.3): | ||||||
|     dependencies: |     dependencies: | ||||||
|       '@iarna/toml': 2.2.5 |       '@iarna/toml': 2.2.5 | ||||||
|       '@octokit/rest': 20.1.1 |       '@octokit/rest': 20.1.1 | ||||||
|       async-retry: 1.3.3 |       async-retry: 1.3.3 | ||||||
|       chalk: 5.3.0 |       chalk: 5.3.0 | ||||||
|       ci-info: 4.1.0 |       ci-info: 4.1.0 | ||||||
|       cosmiconfig: 9.0.0 |       cosmiconfig: 9.0.0(typescript@5.8.3) | ||||||
|       execa: 8.0.0 |       execa: 8.0.0 | ||||||
|       git-url-parse: 14.0.0 |       git-url-parse: 14.0.0 | ||||||
|       globby: 14.0.2 |       globby: 14.0.2 | ||||||
| @@ -3607,6 +3622,9 @@ snapshots: | |||||||
|  |  | ||||||
|   type@2.7.2: {} |   type@2.7.2: {} | ||||||
|  |  | ||||||
|  |   typescript@5.8.3: | ||||||
|  |     optional: true | ||||||
|  |  | ||||||
|   uglify-js@3.19.3: |   uglify-js@3.19.3: | ||||||
|     optional: true |     optional: true | ||||||
|  |  | ||||||
|   | |||||||
| @@ -41,6 +41,7 @@ | |||||||
|   import Settings from "./components/settings/Settings.svelte"; |   import Settings from "./components/settings/Settings.svelte"; | ||||||
|   import Transition from "./components/base/Transition.svelte"; |   import Transition from "./components/base/Transition.svelte"; | ||||||
|   import Orgs from "./components/orgs/Orgs.svelte"; |   import Orgs from "./components/orgs/Orgs.svelte"; | ||||||
|  |   import CardAssignment from "./components/general/CardAssignment.svelte"; | ||||||
|   import Runners from "./components/runners/Runners.svelte"; |   import Runners from "./components/runners/Runners.svelte"; | ||||||
|   import Footer from "./components/general/Footer.svelte"; |   import Footer from "./components/general/Footer.svelte"; | ||||||
|   import TracksOverview from "./components/tracks/TracksOverview.svelte"; |   import TracksOverview from "./components/tracks/TracksOverview.svelte"; | ||||||
| @@ -141,6 +142,11 @@ | |||||||
|             <RunnerDetail {params} /> |             <RunnerDetail {params} /> | ||||||
|           </Route> |           </Route> | ||||||
|         </Route> |         </Route> | ||||||
|  |         <Route path="/cardassignment/*"> | ||||||
|  |           <Route path="/"> | ||||||
|  |             <CardAssignment /> | ||||||
|  |           </Route> | ||||||
|  |         </Route> | ||||||
|         <Route path="/teams/*"> |         <Route path="/teams/*"> | ||||||
|           <Route path="/"> |           <Route path="/"> | ||||||
|             <Teams /> |             <Teams /> | ||||||
|   | |||||||
							
								
								
									
										72
									
								
								src/components/general/CardAssignment.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/components/general/CardAssignment.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | |||||||
|  | <script> | ||||||
|  | 	import QrCodeScanner from "./QrCodeScanner.svelte"; | ||||||
|  | 	let state = "scan_runner"; | ||||||
|  | 	let runnerID = undefined; | ||||||
|  | 	let cardInfo = ""; | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div class="p-4"> | ||||||
|  | 	<h3 class="text-3xl font-bold">Card Assignment for Mobile</h3> | ||||||
|  | 	{#if state === "done"} | ||||||
|  | 		<p>Assigned Card {cardInfo} ✅</p> | ||||||
|  | 		<p>(not really, needs to be implemented)</p> | ||||||
|  | 	{:else} | ||||||
|  | 		<!--  --> | ||||||
|  | 		{#if state === "scan_runner"} | ||||||
|  | 			<h3 class="text-xl font-bold">Scan Runner (Selfservice QR)</h3> | ||||||
|  | 		{/if} | ||||||
|  | 		{#if state === "scan_card"} | ||||||
|  | 			<h3 class="text-xl font-bold">Runner Scanned</h3> | ||||||
|  | 			<p>{runnerID}</p> | ||||||
|  | 			<h3 class="text-xl font-bold">Scan Card (Code 128 Barcode)</h3> | ||||||
|  | 		{/if} | ||||||
|  | 		<QrCodeScanner | ||||||
|  | 			on:detect={(e) => { | ||||||
|  | 				console.log({ type: "DETECT", code: e.detail.decodedText }); | ||||||
|  | 				if (state === "scan_runner") { | ||||||
|  | 					if ( | ||||||
|  | 						e.detail.decodedText.includes( | ||||||
|  | 							"https://portal.lauf-fuer-kaya.de/profile/" | ||||||
|  | 						) | ||||||
|  | 					) { | ||||||
|  | 						runnerID = JSON.parse( | ||||||
|  | 							atob( | ||||||
|  | 								e.detail.decodedText | ||||||
|  | 									.replace("https://portal.lauf-fuer-kaya.de/profile/", "") | ||||||
|  | 									.split(".")[1] | ||||||
|  | 							) | ||||||
|  | 						).id; | ||||||
|  | 						state = "scan_card"; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (state === "scan_card") { | ||||||
|  | 					if ( | ||||||
|  | 						!e.detail.decodedText.includes( | ||||||
|  | 							"https://portal.lauf-fuer-kaya.de/profile/" | ||||||
|  | 						) | ||||||
|  | 					) { | ||||||
|  | 						cardInfo = e.detail.decodedText; | ||||||
|  | 						state = "done"; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 			}} | ||||||
|  | 			width={320} | ||||||
|  | 			height={320} | ||||||
|  | 			class="w-full max-w-sm bg-neutral-300 rounded-lg overflow-hidden" | ||||||
|  | 		/> | ||||||
|  | 		{#if state === "scan_card"} | ||||||
|  | 			<button | ||||||
|  | 				on:click={() => { | ||||||
|  | 					state = "scan_runner"; | ||||||
|  | 					runnerID = undefined; | ||||||
|  | 					cardInfo = ""; | ||||||
|  | 				}} | ||||||
|  | 				type="button" | ||||||
|  | 				class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-red-100 text-red-800 hover:bg-red-200 focus:outline-hidden focus:bg-red-200 disabled:opacity-50 disabled:pointer-events-none dark:text-red-500 dark:bg-red-800/30 dark:hover:bg-red-800/20 dark:focus:bg-red-800/20 w-full mt-2" | ||||||
|  | 			> | ||||||
|  | 				Cancel | ||||||
|  | 			</button> | ||||||
|  | 		{/if} | ||||||
|  | 		<!--  --> | ||||||
|  | 	{/if} | ||||||
|  | </div> | ||||||
							
								
								
									
										80
									
								
								src/components/general/QrCodeScanner.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								src/components/general/QrCodeScanner.svelte
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | |||||||
|  | <script> | ||||||
|  | 	import { onMount, createEventDispatcher } from "svelte"; | ||||||
|  | 	import { | ||||||
|  | 		Html5QrcodeScanner, | ||||||
|  | 		Html5QrcodeScanType, | ||||||
|  | 		Html5QrcodeSupportedFormats, | ||||||
|  | 		Html5QrcodeScannerState, | ||||||
|  | 	} from "html5-qrcode"; | ||||||
|  |  | ||||||
|  | 	export let width; | ||||||
|  | 	export let height; | ||||||
|  | 	export let paused = false; | ||||||
|  |  | ||||||
|  | 	const dispatch = createEventDispatcher(); | ||||||
|  |  | ||||||
|  | 	function onScanSuccess(decodedText, decodedResult) { | ||||||
|  | 		dispatch("detect", { decodedText }); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// usually better to ignore and keep scanning | ||||||
|  | 	function onScanFailure(message) { | ||||||
|  | 		dispatch("error", { message }); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	let scanner; | ||||||
|  | 	onMount(() => { | ||||||
|  | 		scanner = new Html5QrcodeScanner( | ||||||
|  | 			"qr-scanner", | ||||||
|  | 			{ | ||||||
|  | 				fps: 10, | ||||||
|  | 				rememberLastUsedCamera: true, | ||||||
|  | 				qrbox: { width, height }, | ||||||
|  | 				aspectRatio: 1, | ||||||
|  | 				supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA], | ||||||
|  | 				formatsToSupport: [ | ||||||
|  | 					Html5QrcodeSupportedFormats.CODE_39, | ||||||
|  | 					Html5QrcodeSupportedFormats.EAN_8, | ||||||
|  | 					Html5QrcodeSupportedFormats.EAN_13, | ||||||
|  | 					Html5QrcodeSupportedFormats.QR_CODE, | ||||||
|  | 					Html5QrcodeSupportedFormats.CODE_128, | ||||||
|  | 				], | ||||||
|  | 			}, | ||||||
|  | 			false // non-verbose | ||||||
|  | 		); | ||||||
|  | 		scanner.render(onScanSuccess, onScanFailure); | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  | 	// pause/resume scanner to avoid unintended scans | ||||||
|  | 	$: togglePause(paused); | ||||||
|  | 	function togglePause(paused) { | ||||||
|  | 		if (paused && scanner?.getState() === Html5QrcodeScannerState.SCANNING) { | ||||||
|  | 			scanner?.pause(); | ||||||
|  | 		} else if (scanner?.getState() === Html5QrcodeScannerState.PAUSED) { | ||||||
|  | 			scanner?.resume(); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <div id="qr-scanner" class={$$props.class} /> | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | 	/* Hide unwanted icons */ | ||||||
|  | 	#qr-scanner :global(img[alt="Info icon"]), | ||||||
|  | 	#qr-scanner :global(img[alt="Camera based scan"]) { | ||||||
|  | 		display: none; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* Change camera permission button text */ | ||||||
|  | 	#qr-scanner :global(#html5-qrcode-button-camera-permission) { | ||||||
|  | 		visibility: hidden; | ||||||
|  | 	} | ||||||
|  | 	#qr-scanner :global(#html5-qrcode-button-camera-permission::after) { | ||||||
|  | 		position: absolute; | ||||||
|  | 		inset: auto 0 0; | ||||||
|  | 		display: block; | ||||||
|  | 		content: "Allow camera access"; | ||||||
|  | 		visibility: visible; | ||||||
|  | 		padding: 10px 0; | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
| @@ -170,7 +170,7 @@ | |||||||
| 						<img | 						<img | ||||||
| 							class:w-[50%]={is_qrcode} | 							class:w-[50%]={is_qrcode} | ||||||
| 							class:w-full={!is_qrcode} | 							class:w-full={!is_qrcode} | ||||||
| 							class="md:w-auto mb-2 mx-auto" | 							class="w-full lg:max-w-[50vw] lg:max-h-[10rem] object-contain mb-2 mx-auto" | ||||||
| 							alt="Registrierungscode" | 							alt="Registrierungscode" | ||||||
| 							src={textToBase64Barcode(window.config.baseurl, is_qrcode)} | 							src={textToBase64Barcode(window.config.baseurl, is_qrcode)} | ||||||
| 						/> | 						/> | ||||||
| @@ -178,7 +178,7 @@ | |||||||
| 						<img | 						<img | ||||||
| 							class:w-[50%]={is_qrcode} | 							class:w-[50%]={is_qrcode} | ||||||
| 							class:w-full={!is_qrcode} | 							class:w-full={!is_qrcode} | ||||||
| 							class="md:w-auto mb-2 mx-auto" | 							class="w-full lg:max-w-[50vw] lg:max-h-[10rem] object-contain mb-2 mx-auto" | ||||||
| 							alt="Registrierungscode" | 							alt="Registrierungscode" | ||||||
| 							src={barcode} | 							src={barcode} | ||||||
| 						/> | 						/> | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user