Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
fce2bc645e
|
|||
991716a7f5
|
|||
aa720f2460
|
|||
ac4ef8fb6d
|
|||
eae0afda23
|
|||
5291f8a4d1
|
|||
e2d7de1e9e
|
|||
d7c9c27ec7
|
|||
153b1b3c2b
|
|||
ec63c7c1c5
|
|||
05c2535698
|
|||
e261d5e345
|
|||
c00497d776
|
|||
766eeab49f
|
|||
3c9b404234
|
|||
9c56b3883e
|
56
CHANGELOG.md
56
CHANGELOG.md
@@ -2,9 +2,65 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||
|
||||
#### [1.10.1](https://git.odit.services/lfk/frontend/compare/1.10.0...1.10.1)
|
||||
|
||||
- feat: runner list filtered by created_via [`991716a`](https://git.odit.services/lfk/frontend/commit/991716a7f55d0414111ad264ad1e93de9e82971a)
|
||||
|
||||
#### [1.10.0](https://git.odit.services/lfk/frontend/compare/1.9.11...1.10.0)
|
||||
|
||||
> 9 April 2025
|
||||
|
||||
- feat: working CardAssignment [`ac4ef8f`](https://git.odit.services/lfk/frontend/commit/ac4ef8fb6ded5c5d5678a651420e356b3ef45399)
|
||||
- chore(release): 1.10.0 [`aa720f2`](https://git.odit.services/lfk/frontend/commit/aa720f2460079e35eed9d87a2ac580a3305efbd5)
|
||||
|
||||
#### [1.9.11](https://git.odit.services/lfk/frontend/compare/1.9.10...1.9.11)
|
||||
|
||||
> 8 April 2025
|
||||
|
||||
- feat(dash): add runnersViaKiosk [`5291f8a`](https://git.odit.services/lfk/frontend/commit/5291f8a4d1721cd0c745191ebc85f221c34a23c8)
|
||||
- chore(release): 1.9.11 [`eae0afd`](https://git.odit.services/lfk/frontend/commit/eae0afda23a54020e25821c0188d8cbec3139593)
|
||||
|
||||
#### [1.9.10](https://git.odit.services/lfk/frontend/compare/1.9.9...1.9.10)
|
||||
|
||||
> 8 April 2025
|
||||
|
||||
- feat: add experimental ui for mobile card assignment [`d7c9c27`](https://git.odit.services/lfk/frontend/commit/d7c9c27ec7a1fea1cbaf26914843d044bbae32fe)
|
||||
- chore(release): 1.9.10 [`e2d7de1`](https://git.odit.services/lfk/frontend/commit/e2d7de1e9e1fd134f54876fa80f19f94fbea3672)
|
||||
|
||||
#### [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)
|
||||
|
||||
> 2 April 2025
|
||||
|
||||
- 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)
|
||||
|
||||
> 2 April 2025
|
||||
|
||||
- fix: ImportRunnerModal scrolling & team select [`766eeab`](https://git.odit.services/lfk/frontend/commit/766eeab49fb3ca5715c19dbf9bc53cb71124d3df)
|
||||
- chore(release): 1.9.7 [`c00497d`](https://git.odit.services/lfk/frontend/commit/c00497d7760a935965cc83213f72f35999a3c168)
|
||||
|
||||
#### [1.9.6](https://git.odit.services/lfk/frontend/compare/1.9.5...1.9.6)
|
||||
|
||||
> 29 March 2025
|
||||
|
||||
- chore(release): 1.9.6 [`3c9b404`](https://git.odit.services/lfk/frontend/commit/3c9b404234c7d7d2f0c48256be2130a0ed8ae047)
|
||||
- pnpm allow builds [`9c56b38`](https://git.odit.services/lfk/frontend/commit/9c56b3883eeab9e1a5e1c4921bfb6528c230e0d4)
|
||||
|
||||
#### [1.9.5](https://git.odit.services/lfk/frontend/compare/1.9.4...1.9.5)
|
||||
|
||||
> 29 March 2025
|
||||
|
||||
- feat: modal improvements [`d7e84a7`](https://git.odit.services/lfk/frontend/commit/d7e84a79a892294d532cc93aa3391c14a7a5ce99)
|
||||
- chore(release): 1.9.5 [`3d506db`](https://git.odit.services/lfk/frontend/commit/3d506db97502399e8b381b4cf38af2f07a584aec)
|
||||
|
||||
#### [1.9.4](https://git.odit.services/lfk/frontend/compare/1.9.3...1.9.4)
|
||||
|
||||
|
@@ -13,7 +13,7 @@
|
||||
|
||||
<body>
|
||||
<span style="display: none; visibility: hidden" id="buildinfo"
|
||||
>RELEASE_INFO-1.9.5-RELEASE_INFO</span
|
||||
>RELEASE_INFO-1.10.1-RELEASE_INFO</span
|
||||
>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<script src="/env.js"></script>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@odit/lfk-frontend",
|
||||
"version": "1.9.5",
|
||||
"version": "1.10.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"i18n-order": "node order.js",
|
||||
@@ -43,12 +43,13 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/athiti": "^5.2.5",
|
||||
"@odit/lfk-client-js": "1.2.0",
|
||||
"@odit/lfk-client-js": "1.2.3",
|
||||
"@paralleldrive/cuid2": "2.2.2",
|
||||
"@tanstack/svelte-table": "8.9.1",
|
||||
"bwip-js": "3.4.0",
|
||||
"check-password-strength": "2.0.10",
|
||||
"csvtojson": "2.0.10",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"localforage": "1.10.0",
|
||||
"marked": "4.3.0",
|
||||
"svelte": "3.58.0",
|
||||
|
36
pnpm-lock.yaml
generated
36
pnpm-lock.yaml
generated
@@ -12,8 +12,8 @@ importers:
|
||||
specifier: ^5.2.5
|
||||
version: 5.2.5
|
||||
'@odit/lfk-client-js':
|
||||
specifier: 1.2.0
|
||||
version: 1.2.0
|
||||
specifier: 1.2.3
|
||||
version: 1.2.3
|
||||
'@paralleldrive/cuid2':
|
||||
specifier: 2.2.2
|
||||
version: 2.2.2
|
||||
@@ -29,6 +29,9 @@ importers:
|
||||
csvtojson:
|
||||
specifier: 2.0.10
|
||||
version: 2.0.10
|
||||
html5-qrcode:
|
||||
specifier: ^2.3.8
|
||||
version: 2.3.8
|
||||
localforage:
|
||||
specifier: 1.10.0
|
||||
version: 1.10.0
|
||||
@@ -77,7 +80,7 @@ importers:
|
||||
version: 3.3.3(prettier@3.5.3)(svelte@3.58.0)
|
||||
release-it:
|
||||
specifier: 17.10.0
|
||||
version: 17.10.0
|
||||
version: 17.10.0(typescript@5.8.3)
|
||||
svelte-select:
|
||||
specifier: 3.17.0
|
||||
version: 3.17.0
|
||||
@@ -352,8 +355,8 @@ packages:
|
||||
'@octokit/types@13.6.1':
|
||||
resolution: {integrity: sha512-PHZE9Z+kWXb23Ndik8MKPirBPziOc0D2/3KH1P+6jK5nGWe96kadZuE4jev2/Jq7FvIfTlT2Ltg8Fv2x1v0a5g==}
|
||||
|
||||
'@odit/lfk-client-js@1.2.0':
|
||||
resolution: {integrity: sha512-RR/Ij3PDMF840VJtphO51k+3voJcTlvRIxzTFBkvrwriBmLJwchBQxq40K4/kyVIFH7lLwO3uJy0PaxgEoTbFQ==}
|
||||
'@odit/lfk-client-js@1.2.3':
|
||||
resolution: {integrity: sha512-QXJUVfH57iwykKNHQQC4z18/f7rnpCNCjvxijrOmuBMLsBNuYSzvrrqXyno4ce1rr5f0PD4IYtKmhcgJsk49wQ==}
|
||||
|
||||
'@odit/license-exporter@0.2.0':
|
||||
resolution: {integrity: sha512-RRyfQzDLoyLQlGSd8ThJQ3h0fiCe4tkmm935AUvSVQWP+p88FcnI4iaktKBJJVBnIpDhkv/7sDSA5dFc/QMM5w==}
|
||||
@@ -924,6 +927,9 @@ packages:
|
||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
html5-qrcode@2.3.8:
|
||||
resolution: {integrity: sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
|
||||
engines: {node: '>= 14'}
|
||||
@@ -1794,6 +1800,11 @@ packages:
|
||||
type@2.7.2:
|
||||
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:
|
||||
resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
@@ -2165,7 +2176,7 @@ snapshots:
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 22.2.0
|
||||
|
||||
'@odit/lfk-client-js@1.2.0': {}
|
||||
'@odit/lfk-client-js@1.2.3': {}
|
||||
|
||||
'@odit/license-exporter@0.2.0':
|
||||
dependencies:
|
||||
@@ -2439,12 +2450,14 @@ snapshots:
|
||||
graceful-fs: 4.2.11
|
||||
xdg-basedir: 5.1.0
|
||||
|
||||
cosmiconfig@9.0.0:
|
||||
cosmiconfig@9.0.0(typescript@5.8.3):
|
||||
dependencies:
|
||||
env-paths: 2.2.1
|
||||
import-fresh: 3.3.0
|
||||
js-yaml: 4.1.0
|
||||
parse-json: 5.2.0
|
||||
optionalDependencies:
|
||||
typescript: 5.8.3
|
||||
|
||||
crc-32@1.2.2: {}
|
||||
|
||||
@@ -2765,6 +2778,8 @@ snapshots:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
html5-qrcode@2.3.8: {}
|
||||
|
||||
http-proxy-agent@7.0.2:
|
||||
dependencies:
|
||||
agent-base: 7.1.1
|
||||
@@ -3322,14 +3337,14 @@ snapshots:
|
||||
dependencies:
|
||||
rc: 1.2.8
|
||||
|
||||
release-it@17.10.0:
|
||||
release-it@17.10.0(typescript@5.8.3):
|
||||
dependencies:
|
||||
'@iarna/toml': 2.2.5
|
||||
'@octokit/rest': 20.1.1
|
||||
async-retry: 1.3.3
|
||||
chalk: 5.3.0
|
||||
ci-info: 4.1.0
|
||||
cosmiconfig: 9.0.0
|
||||
cosmiconfig: 9.0.0(typescript@5.8.3)
|
||||
execa: 8.0.0
|
||||
git-url-parse: 14.0.0
|
||||
globby: 14.0.2
|
||||
@@ -3607,6 +3622,9 @@ snapshots:
|
||||
|
||||
type@2.7.2: {}
|
||||
|
||||
typescript@5.8.3:
|
||||
optional: true
|
||||
|
||||
uglify-js@3.19.3:
|
||||
optional: true
|
||||
|
||||
|
3
pnpm-workspace.yaml
Normal file
3
pnpm-workspace.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
onlyBuiltDependencies:
|
||||
- es5-ext
|
||||
- esbuild
|
BIN
public/beep.mp3
Normal file
BIN
public/beep.mp3
Normal file
Binary file not shown.
@@ -41,6 +41,7 @@
|
||||
import Settings from "./components/settings/Settings.svelte";
|
||||
import Transition from "./components/base/Transition.svelte";
|
||||
import Orgs from "./components/orgs/Orgs.svelte";
|
||||
import CardAssignment from "./components/general/CardAssignment.svelte";
|
||||
import Runners from "./components/runners/Runners.svelte";
|
||||
import Footer from "./components/general/Footer.svelte";
|
||||
import TracksOverview from "./components/tracks/TracksOverview.svelte";
|
||||
@@ -135,12 +136,23 @@
|
||||
</Route>
|
||||
<Route path="/runners/*">
|
||||
<Route path="/">
|
||||
<Runners />
|
||||
<Runners created_via="all" />
|
||||
</Route>
|
||||
<Route path="/:runnerid" let:params>
|
||||
<Route path="/selfservice/">
|
||||
<Runners created_via="selfservice" />
|
||||
</Route>
|
||||
<Route path="/kiosk/">
|
||||
<Runners created_via="kiosk" />
|
||||
</Route>
|
||||
<Route path="/detail/:runnerid" let:params>
|
||||
<RunnerDetail {params} />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/cardassignment/*">
|
||||
<Route path="/">
|
||||
<CardAssignment />
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="/teams/*">
|
||||
<Route path="/">
|
||||
<Teams />
|
||||
|
@@ -6,7 +6,7 @@
|
||||
{#if !runner}
|
||||
{$_("non-blanko")}
|
||||
{:else}
|
||||
<a href={`/runners/${runner.id}`}>
|
||||
<a href={`/runners/detail/${runner.id}`}>
|
||||
{#if runner.middlename}
|
||||
{runner.firstname} {runner.middlename} {runner.lastname}
|
||||
{:else}
|
||||
|
@@ -41,7 +41,27 @@
|
||||
</svg>
|
||||
<span>{$_("dashboard-title")}</span>
|
||||
</a>
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET")}
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:GET") && store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
|
||||
<a
|
||||
class:activenav={$router.path.includes("/cardassignment/")}
|
||||
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
|
||||
href="/cardassignment/"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
class="flex-shrink-0 w-5 h-5 mr-2 transition group-hover:text-gray-600"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M14.615 1.595a.75.75 0 0 1 .359.852L12.982 9.75h7.268a.75.75 0 0 1 .548 1.262l-10.5 11.25a.75.75 0 0 1-1.272-.71l1.992-7.302H3.75a.75.75 0 0 1-.548-1.262l10.5-11.25a.75.75 0 0 1 .913-.143Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
<span>Card Assignment</span>
|
||||
</a>
|
||||
<a
|
||||
class:activenav={$router.path.includes("/runners/")}
|
||||
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-200 hover:text-gray-900 w-full font-semibold"
|
||||
|
@@ -220,7 +220,24 @@
|
||||
<StatCard
|
||||
title={$_("runner_via_selfservice")}
|
||||
value={stats.runnersViaSelfservice}
|
||||
href="/runners/"
|
||||
href="/runners/selfservice/"
|
||||
>
|
||||
<svg
|
||||
height="24"
|
||||
width="24"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path d="M0 0h24v24H0z" fill="none" />
|
||||
<path
|
||||
d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z"
|
||||
/></svg
|
||||
>
|
||||
</StatCard>
|
||||
<StatCard
|
||||
title={$_('runners_via_kiosk')}
|
||||
value={stats.runnersViaKiosk}
|
||||
href="/runners/kiosk/"
|
||||
>
|
||||
<svg
|
||||
height="24"
|
||||
|
@@ -8,7 +8,7 @@
|
||||
{:else}
|
||||
<div class="text-sm font-medium text-gray-900">
|
||||
<a
|
||||
href="../runners/{runner.id}"
|
||||
href="../runners/detail/{runner.id}"
|
||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800 border border-current"
|
||||
>{runner.firstname}
|
||||
{#if runner.middlename}{runner.middlename}{/if}
|
||||
|
123
src/components/general/CardAssignment.svelte
Normal file
123
src/components/general/CardAssignment.svelte
Normal file
@@ -0,0 +1,123 @@
|
||||
<script>
|
||||
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
|
||||
import QrCodeScanner from "./QrCodeScanner.svelte";
|
||||
let state = "scan_runner";
|
||||
let runnerinfo = { id: 0, firstname: "", lastname: "" };
|
||||
let cardCode = "";
|
||||
$: scannerActive = state.includes("scan");
|
||||
</script>
|
||||
|
||||
<div class="p-4">
|
||||
<h3 class="text-3xl font-bold">Card Assignment for Mobile</h3>
|
||||
<!-- <p>state</p>
|
||||
<p>{state}</p>
|
||||
<p>scannerActive</p>
|
||||
<p>{scannerActive}</p> -->
|
||||
{#if state.includes("scan_")}
|
||||
<!-- -->
|
||||
{#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>{runnerinfo.firstname} {runnerinfo.lastname} [#{runnerinfo.id}]</p>
|
||||
<h3 class="text-xl font-bold">Scan Card (Code 128 Barcode)</h3>
|
||||
{/if}
|
||||
<QrCodeScanner
|
||||
paused={!scannerActive}
|
||||
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/"
|
||||
)
|
||||
) {
|
||||
const runnerID = JSON.parse(
|
||||
atob(
|
||||
e.detail.decodedText
|
||||
.replace("https://portal.lauf-fuer-kaya.de/profile/", "")
|
||||
.split(".")[1]
|
||||
)
|
||||
).id;
|
||||
new Audio("/beep.mp3").play();
|
||||
RunnerService.runnerControllerGetOne(runnerID).then((runner) => {
|
||||
console.log(runner);
|
||||
runnerinfo = runner;
|
||||
});
|
||||
state = "scan_card";
|
||||
}
|
||||
}
|
||||
if (state === "scan_card") {
|
||||
if (
|
||||
!e.detail.decodedText.includes(
|
||||
"https://portal.lauf-fuer-kaya.de/profile/"
|
||||
)
|
||||
) {
|
||||
cardCode = e.detail.decodedText;
|
||||
new Audio("/beep.mp3").play();
|
||||
state = "assigning";
|
||||
RunnerCardService.runnerCardControllerGetAll().then((cards) => {
|
||||
console.log(cards);
|
||||
const card = cards.find((c) => c.code === cardCode);
|
||||
if (card) {
|
||||
console.log("card found", card);
|
||||
RunnerCardService.runnerCardControllerPut(card.id, {
|
||||
enabled: true,
|
||||
id: card.id,
|
||||
runner: runnerinfo.id,
|
||||
}).then(() => {
|
||||
state = "done";
|
||||
});
|
||||
} else {
|
||||
state = "error_card_404";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}}
|
||||
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";
|
||||
runnerinfo = { id: 0, firstname: "", lastname: "" };
|
||||
cardCode = "";
|
||||
}}
|
||||
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}
|
||||
<!-- -->
|
||||
{:else}
|
||||
<!-- -->
|
||||
{#if state === "assigning"}
|
||||
<p>Assigning Card {cardCode} ⌛</p>
|
||||
<p>Please wait a moment while we assign the card...</p>
|
||||
{/if}
|
||||
{#if state === "done"}
|
||||
<p>
|
||||
Assigned Card {cardCode} to {runnerinfo.firstname}
|
||||
{runnerinfo.lastname} [#{runnerinfo.id}] ✅
|
||||
</p>
|
||||
<button
|
||||
on:click={() => {
|
||||
// state = "scan_runner";
|
||||
// runnerinfo = { id: 0, firstname: "", lastname: "" };
|
||||
// cardCode = "";
|
||||
location.reload();
|
||||
}}
|
||||
type="button"
|
||||
class="py-3 px-4 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-100 text-blue-800 hover:bg-blue-200 focus:outline-hidden focus:bg-blue-200 disabled:opacity-50 disabled:pointer-events-none dark:text-blue-500 dark:bg-blue-800/30 dark:hover:bg-blue-800/20 dark:focus:bg-blue-800/20 w-full mt-2"
|
||||
>
|
||||
Done
|
||||
</button>
|
||||
{/if}
|
||||
<!-- -->
|
||||
{/if}
|
||||
</div>
|
84
src/components/general/QrCodeScanner.svelte
Normal file
84
src/components/general/QrCodeScanner.svelte
Normal file
@@ -0,0 +1,84 @@
|
||||
<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) {
|
||||
if (!paused) {
|
||||
dispatch("detect", { decodedText });
|
||||
}
|
||||
}
|
||||
|
||||
// usually better to ignore and keep scanning
|
||||
function onScanFailure(message) {
|
||||
if (!paused) {
|
||||
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>
|
81
src/components/pdf_generation/DownloadProgressModal.svelte
Normal file
81
src/components/pdf_generation/DownloadProgressModal.svelte
Normal file
@@ -0,0 +1,81 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import { onMount } from "svelte";
|
||||
export let download_details = "";
|
||||
export let modal_open;
|
||||
onMount(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-hidden"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl">
|
||||
<div class="">
|
||||
<div
|
||||
class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 sm:text-left text-base">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_('download_laeuft')}
|
||||
</h3>
|
||||
<div class="w-full">
|
||||
{download_details}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
@@ -7,6 +7,7 @@
|
||||
import DocumentServer from "./DocumentServer";
|
||||
import { init } from "@paralleldrive/cuid2";
|
||||
import toast from "svelte-french-toast";
|
||||
import DownloadProgressModal from "./DownloadProgressModal.svelte";
|
||||
const createId = init({ length: 10, fingerprint: "lfk-frontend" });
|
||||
const documentServer = new DocumentServer(
|
||||
config.baseurl_documentserver,
|
||||
@@ -17,8 +18,12 @@
|
||||
export let generate_runners = [];
|
||||
export let generate_orgs = [];
|
||||
export let generate_teams = [];
|
||||
//
|
||||
export let download_modal_open = false;
|
||||
export let download_details = "";
|
||||
|
||||
function generateSponsoringContract(locale) {
|
||||
download_modal_open = true;
|
||||
if (generate_orgs.length > 0) {
|
||||
generateOrgContracts(locale);
|
||||
} else if (generate_teams.length > 0) {
|
||||
@@ -41,19 +46,24 @@
|
||||
|
||||
async function generateTeamContracts(locale) {
|
||||
toast.loading($_("generating-pdfs"));
|
||||
let totalCount = generate_teams.length;
|
||||
let count = 0;
|
||||
for (const t of generate_teams) {
|
||||
count++;
|
||||
download_details = `${t.parentGroup.name} > ${t.name}`;
|
||||
const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
|
||||
t.id
|
||||
);
|
||||
documentServer
|
||||
await documentServer
|
||||
.generateContracts(runners, locale)
|
||||
.then((blob) => {
|
||||
download(
|
||||
blob,
|
||||
`${$_("sponsorings")}_${t.name}-${locale}-${createId()}.pdf`
|
||||
);
|
||||
if (count === totalCount) {
|
||||
download_modal_open = false;
|
||||
}
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
@@ -61,15 +71,23 @@
|
||||
|
||||
async function generateOrgContracts(locale) {
|
||||
toast.loading($_("generating-pdf"));
|
||||
let count_orgs = 0;
|
||||
let totalCount = 0;
|
||||
for (const o of generate_orgs) {
|
||||
count_orgs++;
|
||||
let count = 0;
|
||||
totalCount++;
|
||||
for (const t of o.teams) {
|
||||
totalCount++;
|
||||
}
|
||||
}
|
||||
console.log({ totalCount });
|
||||
let count = 0;
|
||||
for (const o of generate_orgs) {
|
||||
count++;
|
||||
let runners =
|
||||
await RunnerOrganizationService.runnerOrganizationControllerGetRunners(
|
||||
o.id,
|
||||
true
|
||||
);
|
||||
download_details = o.name;
|
||||
await documentServer
|
||||
.generateContracts(runners, locale)
|
||||
.then((blob) => {
|
||||
@@ -84,6 +102,7 @@
|
||||
let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
|
||||
t.id
|
||||
);
|
||||
download_details = `${o.name} > ${t.name}`;
|
||||
await documentServer
|
||||
.generateContracts(runners, locale)
|
||||
.then((blob) => {
|
||||
@@ -93,15 +112,19 @@
|
||||
t.name
|
||||
}-${locale}-${createId()}.pdf`
|
||||
);
|
||||
console.log({ count });
|
||||
if (count === totalCount) {
|
||||
download_modal_open = false;
|
||||
}
|
||||
})
|
||||
.catch((err) => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateRunnerContracts(locale) {
|
||||
async function generateRunnerContracts(locale) {
|
||||
toast.loading($_("generating-pdf"));
|
||||
documentServer
|
||||
await documentServer
|
||||
.generateContracts(generate_runners, locale)
|
||||
.then((blob) => {
|
||||
let fileName = `${$_("sponsorings")}-${locale}-${createId()}.pdf`;
|
||||
@@ -111,6 +134,7 @@
|
||||
}-${locale}-${createId()}.pdf`;
|
||||
}
|
||||
download(blob, fileName);
|
||||
download_modal_open = false;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
@@ -119,6 +143,7 @@
|
||||
</script>
|
||||
|
||||
{#if sponsoring_contracts_show}
|
||||
<DownloadProgressModal {download_details} modal_open={download_modal_open} />
|
||||
<button
|
||||
on:click={() => {
|
||||
generateSponsoringContract("de");
|
||||
|
@@ -74,7 +74,7 @@
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 sm:text-left max-h-[75vh] overflow-y-auto">
|
||||
<div class="mt-3 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_('delete_runner')}
|
||||
</h3>
|
||||
|
@@ -1,401 +1,386 @@
|
||||
<script>
|
||||
import csv from "csvtojson";
|
||||
import { read as readXlsx, utils as xlsx_utils } from "xlsx";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
import csv from "csvtojson";
|
||||
import { read as readXlsx, utils as xlsx_utils } from "xlsx";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import {
|
||||
ImportService,
|
||||
RunnerTeamService,
|
||||
RunnerOrganizationService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import Select from "svelte-select";
|
||||
import toast from "svelte-french-toast";
|
||||
export let opened_from;
|
||||
export let passed_org;
|
||||
export let passed_orgs;
|
||||
export let passed_team;
|
||||
export let import_modal_open;
|
||||
$: searchvalue = "";
|
||||
$: importButtonEnabled =
|
||||
recent_processed &&
|
||||
(!(selected_org_or_team == "" || selected_org_or_team == null) ||
|
||||
!(passed_org?.id == null || passed_org?.id == 0) ||
|
||||
!(passed_team?.id == null || passed_team?.id == 0));
|
||||
const dispatch = createEventDispatcher();
|
||||
function cancelModal() {
|
||||
json_output = [];
|
||||
import_modal_open = false;
|
||||
dispatch("cancel");
|
||||
}
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
cancelModal();
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
//
|
||||
}
|
||||
};
|
||||
})();
|
||||
let groups = [];
|
||||
RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => {
|
||||
const orgs = val.map((r) => {
|
||||
return { label: r.name, value: `ORG_${r.id}` };
|
||||
});
|
||||
groups = groups.concat(orgs);
|
||||
RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
|
||||
const teams = val.map((r) => {
|
||||
return {
|
||||
label: `${r.parentGroup.name} > ${r.name}`,
|
||||
value: `TEAM_${r.id}`,
|
||||
};
|
||||
});
|
||||
groups = groups.concat(teams);
|
||||
});
|
||||
});
|
||||
let selected_org;
|
||||
$: selected_org_or_team = "";
|
||||
let files;
|
||||
let recent_processed = true;
|
||||
$: json_output = [];
|
||||
$: {
|
||||
if (files) {
|
||||
if (
|
||||
files[0].type ===
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", async (e) => {
|
||||
const data = new Uint8Array(e.target.result);
|
||||
const out = readXlsx(data, { type: "array" });
|
||||
json_output = xlsx_utils.sheet_to_json(
|
||||
out.Sheets[Object.keys(out.Sheets)[0]]
|
||||
);
|
||||
});
|
||||
reader.readAsArrayBuffer(files[0]);
|
||||
} else {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", async (e) => {
|
||||
json_output = await csv({
|
||||
delimiter: [";", ","],
|
||||
trim: true,
|
||||
}).fromString(e.target.result);
|
||||
});
|
||||
reader.readAsText(files[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function importAction() {
|
||||
if (recent_processed === true) {
|
||||
toast.loading($_("runners-are-being-imported"));
|
||||
recent_processed = false;
|
||||
const mapped = json_output.map(function (runner) {
|
||||
return {
|
||||
firstname: runner[`${$_("csv_import__firstname")}`],
|
||||
middlename: runner[`${$_("csv_import__middlename")}`],
|
||||
lastname: runner[`${$_("csv_import__lastname")}`],
|
||||
team:
|
||||
runner[`${$_("csv_import__team")}`] ||
|
||||
runner[`${$_("csv_import__class")}`],
|
||||
};
|
||||
});
|
||||
let org = 0;
|
||||
if (opened_from === "OrgDetail") {
|
||||
org = passed_org.id;
|
||||
}
|
||||
if (opened_from === "OrgOverview") {
|
||||
org = parseInt(selected_org);
|
||||
}
|
||||
if (opened_from === "OrgOverview" || opened_from === "OrgDetail") {
|
||||
ImportService.importControllerPostOrgsJson(org, mapped)
|
||||
.then((resp) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (opened_from === "TeamDetail") {
|
||||
ImportService.importControllerPostTeamsJson(passed_team.id, mapped)
|
||||
.then((resp) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (opened_from === "RunnerOverview") {
|
||||
if (selected_org_or_team.includes("ORG_")) {
|
||||
selected_org_or_team = selected_org_or_team.split("_")[1];
|
||||
ImportService.importControllerPostOrgsJson(
|
||||
selected_org_or_team,
|
||||
mapped
|
||||
)
|
||||
.then((resp) => {
|
||||
dispatch("created", { runners: resp });
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (selected_org_or_team.includes("TEAM_")) {
|
||||
selected_org_or_team = selected_org_or_team.split("_")[1];
|
||||
ImportService.importControllerPostTeamsJson(
|
||||
selected_org_or_team,
|
||||
mapped
|
||||
)
|
||||
.then((resp) => {
|
||||
dispatch("created", { runners: resp });
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
import {
|
||||
ImportService,
|
||||
RunnerTeamService,
|
||||
RunnerOrganizationService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import Select from "svelte-select";
|
||||
import toast from "svelte-french-toast";
|
||||
export let opened_from;
|
||||
export let passed_org;
|
||||
export let passed_orgs;
|
||||
export let passed_team;
|
||||
export let import_modal_open;
|
||||
$: searchvalue = "";
|
||||
$: importButtonEnabled =
|
||||
recent_processed &&
|
||||
(!(selected_org_or_team == "" || selected_org_or_team == null) ||
|
||||
!(passed_org?.id == null || passed_org?.id == 0) ||
|
||||
!(passed_team?.id == null || passed_team?.id == 0));
|
||||
const dispatch = createEventDispatcher();
|
||||
function cancelModal() {
|
||||
json_output = [];
|
||||
import_modal_open = false;
|
||||
dispatch("cancel");
|
||||
}
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
cancelModal();
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
//
|
||||
}
|
||||
};
|
||||
})();
|
||||
let groups = [];
|
||||
RunnerOrganizationService.runnerOrganizationControllerGetAll().then((val) => {
|
||||
const orgs = val.map((r) => {
|
||||
return { label: r.name, value: `ORG_${r.id}` };
|
||||
});
|
||||
groups = groups.concat(orgs);
|
||||
RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
|
||||
const teams = val.map((r) => {
|
||||
return {
|
||||
label: `${r.parentGroup.name} > ${r.name}`,
|
||||
value: `TEAM_${r.id}`,
|
||||
};
|
||||
});
|
||||
groups = groups.concat(teams);
|
||||
});
|
||||
});
|
||||
let selected_org;
|
||||
$: selected_org_or_team = "";
|
||||
let files;
|
||||
let recent_processed = true;
|
||||
$: json_output = [];
|
||||
$: {
|
||||
if (files) {
|
||||
if (
|
||||
files[0].type ===
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
) {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", async (e) => {
|
||||
const data = new Uint8Array(e.target.result);
|
||||
const out = readXlsx(data, { type: "array" });
|
||||
json_output = xlsx_utils.sheet_to_json(
|
||||
out.Sheets[Object.keys(out.Sheets)[0]]
|
||||
);
|
||||
});
|
||||
reader.readAsArrayBuffer(files[0]);
|
||||
} else {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", async (e) => {
|
||||
json_output = await csv({
|
||||
delimiter: [";", ","],
|
||||
trim: true,
|
||||
}).fromString(e.target.result);
|
||||
});
|
||||
reader.readAsText(files[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
function importAction() {
|
||||
if (recent_processed === true) {
|
||||
toast.loading($_("runners-are-being-imported"));
|
||||
recent_processed = false;
|
||||
const mapped = json_output.map(function (runner) {
|
||||
return {
|
||||
firstname: runner[`${$_("csv_import__firstname")}`],
|
||||
middlename: runner[`${$_("csv_import__middlename")}`],
|
||||
lastname: runner[`${$_("csv_import__lastname")}`],
|
||||
team:
|
||||
runner[`${$_("csv_import__team")}`] ||
|
||||
runner[`${$_("csv_import__class")}`],
|
||||
};
|
||||
});
|
||||
let org = 0;
|
||||
if (opened_from === "OrgDetail") {
|
||||
org = passed_org.id;
|
||||
}
|
||||
if (opened_from === "OrgOverview") {
|
||||
org = parseInt(selected_org);
|
||||
}
|
||||
if (opened_from === "OrgOverview" || opened_from === "OrgDetail") {
|
||||
ImportService.importControllerPostOrgsJson(org, mapped)
|
||||
.then((resp) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (opened_from === "TeamDetail") {
|
||||
ImportService.importControllerPostTeamsJson(passed_team.id, mapped)
|
||||
.then((resp) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (opened_from === "RunnerOverview") {
|
||||
if (selected_org_or_team.includes("ORG_")) {
|
||||
selected_org_or_team = selected_org_or_team.split("_")[1];
|
||||
ImportService.importControllerPostOrgsJson(
|
||||
selected_org_or_team,
|
||||
mapped
|
||||
)
|
||||
.then((resp) => {
|
||||
dispatch("created", { runners: resp });
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
if (selected_org_or_team.includes("TEAM_")) {
|
||||
selected_org_or_team = selected_org_or_team.split("_")[1];
|
||||
ImportService.importControllerPostTeamsJson(
|
||||
selected_org_or_team,
|
||||
mapped
|
||||
)
|
||||
.then((resp) => {
|
||||
dispatch("created", { runners: resp });
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.success($_("import-finished"));
|
||||
cancelModal();
|
||||
})
|
||||
.catch((err) => {
|
||||
toast.dismiss();
|
||||
recent_processed = true;
|
||||
toast.error($_("error-during-import"));
|
||||
cancelModal();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if import_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-hidden"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl lg:rounded-xl">
|
||||
<div class="">
|
||||
<div
|
||||
class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 sm:mt-0 sm:text-left w-full">
|
||||
<h3 class="text-lg leading-6 font-bold mt-2 text-gray-900">
|
||||
{$_("runner-import")}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:text-left w-full">
|
||||
{#if json_output.length === 0}
|
||||
<div class="mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_("please-provide-the-required-csv-xlsx-file")}
|
||||
</p>
|
||||
</div>
|
||||
<div class="overflow-hidden relative mt-4 mb-4">
|
||||
<input
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
bind:files
|
||||
type="file"
|
||||
/>
|
||||
</div>
|
||||
<div class="overflow-hidden relative mt-4 mb-4">
|
||||
<button
|
||||
on:click={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
type="button"
|
||||
class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{#if json_output.length > 0}
|
||||
{#if opened_from === "OrgOverview"}
|
||||
<p>{$_("import__target-organization")}</p>
|
||||
<select
|
||||
name="team"
|
||||
bind:value={selected_org}
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
|
||||
>
|
||||
{#each passed_orgs as o}
|
||||
<option value={o.id}>{o.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<p>{$_("confirm-runner-import")}</p>
|
||||
{/if}
|
||||
{#if opened_from === "RunnerOverview"}
|
||||
<p>{$_("group")}</p>
|
||||
<Select
|
||||
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
|
||||
itemFilter={(label, filterText, option) =>
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.id.value
|
||||
.toString()
|
||||
.startsWith(filterText.toLowerCase())}
|
||||
items={groups}
|
||||
showChevron={true}
|
||||
placeholder={$_(
|
||||
"search-for-an-organization-or-team-by-name-or-id"
|
||||
)}
|
||||
noOptionsMessage={$_("no-organization-or-team-found")}
|
||||
on:select={(selectedValue) => {
|
||||
selected_org_or_team = selectedValue.detail.value;
|
||||
}}
|
||||
on:clear={() => (selected_org_or_team = null)}
|
||||
/>
|
||||
{/if}
|
||||
{#if opened_from === "OrgDetail"}
|
||||
<p>
|
||||
{$_("runnerimport_verify_runners_org", {
|
||||
values: { org_name: passed_org.name },
|
||||
})}
|
||||
</p>
|
||||
{/if}
|
||||
<input
|
||||
type="search"
|
||||
bind:value={searchvalue}
|
||||
placeholder={$_("datatable.search")}
|
||||
aria-label={$_("datatable.search")}
|
||||
class="p-2 w-full"
|
||||
/>
|
||||
<div class="relative w-full mt-4 mb-4">
|
||||
<div class="w-full overflow-x-auto">
|
||||
<table class="divide-y divide-gray-200 w-full">
|
||||
<thead class="bg-gray-50">
|
||||
<tr class="odd:bg-white even:bg-gray-100">
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__firstname")}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__middlename")}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__lastname")}
|
||||
</th>
|
||||
{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))}
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__team")}
|
||||
</th>
|
||||
{/if}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
{#each json_output as runner}
|
||||
{#if Object.values(runner)
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(searchvalue)}
|
||||
<tr class="odd:bg-white even:bg-gray-100">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__firstname")}`]}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__middlename")}`] || ""}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__lastname")}`]}
|
||||
</td>
|
||||
{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))}
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__team")}`] ||
|
||||
runner[`${$_("csv_import__class")}`] ||
|
||||
"---"}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button
|
||||
disabled={!importButtonEnabled}
|
||||
class:opacity-50={!importButtonEnabled}
|
||||
on:click={importAction}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
{$_("import-runners")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-hidden"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center h-screen text-center sm:block p-0 lg:p-4"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom text-left shadow-xl transform transition-all sm:align-middle w-full lg:w-auto min-w-auto lg:min-w-[35vw]"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div
|
||||
class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4 rounded-t-xl lg:rounded-xl"
|
||||
>
|
||||
<div class="">
|
||||
<div
|
||||
class="flex-shrink-0 flex items-center justify-center size-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
d="M9.83 8.79L8 9.456V13H6V8.05h.015l5.268-1.918c.244-.093.51-.14.782-.131a2.616 2.616 0 0 1 2.427 1.82c.186.583.356.977.51 1.182A4.992 4.992 0 0 0 19 11v2a6.986 6.986 0 0 1-5.402-2.547l-.581 3.297L15 15.67V23h-2v-5.986l-2.05-1.987-.947 4.298-6.894-1.215.348-1.97 4.924.868L9.83 8.79zM13.5 5.5a2 2 0 1 1 0-4 2 2 0 0 1 0 4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 sm:mt-0 sm:text-left w-full">
|
||||
<h3 class="text-lg leading-6 font-bold mt-2 text-gray-900">
|
||||
{$_("runner-import")}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sm:text-left w-full">
|
||||
{#if json_output.length === 0}
|
||||
<div class="mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_("please-provide-the-required-csv-xlsx-file")}
|
||||
</p>
|
||||
</div>
|
||||
<div class="overflow-hidden relative mt-4 mb-4">
|
||||
<input
|
||||
accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
bind:files
|
||||
type="file"
|
||||
/>
|
||||
</div>
|
||||
<div class="overflow-hidden relative mt-4 mb-4">
|
||||
<button
|
||||
on:click={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
type="button"
|
||||
class="w-full justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 hidden lg:block"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{#if json_output.length > 0}
|
||||
{#if opened_from === "OrgOverview"}
|
||||
<p>{$_("import__target-organization")}</p>
|
||||
<select
|
||||
name="team"
|
||||
bind:value={selected_org}
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
|
||||
>
|
||||
{#each passed_orgs as o}
|
||||
<option value={o.id}>{o.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<p>{$_("confirm-runner-import")}</p>
|
||||
{/if}
|
||||
{#if opened_from === "RunnerOverview"}
|
||||
<p>{$_("group")}</p>
|
||||
<select
|
||||
bind:value={selected_org_or_team}
|
||||
class="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-neutral-800 rounded-md p-2"
|
||||
>
|
||||
{#each groups as g}
|
||||
<option value={g.value}>{g.label}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{/if}
|
||||
{#if opened_from === "OrgDetail"}
|
||||
<p>
|
||||
{$_("runnerimport_verify_runners_org", {
|
||||
values: { org_name: passed_org.name },
|
||||
})}
|
||||
</p>
|
||||
{/if}
|
||||
<div class="relative w-full mt-4 mb-4">
|
||||
<div class="w-full overflow-x-auto max-h-[50vh]">
|
||||
<table class="divide-y divide-gray-200 w-full">
|
||||
<thead class="bg-gray-50">
|
||||
<tr class="odd:bg-white even:bg-gray-100">
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__firstname")}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__middlename")}
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__lastname")}
|
||||
</th>
|
||||
{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))}
|
||||
<th
|
||||
scope="col"
|
||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
{$_("csv_import__team")}
|
||||
</th>
|
||||
{/if}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200">
|
||||
{#each json_output as runner}
|
||||
{#if Object.values(runner)
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(searchvalue)}
|
||||
<tr class="odd:bg-white even:bg-gray-100">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__firstname")}`]}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__middlename")}`] || ""}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__lastname")}`]}
|
||||
</td>
|
||||
{#if (opened_from !== "TeamDetail" && opened_from !== "RunnerOverview") || (opened_from === "RunnerOverview" && selected_org_or_team.includes("ORG_"))}
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
{runner[`${$_("csv_import__team")}`] ||
|
||||
runner[`${$_("csv_import__class")}`] ||
|
||||
"---"}
|
||||
</td>
|
||||
{/if}
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<button
|
||||
disabled={!importButtonEnabled}
|
||||
class:opacity-50={!importButtonEnabled}
|
||||
on:click={importAction}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
>
|
||||
{$_("import-runners")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
cancelModal();
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
@@ -100,7 +100,7 @@
|
||||
<nav class="w-full flex">
|
||||
<ol class="list-none flex flex-row items-center justify-start">
|
||||
<li class="flex items-center">
|
||||
<a class="mr-2" href="./"
|
||||
<a class="mr-2" href="/runners/"
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
|
@@ -32,6 +32,7 @@
|
||||
|
||||
$: active_delete = undefined;
|
||||
let dataLoaded = false;
|
||||
export let created_via = "all";
|
||||
export let current_runners = [];
|
||||
$: sponsoring_contracts_show = selected.length > 0;
|
||||
$: cards_show = selected.length > 0;
|
||||
@@ -103,7 +104,7 @@
|
||||
header: () => $_("action"),
|
||||
cell: (info) => {
|
||||
return renderComponent(TableActions, {
|
||||
detailsLink: `./${info.row.original.id}`,
|
||||
detailsLink: `/runners/detail/${info.row.original.id}`,
|
||||
deleteAction: () => {
|
||||
active_delete =
|
||||
current_runners[
|
||||
@@ -161,7 +162,11 @@
|
||||
|
||||
let page = 0;
|
||||
while (page >= 0) {
|
||||
const runners = await RunnerService.runnerControllerGetAll(page, 500);
|
||||
const runners = await RunnerService.runnerControllerGetAll(
|
||||
page,
|
||||
500,
|
||||
created_via
|
||||
);
|
||||
if (runners.length == 0) {
|
||||
page = -2;
|
||||
}
|
||||
@@ -180,6 +185,7 @@
|
||||
import store from "../../store";
|
||||
import AddRunnerModal from "./AddRunnerModal.svelte";
|
||||
import ImportRunnerModal from "./ImportRunnerModal.svelte";
|
||||
import toast from "svelte-french-toast";
|
||||
$: current_runners = [];
|
||||
export let modal_open = false;
|
||||
export let import_modal_open = false;
|
||||
@@ -189,6 +195,9 @@
|
||||
<h4 class="mb-1 text-3xl font-extrabold leading-tight">
|
||||
{$_("runners")}
|
||||
</h4>
|
||||
{#if created_via !== "all"}
|
||||
<p>created_via={created_via}</p>
|
||||
{/if}
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("RUNNER:CREATE")}
|
||||
<button
|
||||
on:click={() => {
|
||||
|
@@ -170,7 +170,7 @@
|
||||
<img
|
||||
class:w-[50%]={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"
|
||||
src={textToBase64Barcode(window.config.baseurl, is_qrcode)}
|
||||
/>
|
||||
@@ -178,7 +178,7 @@
|
||||
<img
|
||||
class:w-[50%]={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"
|
||||
src={barcode}
|
||||
/>
|
||||
|
@@ -204,6 +204,7 @@
|
||||
"donors-are-being-loaded": "Sponsoren werden geladen",
|
||||
"dont-have-your-email-connected": "Deine E-Mail ist nicht verknüpft?",
|
||||
"dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌",
|
||||
"download_laeuft": "Download läuft...",
|
||||
"e-mail-adress": "E-Mail-Adresse",
|
||||
"edit": "Bearbeiten",
|
||||
"edit-a-card": "Läuferkarte bearbeiten",
|
||||
@@ -381,6 +382,7 @@
|
||||
"runners": "Läufer",
|
||||
"runners-are-being-imported": "Läufer werden importiert ...",
|
||||
"runners-are-being-loaded": "Läufer werden geladen ...",
|
||||
"runners_via_kiosk": "Läufer via Kiosk",
|
||||
"save": "Speichern",
|
||||
"save-changes": "Änderungen speichern",
|
||||
"scan-added": "Scan hinzugefügt",
|
||||
|
@@ -204,6 +204,7 @@
|
||||
"donors-are-being-loaded": "donors are being loaded",
|
||||
"dont-have-your-email-connected": "Don't have your email connected?",
|
||||
"dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌",
|
||||
"download_laeuft": "Download in progress...",
|
||||
"e-mail-adress": "E-Mail Adress",
|
||||
"edit": "Edit",
|
||||
"edit-a-card": "Edit a card",
|
||||
@@ -381,6 +382,7 @@
|
||||
"runners": "Runners",
|
||||
"runners-are-being-imported": "Runners are being imported...",
|
||||
"runners-are-being-loaded": "runners are being loaded...",
|
||||
"runners_via_kiosk": "Runners via Kiosk",
|
||||
"save": "Save",
|
||||
"save-changes": "Save Changes",
|
||||
"scan-added": "Scan added",
|
||||
|
Reference in New Issue
Block a user