Compare commits

...

36 Commits

Author SHA1 Message Date
e75be49be4 🚀RELEASE v1.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-19 17:41:40 +02:00
505fb8cb08 feat(donations): Implemented donation deletion via confirm modal 2023-04-19 17:41:21 +02:00
e5c9265588 feat(donations): Implemented add donation payment via datatable refresh 2023-04-19 17:34:34 +02:00
02003ec80e feat(donations): Donations reactive create and load into datatable 2023-04-19 17:21:24 +02:00
133470b6f2 feat(donationsoverview): Switched donations overview to datatable 2023-04-19 17:12:04 +02:00
4a6230c439 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-19 16:56:23 +02:00
fdc7d80bbf 🚀RELEASE v1.2.0 2023-04-19 16:56:09 +02:00
352551e168 feat(donorsoverview): Dynamicly add newly generated donors 2023-04-19 16:55:14 +02:00
7aec050419 feat(donorsoverview): Implemented delete confirmation with datatable 2023-04-19 16:49:54 +02:00
4289034436 new license file version [CI SKIP] 2023-04-19 14:45:02 +00:00
8f8858f100 feat(DonationsOverview): i18n loading text
All checks were successful
continuous-integration/drone/push Build is passing
2023-04-19 16:44:39 +02:00
d98fb0d5b2 feat(donoroverview): Added datatable formatters 2023-04-19 16:39:30 +02:00
5014bf5bc5 feat(donors): Load donors paginated 2023-04-19 16:23:00 +02:00
0708cabc75 🚀RELEASE v1.1.0
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-19 16:05:21 +02:00
4fcb26cf93 feat(dashboard): Updated stats icons 2023-04-19 16:04:02 +02:00
269def20d1 feat(dashboard): Added average sponsoring
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-19 15:59:45 +02:00
b8de9e0e42 feat(dashboard): Added average distance 2023-04-19 15:57:46 +02:00
7b2b598588 feat(dashboard): Added total donations 2023-04-19 15:56:21 +02:00
e0b61486b0 feat(dashboar): Added total donors to overview 2023-04-19 15:54:39 +02:00
3f86f7412f Lockfile 2023-04-19 15:53:33 +02:00
6454d960de Bumped client 2023-04-19 15:53:28 +02:00
37154c188b Merge branch 'dev' of git.odit.services:lfk/frontend into dev
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-19 15:38:15 +02:00
8da7578a0a 🚀RELEASE v1.0.0 2023-04-19 15:37:56 +02:00
2a64094006 new license file version [CI SKIP] 2023-04-19 13:37:32 +00:00
e9ce9644ff Merge pull request 'feature/175-request_pagination' (#176) from feature/175-request_pagination into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #176
2023-04-19 13:37:16 +00:00
52439aa5bc Allways set loaded to true
ref #175
2023-04-18 20:47:42 +02:00
ccf865687b Donation paginated loading
ref #175
2023-04-18 20:46:18 +02:00
cac34db1fd Paginated scan loading
ref #175
2023-04-18 20:43:04 +02:00
faf3893180 Paginated runner loading (1000 per page)
ref #175
2023-04-18 20:40:28 +02:00
c33dfcfddd Implemented Async loading of cards via pagination (500 cards per request)
ref #175
2023-04-18 20:38:01 +02:00
019e14ab1f Bumped lfk client
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-18 20:18:46 +02:00
b5790196c6 Merge branch 'dev' of git.odit.services:lfk/frontend into dev
Some checks failed
continuous-integration/drone/push Build is failing
2023-04-17 17:56:42 +02:00
94a64ca690 🚀RELEASE v0.19.0 2023-04-17 17:56:34 +02:00
a6ce04c903 new license file version [CI SKIP] 2023-04-17 15:56:08 +00:00
165c154233 Merge pull request 'feature/173-scanstation_configcodes' (#174) from feature/173-scanstation_configcodes into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #174
2023-04-17 15:55:53 +00:00
318547db46 Adjusted size on smaller devices
ref #173
2023-04-17 17:55:33 +02:00
27 changed files with 2582 additions and 1947 deletions

View File

@@ -2,8 +2,72 @@
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.3.0](https://git.odit.services/lfk/frontend/compare/1.2.0...1.3.0)
- feat(donations): Implemented donation deletion via confirm modal [`505fb8c`](https://git.odit.services/lfk/frontend/commit/505fb8cb08b81a7dcb08561bdda0f6464f140d3e)
- feat(donationsoverview): Switched donations overview to datatable [`133470b`](https://git.odit.services/lfk/frontend/commit/133470b6f2a63ec087f27c98ef260648a8672e5f)
- feat(donations): Implemented add donation payment via datatable refresh [`e5c9265`](https://git.odit.services/lfk/frontend/commit/e5c92655886ad9a6fcd7565fadd7955c477c3595)
- feat(donations): Donations reactive create and load into datatable [`02003ec`](https://git.odit.services/lfk/frontend/commit/02003ec80efc16aabd126710a6eeac18df43f841)
- feat(DonationsOverview): i18n loading text [`8f8858f`](https://git.odit.services/lfk/frontend/commit/8f8858f10071ddf9988d0ec0e3c4a891db24a102)
- new license file version [CI SKIP] [`4289034`](https://git.odit.services/lfk/frontend/commit/4289034436869750205a946247e7ab5f9892fe98)
#### [1.2.0](https://git.odit.services/lfk/frontend/compare/1.1.0...1.2.0)
> 19 April 2023
- feat(donoroverview): Added datatable formatters [`d98fb0d`](https://git.odit.services/lfk/frontend/commit/d98fb0d5b288c987a45ccbf2bb026ccaab539a71)
- 🚀RELEASE v1.2.0 [`fdc7d80`](https://git.odit.services/lfk/frontend/commit/fdc7d80bbf9bd698128e9ec4f91fa813499777a9)
- feat(donors): Load donors paginated [`5014bf5`](https://git.odit.services/lfk/frontend/commit/5014bf5bc5873cfe4ae04d71b4aff12b257dd2e3)
- feat(donorsoverview): Dynamicly add newly generated donors [`352551e`](https://git.odit.services/lfk/frontend/commit/352551e168b5dced5e7353e82655908d82d28af0)
- feat(donorsoverview): Implemented delete confirmation with datatable [`7aec050`](https://git.odit.services/lfk/frontend/commit/7aec050419f6f1bf853c3e1bc655b01725ed3b65)
#### [1.1.0](https://git.odit.services/lfk/frontend/compare/1.0.0...1.1.0)
> 19 April 2023
- 🚀RELEASE v1.1.0 [`0708cab`](https://git.odit.services/lfk/frontend/commit/0708cabc75e63a876e54a0b343318f8d934ae319)
- feat(dashboar): Added total donors to overview [`e0b6148`](https://git.odit.services/lfk/frontend/commit/e0b61486b089aa1e611ef3569b1521fc331ec0e4)
- feat(dashboard): Updated stats icons [`4fcb26c`](https://git.odit.services/lfk/frontend/commit/4fcb26cf9371e27e5d7e474b3558ef354e9114c0)
- feat(dashboard): Added average sponsoring [`269def2`](https://git.odit.services/lfk/frontend/commit/269def20d114ededaba3153bbd50ec2ddd70e1c6)
- feat(dashboard): Added total donations [`7b2b598`](https://git.odit.services/lfk/frontend/commit/7b2b59858839b98370af6fb1e6028ba0a1639186)
- feat(dashboard): Added average distance [`b8de9e0`](https://git.odit.services/lfk/frontend/commit/b8de9e0e427b3a8b56e6354ad7168ae12c7cce85)
- Lockfile [`3f86f74`](https://git.odit.services/lfk/frontend/commit/3f86f7412ffc4bc27328ad1f7d3c3118546e7e29)
- Bumped client [`6454d96`](https://git.odit.services/lfk/frontend/commit/6454d960de3f9f5ea86679f157b3b7e7cffde74d)
- new license file version [CI SKIP] [`2a64094`](https://git.odit.services/lfk/frontend/commit/2a640940062765a470387103a72ed14a2411d97b)
### [1.0.0](https://git.odit.services/lfk/frontend/compare/0.19.0...1.0.0)
> 19 April 2023
- 🚀RELEASE v1.0.0 [`8da7578`](https://git.odit.services/lfk/frontend/commit/8da7578a0a46a3e97d8c870e29399f6e8821c9fa)
- Merge pull request 'feature/175-request_pagination' (#176) from feature/175-request_pagination into dev [`e9ce964`](https://git.odit.services/lfk/frontend/commit/e9ce9644ff03f981cec6e9ad56aa5fdf0ff71ef4)
- Donation paginated loading [`ccf8656`](https://git.odit.services/lfk/frontend/commit/ccf865687b34016931a702c0a9b98a0a18e2b03a)
- Paginated scan loading [`cac34db`](https://git.odit.services/lfk/frontend/commit/cac34db1fd3bf5dc7c7be64b3a76ca4c8c77938d)
- Implemented Async loading of cards via pagination (500 cards per request) [`c33dfcf`](https://git.odit.services/lfk/frontend/commit/c33dfcfddddfed0902f3fa9b1d8a1d3e1560262f)
- Paginated runner loading (1000 per page) [`faf3893`](https://git.odit.services/lfk/frontend/commit/faf3893180bb735bea6f1ea58c896686b89949fe)
- Allways set loaded to true [`52439aa`](https://git.odit.services/lfk/frontend/commit/52439aa5bc8cfb1d78d5dfce55b1a0df640ad8f5)
- Bumped lfk client [`019e14a`](https://git.odit.services/lfk/frontend/commit/019e14ab1f99906f13d36c7148d0f4b7894072f2)
- new license file version [CI SKIP] [`a6ce04c`](https://git.odit.services/lfk/frontend/commit/a6ce04c90386f16abf235cc7b2f95aeea5011c7d)
#### [0.19.0](https://git.odit.services/lfk/frontend/compare/0.18.4...0.19.0)
> 17 April 2023
- 🚀RELEASE v0.19.0 [`94a64ca`](https://git.odit.services/lfk/frontend/commit/94a64ca69078c7fe2935eeb5f955fab95a79cb85)
- Merge pull request 'feature/173-scanstation_configcodes' (#174) from feature/173-scanstation_configcodes into dev [`165c154`](https://git.odit.services/lfk/frontend/commit/165c1542338c58f2abf42fef2e7b84b40d1e2d9c)
- I18n [`e60c09e`](https://git.odit.services/lfk/frontend/commit/e60c09e19c9cc20338906e84f4db4e009d926360)
- Implemented config code generation [`4b63427`](https://git.odit.services/lfk/frontend/commit/4b6342727ee0ea38597750d8c99edc301f1ccc2d)
- Styling [`4834d14`](https://git.odit.services/lfk/frontend/commit/4834d1484c3fb6ecd4a1b56aa9fbb8125c641a62)
- Adjusted size on smaller devices [`318547d`](https://git.odit.services/lfk/frontend/commit/318547db46045e41de64d5688368e85cd6fb8035)
- Lockfile [`947d01c`](https://git.odit.services/lfk/frontend/commit/947d01cf7fc7fe2ee88c56e017b0d663f1f3b4f9)
- Barcode placeholder [`cb5fa52`](https://git.odit.services/lfk/frontend/commit/cb5fa52cd9a97490b50fb0c02c26615b49650c08)
- Added bwip-js for barcode generation [`3563394`](https://git.odit.services/lfk/frontend/commit/3563394fb33d661890327e2ae08c400830b37844)
#### [0.18.4](https://git.odit.services/lfk/frontend/compare/0.18.3...0.18.4) #### [0.18.4](https://git.odit.services/lfk/frontend/compare/0.18.3...0.18.4)
> 15 April 2023
- 🚀RELEASE v0.18.4 [`269d7a7`](https://git.odit.services/lfk/frontend/commit/269d7a7defdde059ef2bb5103262cf734e9babe9)
- Hide address2 in orgs by default [`e95f233`](https://git.odit.services/lfk/frontend/commit/e95f2333b0b958ed00c0e097b43aac2e70ad0d38) - Hide address2 in orgs by default [`e95f233`](https://git.odit.services/lfk/frontend/commit/e95f2333b0b958ed00c0e097b43aac2e70ad0d38)
#### [0.18.3](https://git.odit.services/lfk/frontend/compare/0.18.2...0.18.3) #### [0.18.3](https://git.odit.services/lfk/frontend/compare/0.18.2...0.18.3)

View File

@@ -13,7 +13,7 @@
</head> </head>
<body> <body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.18.4-RELEASE_INFO</span> <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-1.3.0-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>
<script type="module" src="/src/main.js"></script> <script type="module" src="/src/main.js"></script>

View File

@@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "0.18.4", "version": "1.3.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",
@@ -39,7 +39,7 @@
} }
}, },
"dependencies": { "dependencies": {
"@odit/lfk-client-js": "0.14.3", "@odit/lfk-client-js": "1.1.0",
"@paralleldrive/cuid2": "^2.2.0", "@paralleldrive/cuid2": "^2.2.0",
"@tanstack/svelte-table": "^8.8.5", "@tanstack/svelte-table": "^8.8.5",
"bwip-js": "^3.4.0", "bwip-js": "^3.4.0",

8
pnpm-lock.yaml generated
View File

@@ -2,8 +2,8 @@ lockfileVersion: '6.0'
dependencies: dependencies:
'@odit/lfk-client-js': '@odit/lfk-client-js':
specifier: 0.14.3 specifier: 1.1.0
version: 0.14.3 version: 1.1.0
'@paralleldrive/cuid2': '@paralleldrive/cuid2':
specifier: ^2.2.0 specifier: ^2.2.0
version: 2.2.0 version: 2.2.0
@@ -510,8 +510,8 @@ packages:
'@octokit/openapi-types': 16.0.0 '@octokit/openapi-types': 16.0.0
dev: true dev: true
/@odit/lfk-client-js@0.14.3: /@odit/lfk-client-js@1.1.0:
resolution: {integrity: sha512-oOZ9jjzqcbMA0Sfwxn4q9+8hHckMU2IhAn7v0OAS54zcnquYQANnY4RMEoNIyXd0oEe1z8QewBjyBvFEDg6BmA==} resolution: {integrity: sha512-yhjsi7YMzL9/fJ7o06yszzw15iZhao3VmX0G9oqZWFwYJd1M2td3Lvm76mXNzTVlbdG6W0W3+eEjcalBdo51Pg==}
dev: false dev: false
/@odit/license-exporter@0.0.12: /@odit/license-exporter@0.0.12:

File diff suppressed because one or more lines are too long

View File

@@ -32,7 +32,7 @@
export let original_data = {}; export let original_data = {};
export let current_cards = []; export let current_cards = [];
export const addCards = (cards) => { export const addCards = (cards) => {
console.log(cards) console.log(cards);
current_cards = current_cards.concat(...cards); current_cards = current_cards.concat(...cards);
options.update((options) => ({ options.update((options) => ({
...options, ...options,
@@ -155,15 +155,27 @@
}).showToast(); }).showToast();
} }
onMount(() => { onMount(async () => {
RunnerCardService.runnerCardControllerGetAll().then((val) => { let page = 0;
current_cards = val; while (page >= 0) {
const cards = await RunnerCardService.runnerCardControllerGetAll(
page,
500
);
if (cards.length == 0) {
page = -2;
}
current_cards = current_cards.concat(...cards);
options.update((options) => ({ options.update((options) => ({
...options, ...options,
data: current_cards, data: current_cards,
})); }));
dataLoaded = true; dataLoaded = true;
}); page++;
}
console.log("All cards loaded");
}); });
</script> </script>
@@ -229,7 +241,7 @@
...options, ...options,
data: current_cards, data: current_cards,
})); }));
$table.resetRowSelection() $table.resetRowSelection();
}} }}
> >
{$_("delete-cards")} {$_("delete-cards")}
@@ -249,7 +261,10 @@
</svg> </svg>
</button> </button>
{/if} {/if}
<GenerateRunnerCards cards_show={selected.length>0} bind:generate_cards={selectedCards} /> <GenerateRunnerCards
cards_show={selected.length > 0}
bind:generate_cards={selectedCards}
/>
</div> </div>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="w-full"> <table class="w-full">

View File

@@ -35,7 +35,9 @@
<p class="text-sm">{$_("this-might-take-a-moment")}</p> <p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:then stats} {:then stats}
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 2xl:grid-cols-6 gap-4"> <div
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 2xl:grid-cols-6 gap-4"
>
<StatCard <StatCard
title={$_("runners")} title={$_("runners")}
value={stats.total_runners} value={stats.total_runners}
@@ -59,18 +61,67 @@
href="/scans/" href="/scans/"
> >
<svg <svg
stroke="currentColor"
fill="currentColor" fill="currentColor"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
size="24"
class="stroke-current text-grey-500"
height="24"
width="24" width="24"
height="24"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
><polyline points="22 12 18 12 15 21 9 3 6 12 2 12" /></svg viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M2 4h2v16H2V4zm4 0h1v16H6V4zm2 0h2v16H8V4zm3 0h2v16h-2V4zm3 0h2v16h-2V4zm3 0h1v16h-1V4zm2 0h3v16h-3V4z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-donors")}
value={stats.total_donors}
href="/donors/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"
/></svg
>
</StatCard>
<StatCard
title={$_("total-donation-count")}
value={stats.total_donations}
href="/donations/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</StatCard>
<StatCard
title={$_("average-donation")}
value={`${(stats.average_donation / 100).toFixed(2)} €`}
href="/donations/"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
> >
</StatCard> </StatCard>
<StatCard <StatCard
@@ -105,6 +156,22 @@
/></svg /></svg
> >
</StatCard> </StatCard>
<StatCard
title={$_("average-distance")}
value={`${(stats.average_distance / 1000).toFixed(2)} km`}
href="#"
>
<svg
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
height="24"
width="24"
><path d="M0 0h24v24H0z" fill="none" />
<path
d="M21 6H3c-1.1 0-2 .9-2 2v8c0 1.1.9 2 2 2h18c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 10H3V8h2v4h2V8h2v4h2V8h2v4h2V8h2v4h2V8h2v8z"
/></svg
>
</StatCard>
<StatCard <StatCard
title={$_("count_teams")} title={$_("count_teams")}
value={stats.total_teams} value={stats.total_teams}

View File

@@ -9,9 +9,10 @@
} from "@odit/lfk-client-js"; } from "@odit/lfk-client-js";
import Select from "svelte-select"; import Select from "svelte-select";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { is_promise } from "svelte/internal"; import { is_promise } from "svelte/internal";
import { createEventDispatcher } from "svelte";
export let modal_open; export let modal_open;
export let current_donations; const dispatch = createEventDispatcher();
const getDonorLabel = (option) => const getDonorLabel = (option) =>
option.firstname + " " + (option.middlename || "") + " " + option.lastname; option.firstname + " " + (option.middlename || "") + " " + option.lastname;
const filterDonors = (label, filterText, option) => const filterDonors = (label, filterText, option) =>
@@ -59,16 +60,16 @@ import { is_promise } from "svelte/internal";
let amount_cent = Math.floor(amount_input * 100); let amount_cent = Math.floor(amount_input * 100);
processed_last_submit = false; processed_last_submit = false;
const toast = Toastify({ const toast = Toastify({
text: $_('adding-donation'), text: $_("adding-donation"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
if (is_fixed) { if (is_fixed) {
let postdata = { let postdata = {
donor, donor,
amount: amount_cent, amount: amount_cent,
paidAmount: 0 paidAmount: 0,
}; };
if(is_paid){ if (is_paid) {
postdata.paidAmount = amount_cent; postdata.paidAmount = amount_cent;
} }
DonationService.donationControllerPostFixed(postdata) DonationService.donationControllerPostFixed(postdata)
@@ -79,12 +80,11 @@ import { is_promise } from "svelte/internal";
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: $_('donation_added'), text: $_("donation_added"),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_donations.push(result); dispatch("created", { donations: [result] });
current_donations = current_donations;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -108,12 +108,11 @@ import { is_promise } from "svelte/internal";
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: $_('donation_added'), text: $_("donation_added"),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_donations.push(result); dispatch("created", { donations: [result] });
current_donations = current_donations;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -128,6 +127,207 @@ import { is_promise } from "svelte/internal";
} }
</script> </script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<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">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
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">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{#if is_fixed}
{$_("create-a-new-fixed-donation")}
{:else}{$_("create-a-new-distance-donation")}{/if}
</h3>
<label class="content-center align-middle object-center">
<span class="ml-2 text-base" class:text-gray-300={is_fixed}
>{$_("distance-donation")}</span
>
<input
class="toggle relative w-10 h-5 transition-all duration-200 ease-in-out bg-gray-400 rounded-full shadow-inner outline-none appearance-none align-middle"
type="checkbox"
bind:checked={is_fixed}
/>
<span class="ml-2 text-base" class:text-gray-300={!is_fixed}
>{$_("fixed-donation")}</span
>
</label>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
"please-provide-the-nessecary-information-to-create-a-new-donation"
)}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700"
>{$_("donor")}</label
>
<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-gray-500 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={donors}
showChevron={true}
placeholder={$_("search-for-donor-name-or-id")}
noOptionsMessage={$_("no-donors-found")}
on:select={(selectedValue) =>
(donor = selectedValue.detail.value.id)}
on:clear={() => (donors = null)}
/>
</div>
{#if !is_fixed}
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700"
>{$_("runner")}</label
>
<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-gray-500 rounded-md p-2"
itemFilter={(label, filterText, option) =>
filterDonors(label, filterText, option)}
items={runners}
showChevron={true}
placeholder={$_("search-for-runner-by-name-or-id")}
noOptionsMessage={$_("no-runners-found")}
on:select={(selectedValue) =>
(runner = selectedValue.detail.value.id)}
on:clear={() => (runner = null)}
/>
</div>
{/if}
<div class="col-span-6">
<label
for="donation_amount_eur"
class="block text-sm font-medium text-gray-700"
>
{#if !is_fixed}
{$_("amount-per-kilometer")}
{:else}{$_("donation-amount")}{/if}</label
>
<div class="mt-1 flex rounded-md shadow-sm">
<input
autocomplete="off"
class:border-red-500={!is_amount_valid}
class:focus:border-red-500={!is_amount_valid}
class:focus:ring-red-500={!is_amount_valid}
bind:value={amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2"
placeholder="2.00"
/>
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
></span
>
</div>
{#if !is_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
>
{$_("donation-amount-must-be-greater-that-0-00eur")}
</span>
{/if}
</div>
{#if is_fixed}
<div class="col-span-6">
<label
for="paid"
class="block text-sm font-medium text-gray-700"
>{$_("already-paid")}</label
>
<p class="text-gray-500">
<input
id="paid"
bind:checked={is_paid}
name="paid"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
<span class="align-text-bottom">
{#if is_paid}
{$_("paid")}
{:else}
{$_("open")}
{/if}
</span>
</p>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
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 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("create")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}
<style> <style>
.toggle:before { .toggle:before {
content: ""; content: "";
@@ -152,173 +352,3 @@ import { is_promise } from "svelte/internal";
left: 1.25rem; left: 1.25rem;
} }
</style> </style>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<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">&#8203;</span>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
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">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z" /></svg>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{#if is_fixed}
{$_('create-a-new-fixed-donation')}
{:else}{$_('create-a-new-distance-donation')}{/if}
</h3>
<label class="content-center align-middle object-center">
<span
class="ml-2 text-base"
class:text-gray-300={is_fixed}>{$_('distance-donation')}</span>
<input
class="toggle relative w-10 h-5 transition-all duration-200 ease-in-out bg-gray-400 rounded-full shadow-inner outline-none appearance-none align-middle"
type="checkbox"
bind:checked={is_fixed} />
<span
class="ml-2 text-base "
class:text-gray-300={!is_fixed}>{$_('fixed-donation')}</span>
</label>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_('please-provide-the-nessecary-information-to-create-a-new-donation')}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700">{$_('donor')}</label>
<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-gray-500 rounded-md p-2"
itemFilter={(label, filterText, option) => filterDonors(label, filterText, option)}
items={donors}
showChevron={true}
placeholder={$_('search-for-donor-name-or-id')}
noOptionsMessage={$_('no-donors-found')}
on:select={(selectedValue) => (donor = selectedValue.detail.value.id)}
on:clear={() => (donors = null)} />
</div>
{#if !is_fixed}
<div class="col-span-6">
<label
for="donor"
class="block text-sm font-medium text-gray-700">{$_('runner')}</label>
<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-gray-500 rounded-md p-2"
itemFilter={(label, filterText, option) => filterDonors(label, filterText, option)}
items={runners}
showChevron={true}
placeholder={$_('search-for-runner-by-name-or-id')}
noOptionsMessage={$_('no-runners-found')}
on:select={(selectedValue) => (runner = selectedValue.detail.value.id)}
on:clear={() => (runner = null)} />
</div>
{/if}
<div class="col-span-6">
<label
for="donation_amount_eur"
class="block text-sm font-medium text-gray-700">
{#if !is_fixed}
{$_('amount-per-kilometer')}
{:else}{$_('donation-amount')}{/if}</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input
autocomplete="off"
class:border-red-500={!is_amount_valid}
class:focus:border-red-500={!is_amount_valid}
class:focus:ring-red-500={!is_amount_valid}
bind:value={amount_input}
type="number"
step="0.01"
name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2"
placeholder="2.00" />
<span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"></span>
</div>
{#if !is_amount_valid}
<span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
{$_('donation-amount-must-be-greater-that-0-00eur')}
</span>
{/if}
</div>
{#if is_fixed}
<div class="col-span-6">
<label
for="paid"
class="block text-sm font-medium text-gray-700">{$_('already-paid')}</label>
<p class="text-gray-500">
<input
id="paid"
bind:checked={is_paid}
name="paid"
type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" >
<span class="align-text-bottom">
{#if is_paid}
{$_('paid')}
{:else}
{$_('open')}
{/if}
</span>
</p>
</div>
{/if}
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
disabled={!createbtnenabled}
class:opacity-50={!createbtnenabled}
on:click={submit}
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 sm:ml-3 sm:w-auto sm:text-sm">
{$_('create')}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
{$_('cancel')}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -4,16 +4,18 @@
import { DonationService } from "@odit/lfk-client-js"; import { DonationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let payment_modal_open = false; export let payment_modal_open = false;
export let current_donations = [];
export let editable = {};
export let original_data = {}; export let original_data = {};
export let paid_amount_input = 0; export let paid_amount_input = 0;
$:processed_last_submit=true; const dispatch = createEventDispatcher();
$: processed_last_submit = true;
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
$: createbtnenabled = is_paid_amount_valid && !(paid_amount_input*100 == original_data.paidAmount) $: createbtnenabled =
is_paid_amount_valid &&
!(paid_amount_input * 100 == original_data.paidAmount);
$: is_paid_amount_valid = paid_amount_input > 0; $: is_paid_amount_valid = paid_amount_input > 0;
(() => { (() => {
document.onkeydown = (e) => { document.onkeydown = (e) => {
@@ -33,61 +35,56 @@
if (processed_last_submit === true) { if (processed_last_submit === true) {
processed_last_submit = false; processed_last_submit = false;
const toast = Toastify({ const toast = Toastify({
text: $_('updating-donation'), text: $_("updating-donation"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
const editable = Object.assign({}, original_data);
editable.donor = editable.donor.id; editable.donor = editable.donor.id;
editable.paidAmount = paid_amount_input*100; editable.paidAmount = paid_amount_input * 100;
if(editable.responseType == "DISTANCEDONATION" || editable.runner){ if (editable.responseType == "DISTANCEDONATION" || editable.runner) {
editable.runner = editable.runner.id; editable.runner = editable.runner.id;
DonationService.donationControllerPutDistance(original_data.id, editable) DonationService.donationControllerPutDistance(
.then((result) => { original_data.id,
let id = original_data.id; editable
editable = {}; )
original_data = {}; .then((result) => {
payment_modal_open = false; payment_modal_open = false;
// //
Toastify({ Toastify({
text: $_('donation-updated'), text: $_("donation-updated"),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_donations[current_donations.findIndex((c) => c.id === id)] = result; dispatch("created", { donation: response });
current_donations = current_donations; })
}) .catch((err) => {
.catch((err) => { //
// })
}) .finally(() => {
.finally(() => { processed_last_submit = true;
processed_last_submit = true; //
// toast.hideToast();
toast.hideToast(); });
}); } else {
} DonationService.donationControllerPutFixed(original_data.id, editable)
else{ .then((result) => {
DonationService.donationControllerPutFixed(original_data.id, editable) payment_modal_open = false;
.then((result) => { //
let id = original_data.id; Toastify({
editable = {}; text: $_("donation-updated"),
original_data = {}; duration: 500,
payment_modal_open = false; backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
// }).showToast();
Toastify({ dispatch("created", { donation: response });
text: $_('donation-updated'), })
duration: 500, .catch((err) => {
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", //
}).showToast(); })
current_donations[current_donations.findIndex((c) => c.id === id)] = result; .finally(() => {
current_donations = current_donations; processed_last_submit = true;
}) //
.catch((err) => { toast.hideToast();
// });
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
} }
} }
} }
@@ -96,57 +93,71 @@
{#if payment_modal_open} {#if payment_modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
payment_modal_open = false; payment_modal_open = false;
}}> }}
>
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div <div
class="absolute inset-0 bg-gray-500 opacity-75" class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop" /> data-id="modal_backdrop"
/>
</div> </div>
<span <span
class="hidden sm:inline-block sm:align-middle sm:h-screen" class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span> aria-hidden="true">&#8203;</span
>
<div <div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
aria-labelledby="modal-headline"> aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start"> <div class="sm:flex sm:items-start">
<div <div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg <svg
class="h-6 w-6 text-blue-600" class="h-6 w-6 text-blue-600"
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="24" width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" /> height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path <path
fill="currentColor" fill="currentColor"
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z" /></svg> d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
/></svg
>
</div> </div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
{$_('enter-payment')} {$_("enter-payment")}
</h3> </h3>
<div class="mt-2 mb-6"> <div class="mt-2 mb-6">
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
{$_('you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount')} {$_(
"you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount"
)}
</p> </p>
</div> </div>
<div class="grid grid-cols gap-6"> <div class="grid grid-cols gap-6">
<div class="w-full"> <div class="w-full">
<label <label
for="token" for="token"
class="block text-sm font-medium text-gray-700">{$_('paid-amount')}</label> class="block text-sm font-medium text-gray-700"
<div class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full"> >{$_("paid-amount")}</label
<input >
<div
class="inline-flex border-gray-300 border rounded-l-md rounded-r-md bg-gray-50 text-gray-500 w-full"
>
<input
autocomplete="off" autocomplete="off"
class:border-red-500={!is_paid_amount_valid} class:border-red-500={!is_paid_amount_valid}
class:focus:border-red-500={!is_paid_amount_valid} class:focus:border-red-500={!is_paid_amount_valid}
@@ -156,47 +167,55 @@
step="0.01" step="0.01"
name="donation_amount_eur" name="donation_amount_eur"
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm p-2"
placeholder="2.00" /> placeholder="2.00"
/>
<button <button
on:click={ on:click={() => {
()=>{ paid_amount_input = paid_amount_input = (
paid_amount_input=paid_amount_input = (original_data.amount/100).toFixed(2); original_data.amount / 100
} ).toFixed(2);
} }}
class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm">MAX</button> class="inline-flex items-center p-r-2 text-indigo-300 hover:text-indigo-700 text-sm"
>MAX</button
>
<span <span
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"></span> class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
></span
>
</div> </div>
{#if !is_paid_amount_valid} {#if !is_paid_amount_valid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('payment-amount-must-be-greater-than-0-00eur')} >
{$_("payment-amount-must-be-greater-than-0-00eur")}
</span> </span>
{/if} {/if}
</div> </div>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse"> </div>
<button <div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
disabled={!createbtnenabled} <button
class:opacity-50={!createbtnenabled} disabled={!createbtnenabled}
on:click={submit} class:opacity-50={!createbtnenabled}
type="button" on:click={submit}
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 sm:ml-3 sm:w-auto sm:text-sm"> type="button"
{$_('save-changes')} 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 sm:ml-3 sm:w-auto sm:text-sm"
</button> >
<button {$_("save-changes")}
on:click={() => { </button>
payment_modal_open = false; <button
}} on:click={() => {
type="button" payment_modal_open = false;
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> }}
{$_('cancel')} type="button"
</button> class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
</div> >
{$_("cancel")}
</button>
</div> </div>
</div> </div>
</div> </div>
</div>
{/if} {/if}

View File

@@ -0,0 +1,122 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { createEventDispatcher, onMount } from "svelte";
export let modal_open;
export let delete_donation = {
id: 0,
runner: {
firstname: "",
lastname: "",
},
donor: {
firstname: "",
lastname: "",
},
};
const dispatch = createEventDispatcher();
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();
}
}
};
});
async function submit() {
dispatch("delete", { id: delete_donation.id });
modal_open = false;
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside
on:click_outside={() => {
modal_open = false;
}}
>
<div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<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">&#8203;</span
>
<div
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
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">
<div class="sm:flex sm:items-start">
<div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path
d="M14 2a8 8 0 013.3 15.3A8 8 0 116.7 6.7 8 8 0 0114 2zm-3 7H9v1a2.5 2.5 0 00-.16 5h2.25a.5.5 0 010 1H7v2h2v1h2v-1a2.5 2.5 0 00.16-5H8.91a.5.5 0 010-1H13v-2h-2V9zm3-5a5.99 5.99 0 00-4.48 2.01 8 8 0 018.47 8.47A6 6 0 0014 4z"
/></svg
>
</div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900">
{$_("confirm-delete")}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_("please-confirm-the-deletion-of-donation")}
</p>
</div>
<div class="w-full">
<span class="inline-block"
><b>{$_("donor")}</b>: {delete_donation.donor.firstname}
{delete_donation.donor.lastname}</span
>
</div>
</div>
</div>
</div>
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
<button
on:click={submit}
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 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("delete")}
</button>
<button
on:click={() => {
modal_open = false;
}}
type="button"
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
>
{$_("cancel")}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -0,0 +1,18 @@
<script>
import { _ } from "svelte-i18n";
export let donor;
</script>
{#if !donor || donor.firstname == 0}
{$_("donor-has-no-associated-donations")}
{:else}
<div class="flex items-center">
<a
href="../donors/{donor.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{donor.firstname}
{#if donor.middlename}{donor.middlename}{/if}
{donor.lastname}</a
>
</div>
{/if}

View File

@@ -0,0 +1,18 @@
<script>
import { _ } from "svelte-i18n";
export let runner;
</script>
{#if !runner || runner.firstname == 0}
{$_("fixed-donation")}
{:else}
<div class="text-sm font-medium text-gray-900">
<a
href="../runners/{runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
>{runner.firstname}
{#if runner.middlename}{runner.middlename}{/if}
{runner.lastname}</a
>
</div>
{/if}

View File

@@ -0,0 +1,16 @@
<script>
import { _ } from "svelte-i18n";
export let status;
</script>
{#if status == "PAID"}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
>{$_("paid")}</span
>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
>{$_("open")}</span
>
{/if}

View File

@@ -0,0 +1,21 @@
<script>
import { _ } from "svelte-i18n";
import TableActions from "../shared/TableActions.svelte";
export let detailsLink;
export let detailsAction;
export let deleteEnabled;
export let deleteAction;
export let paymentAction;
</script>
<button
on:click={paymentAction}
class="text-[#025a21] hover:text-green-900 mr-4">{$_("enter-payment")}</button
>
<TableActions
bind:detailsAction
bind:detailsLink
bind:deleteAction
bind:deleteEnabled
/>

View File

@@ -5,25 +5,33 @@
import DonationsOverview from "./DonationsOverview.svelte"; import DonationsOverview from "./DonationsOverview.svelte";
$: current_donations = []; $: current_donations = [];
export let modal_open = false; export let modal_open = false;
let addDonations;
</script> </script>
<section class="container p-5"> <section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight"> <span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('donations')} {$_("donations")}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")}
<button <button
on:click={() => { on:click={() => {
modal_open = true; modal_open = true;
}} }}
type="button" 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 sm:ml-3 sm:w-auto sm:text-sm"> 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 sm:ml-3 sm:w-auto sm:text-sm"
{$_('add-donation')} >
{$_("add-donation")}
</button> </button>
{/if} {/if}
</span> </span>
<DonationsOverview bind:current_donations /> <DonationsOverview bind:current_donations bind:addDonations />
</section> </section>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:CREATE")}
<AddDonationModal bind:current_donations bind:modal_open /> <AddDonationModal
on:created={(event) => {
console.log(event)
addDonations(event.detail.donations);
}}
bind:modal_open
/>
{/if} {/if}

View File

@@ -1,235 +1,279 @@
<script> <script>
import { getLocaleFromNavigator, _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { DonationService, DonorService } from "@odit/lfk-client-js"; import { DonationService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import Toastify from "toastify-js";
import DonationsEmptyState from "./DonationsEmptyState.svelte"; import DonationsEmptyState from "./DonationsEmptyState.svelte";
import AddDonationPaymentModal from "./AddDonationPaymentModal.svelte"; import AddDonationPaymentModal from "./AddDonationPaymentModal.svelte";
import { onMount } from "svelte";
import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { writable } from "svelte/store";
import TableBottom from "../shared/TableBottom.svelte";
import InputElement from "../shared/InputElement.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import DonationDonor from "./DonationDonor.svelte";
import DonationRunner from "./DonationRunner.svelte";
import DonationStatus from "./DonationStatus.svelte";
import DonationTableAction from "./DonationTableAction.svelte";
import DeleteDonationModal from "./DeleteDonationModal.svelte";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: active_edits = [];
$: selectedDonations =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: dataLoaded = false;
export let current_donations = []; export let current_donations = [];
export let payment_modal_open = false; export const addDonations = (donations) => {
export let editable = {}; current_donations = current_donations.concat(...donations);
export let original_data = {}; options.update((options) => ({
export let paid_amount_input = 0; ...options,
const donations_promise = DonationService.donationControllerGetAll().then( data: current_donations,
(val) => { }));
current_donations = val; };
}
); //Section table
function should_display_based_on_id(id) { const columns = [
if (searchvalue.toString().slice(-1) === "*") { {
return id.toString().startsWith(searchvalue.replace("*", "")); accessorKey: "id",
} header: () => "id",
return id.toString() === searchvalue; filterFn: `equalsString`,
} },
function open_payment_modal(donation) { {
editable = Object.assign({}, donation); accessorKey: "donor",
original_data = Object.assign({}, donation); header: () => $_("donor"),
paid_amount_input = (donation.paidAmount/100).toFixed(2); cell: (info) => {
payment_modal_open = true; return renderComponent(DonationDonor, { donor: info.getValue() });
},
filterFn: `includesString`,
},
{
accessorKey: "runner",
header: () => $_("runner"),
cell: (info) => {
return renderComponent(DonationRunner, { runner: info.getValue() });
},
filterFn: `includesString`,
},
{
accessorKey: "amountPerDistance",
header: () => $_("amount-per-kilometer"),
cell: (info) => {
if (!info.getValue()) {
return $_("fixed-donation");
}
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "amount",
header: () => $_("donation-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "paidAmount",
header: () => $_("total-paid-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })} €`;
},
enableColumnFilter: false,
},
{
accessorKey: "status",
header: () => $_("status"),
cell: (info) => {
return renderComponent(DonationStatus, { status: info.getValue() });
},
enableColumnFilter: false,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(DonationTableAction, {
detailsLink: `./${info.row.original.id}`,
deleteAction: () => {
active_deletes = current_donations.filter(
(r) => r.id == info.row.original.id
);
},
paymentAction: () => {
active_edits = current_donations.filter(
(r) => r.id == info.row.original.id
);
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes(
"DONATION:DELETE"
),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
const table = createSvelteTable(options);
async function deleteDonation(delete_donation_id) {
await DonationService.donationControllerRemove(delete_donation_id, true);
current_donations = current_donations.filter(
(r) => r.id !== delete_donation_id
);
options.update((options) => ({
...options,
data: current_donations,
}));
Toastify({
text: $_("donation-deleted"),
duration: 3500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
} }
onMount(async () => {
let page = 0;
while (page >= 0) {
const donations = await DonationService.donationControllerGetAll(
page,
500
);
if (donations.length == 0) {
page = -2;
}
current_donations = current_donations.concat(...donations);
options.update((options) => ({
...options,
data: current_donations,
}));
dataLoaded = true;
page++;
}
console.log("All donations loaded");
});
</script> </script>
<AddDonationPaymentModal bind:current_donations bind:original_data bind:editable bind:paid_amount_input bind:payment_modal_open /> <AddDonationPaymentModal
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')} original_data={active_edits[0]}
{#await donations_promise} payment_modal_open={active_edits.length > 0}
paid_amount_input={(active_edits[0]?.paidAmount || 0) / 100}
on:created={(event) => {
current_donations[
current_donations.findIndex((d) => d.id === event.detail.donation.id)
].paidAmount = event.detail.donation.paidAmount;
options.update((options) => ({
...options,
data: current_donations,
}));
}}
/>
<DeleteDonationModal
delete_donation={active_deletes[0]}
modal_open={active_deletes.length > 0}
on:delete={(event) => {
deleteDonation(event.detail.id);
}}
/>
{#if store.state.jwtinfo.userdetails.permissions.includes("DONATION:GET")}
{#if !dataLoaded}
<div <div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"> role="alert"
<p class="font-bold">donations are being loaded</p> >
<p class="text-sm">{$_('this-might-take-a-moment')}</p> <p class="font-bold">{$_("donations-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:then} {:else if current_donations.length === 0}
{#if current_donations.length === 0} <DonationsEmptyState />
<DonationsEmptyState /> {:else}
{:else} <input
<input type="search"
type="search" bind:value={searchvalue}
bind:value={searchvalue} placeholder={$_("datatable.search")}
placeholder={$_('datatable.search')} aria-label={$_("datatable.search")}
aria-label={$_('datatable.search')} class="mb-4"
class="mb-4" /> />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
<table class="divide-y divide-gray-200 w-full"> >
<thead class="bg-gray-50"> <table class="w-full">
<tr> <thead>
<th {#each $table.getHeaderGroups() as headerGroup}
scope="col" <tr class="select-none">
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
{$_('donor')} <InputElement
</th> type="checkbox"
<th checked={$table.getIsAllRowsSelected()}
scope="col" indeterminate={$table.getIsSomeRowsSelected()}
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> on:change={() => $table.toggleAllRowsSelected()}
{$_('runner')} />
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('amount-per-kilometer')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donation-amount')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('paid-amount')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('status')}
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span>
</th> </th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr> </tr>
</thead> {/each}
<tbody class="divide-y divide-gray-200"> </thead>
{#each current_donations as donation} <tbody>
{#if donation.donor.firstname {#each $table.getRowModel().rows as row}
.toLowerCase() <tr>
.includes( <td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
searchvalue.toLowerCase() <InputElement
) || donation.donor.lastname type="checkbox"
.toLowerCase() checked={row.getIsSelected()}
.includes( on:change={() => row.toggleSelected()}
searchvalue.toLowerCase() />
) || donation.runner?.firstname </td>
.toLowerCase() {#each row.getVisibleCells() as cell}
.includes( <td>
searchvalue.toLowerCase() <svelte:component
) || donation.runner?.lastname this={flexRender(
.toLowerCase() cell.column.columnDef.cell,
.includes( cell.getContext()
searchvalue.toLowerCase() )}
) || should_display_based_on_id(donation.id)} />
<tr data-rowid="donation_{donation.id}"> </td>
<td class="px-6 py-4 whitespace-nowrap"> {/each}
<div class="flex items-center"> </tr>
<a {/each}
href="../donors/{donation.donor.id}" </tbody>
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{donation.donor.firstname} </table>
{donation.donor.middlename || ''}
{donation.donor.lastname}</a>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.runner}
<div class="text-sm font-medium text-gray-900">
<a
href="../runners/{donation.runner.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{donation.runner.firstname}
{donation.runner.middlename || ''}
{donation.runner.lastname}</a>
</div>
{:else}
<div class="text-sm font-medium text-gray-900">
{$_('fixed-donation')}
</div>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.amountPerDistance}
<div class="text-sm font-medium text-gray-900">
{(donation.amountPerDistance / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</div>
{:else}
<div class="text-sm font-medium text-gray-900">
{$_('fixed-donation')}
</div>
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">
{(donation.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="text-sm font-medium text-gray-900">
{(donation.paidAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if donation.status =="PAID"}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('paid')}</span>
{:else}
<span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('open')}</span>
{/if}
</td>
{#if active_deletes[donation.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {
active_deletes[donation.id] = false;
}}
tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button
on:click={() => {
DonationService.donationControllerRemove(donation.id, false).then(
(resp) => {
current_donations = current_donations.filter(
(obj) => obj.id !== donation.id
);
Toastify({
text: $_('donation-deleted'),
duration: 500,
backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast();
}
);
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
</td>
{:else}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {open_payment_modal(donation);}}
class="text-[#025a21] hover:text-green-900 mr-4">{$_('enter-payment')}</button>
<a
href="./{donation.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:DELETE')}
<button
on:click={() => {
active_deletes[donation.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button>
{/if}
</td>
{/if}
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
{error}
</span>
</div> </div>
{/await} <div class="h-2" />
<TableBottom {table} {selected} />
{/if}
{/if} {/if}

View File

@@ -2,14 +2,12 @@
import { _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import { import { DonorService } from "@odit/lfk-client-js";
DonorService
} from "@odit/lfk-client-js";
import isEmail from "validator/es/lib/isEmail"; import isEmail from "validator/es/lib/isEmail";
import isMobilePhone from "validator/es/lib/isMobilePhone"; import isMobilePhone from "validator/es/lib/isMobilePhone";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let modal_open; export let modal_open;
export let current_donors;
let firstname_input; let firstname_input;
let lastname_input; let lastname_input;
let middlename_input; let middlename_input;
@@ -19,6 +17,7 @@
let address_input2; let address_input2;
let address_zipcode; let address_zipcode;
let address_city; let address_city;
const dispatch = createEventDispatcher();
function focus(el) { function focus(el) {
el.focus(); el.focus();
} }
@@ -75,7 +74,7 @@
if (processed_last_submit === true) { if (processed_last_submit === true) {
processed_last_submit = false; processed_last_submit = false;
const toast = Toastify({ const toast = Toastify({
text: $_('donor-is-being-added'), text: $_("donor-is-being-added"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
let address = {}; let address = {};
@@ -92,7 +91,7 @@
firstname: firstname_input_value, firstname: firstname_input_value,
lastname: lastname_input_value, lastname: lastname_input_value,
address, address,
receiptNeeded: address_checked receiptNeeded: address_checked,
}; };
if (middlename_input_value) { if (middlename_input_value) {
postdata.middlename = middlename_input_value; postdata.middlename = middlename_input_value;
@@ -112,12 +111,11 @@
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: $_('donor-added'), text: $_("donor-added"),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
current_donors.push(result); dispatch("created", { donors: [result] });
current_donors = current_donors;
}) })
.catch((err) => { .catch((err) => {
// //
@@ -134,58 +132,70 @@
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside use:clickOutside
on:click_outside={() => { on:click_outside={() => {
modal_open = false; modal_open = false;
}}> }}
>
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div <div
class="absolute inset-0 bg-gray-500 opacity-75" class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop" /> data-id="modal_backdrop"
/>
</div> </div>
<span <span
class="hidden sm:inline-block sm:align-middle sm:h-screen" class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span> aria-hidden="true">&#8203;</span
>
<div <div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
aria-labelledby="modal-headline"> aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start"> <div class="sm:flex sm:items-start">
<div <div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
>
<svg <svg
class="h-6 w-6 text-blue-600" class="h-6 w-6 text-blue-600"
fill="currentColor" fill="currentColor"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" viewBox="0 0 24 24"
width="24" width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" /> height="24"
><path fill="none" d="M0 0h24v24H0z" />
<path <path
d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z" /></svg> d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"
/></svg
>
</div> </div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
{$_('create-a-new-donor')} {$_("create-a-new-donor")}
</h3> </h3>
<div class="mt-2 mb-6"> <div class="mt-2 mb-6">
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
{$_('please-provide-the-nessecary-information-to-add-a-new-donor')} {$_(
"please-provide-the-nessecary-information-to-add-a-new-donor"
)}
</p> </p>
</div> </div>
<div class="grid grid-cols-6 gap-6"> <div class="grid grid-cols-6 gap-6">
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="firstname" for="firstname"
class="block text-sm font-medium text-gray-700">{$_('first-name')}</label> class="block text-sm font-medium text-gray-700"
>{$_("first-name")}</label
>
<input <input
use:focus use:focus
autocomplete="off" autocomplete="off"
placeholder={$_('first-name')} placeholder={$_("first-name")}
class:border-red-500={!isFirstnameValid} class:border-red-500={!isFirstnameValid}
class:focus:border-red-500={!isFirstnameValid} class:focus:border-red-500={!isFirstnameValid}
class:focus:ring-red-500={!isFirstnameValid} class:focus:ring-red-500={!isFirstnameValid}
@@ -193,34 +203,41 @@
bind:this={firstname_input} bind:this={firstname_input}
type="text" type="text"
name="firstname" name="firstname"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !isFirstnameValid} {#if !isFirstnameValid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('first-name-is-required')} >
{$_("first-name-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="trackname" for="trackname"
class="block text-sm font-medium text-gray-700">{$_('middle-name')}</label> class="block text-sm font-medium text-gray-700"
>{$_("middle-name")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('middle-name')} placeholder={$_("middle-name")}
bind:value={middlename_input_value} bind:value={middlename_input_value}
bind:this={middlename_input} bind:this={middlename_input}
type="text" type="text"
name="trackname" name="trackname"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="lastname" for="lastname"
class="block text-sm font-medium text-gray-700">{$_('last-name')}</label> class="block text-sm font-medium text-gray-700"
>{$_("last-name")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder="{$_('last-name')}" placeholder={$_("last-name")}
class:border-red-500={!isLastnameValid} class:border-red-500={!isLastnameValid}
class:focus:border-red-500={!isLastnameValid} class:focus:border-red-500={!isLastnameValid}
class:focus:ring-red-500={!isLastnameValid} class:focus:ring-red-500={!isLastnameValid}
@@ -228,21 +245,25 @@
bind:this={lastname_input} bind:this={lastname_input}
type="text" type="text"
name="lastname" name="lastname"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !isLastnameValid} {#if !isLastnameValid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('last-name-is-required')} >
{$_("last-name-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="phone" for="phone"
class="block text-sm font-medium text-gray-700">{$_('phone')}</label> class="block text-sm font-medium text-gray-700"
>{$_("phone")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('phone')} placeholder={$_("phone")}
class:border-red-500={!isPhoneValidOrEmpty} class:border-red-500={!isPhoneValidOrEmpty}
class:focus:border-red-500={!isPhoneValidOrEmpty} class:focus:border-red-500={!isPhoneValidOrEmpty}
class:focus:ring-red-500={!isPhoneValidOrEmpty} class:focus:ring-red-500={!isPhoneValidOrEmpty}
@@ -250,21 +271,27 @@
bind:this={phone_input} bind:this={phone_input}
type="tel" type="tel"
name="phone" name="phone"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !isPhoneValidOrEmpty} {#if !isPhoneValidOrEmpty}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{@html $_('the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number')} >
{@html $_(
"the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number"
)}
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="email" for="email"
class="block text-sm font-medium text-gray-700">{$_('e-mail-adress')}</label> class="block text-sm font-medium text-gray-700"
>{$_("e-mail-adress")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('e-mail-adress')} placeholder={$_("e-mail-adress")}
class:border-red-500={!isEmailValidOrEmpty} class:border-red-500={!isEmailValidOrEmpty}
class:focus:border-red-500={!isEmailValidOrEmpty} class:focus:border-red-500={!isEmailValidOrEmpty}
class:focus:ring-red-500={!isEmailValidOrEmpty} class:focus:ring-red-500={!isEmailValidOrEmpty}
@@ -272,11 +299,13 @@
bind:this={email_input} bind:this={email_input}
type="email" type="email"
name="email" name="email"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !isEmailValidOrEmpty} {#if !isEmailValidOrEmpty}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('valid-email-is-required')} >
{$_("valid-email-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
@@ -287,19 +316,22 @@
id="comments" id="comments"
name="comments" name="comments"
type="checkbox" type="checkbox"
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
/>
</div> </div>
<div class="ml-3 text-sm"> <div class="ml-3 text-sm">
<label <label for="comments" class="font-medium text-gray-700"
for="comments" >{$_("receipt-needed")}</label
class="font-medium text-gray-700">{$_('receipt-needed')}</label> >
</div> </div>
</div> </div>
{#if address_checked === true} {#if address_checked === true}
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="address1" for="address1"
class="block text-sm font-medium text-gray-700">{$_('address')}</label> class="block text-sm font-medium text-gray-700"
>{$_("address")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder="Address" placeholder="Address"
@@ -310,34 +342,41 @@
bind:this={address_input1} bind:this={address_input1}
type="text" type="text"
name="address1" name="address1"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !isAddress1Valid} {#if !isAddress1Valid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('address-is-required')} >
{$_("address-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="address2" for="address2"
class="block text-sm font-medium text-gray-700">{$_('apartment-suite-etc')}</label> class="block text-sm font-medium text-gray-700"
>{$_("apartment-suite-etc")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('apartment-suite-etc')} placeholder={$_("apartment-suite-etc")}
bind:value={address_input2_value} bind:value={address_input2_value}
bind:this={address_input2} bind:this={address_input2}
type="text" type="text"
name="address2" name="address2"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="zipcode" for="zipcode"
class="block text-sm font-medium text-gray-700">{$_('zip-postal-code')}</label> class="block text-sm font-medium text-gray-700"
>{$_("zip-postal-code")}</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder={$_('zip-postal-code')} placeholder={$_("zip-postal-code")}
class:border-red-500={!iszipcodevalid} class:border-red-500={!iszipcodevalid}
class:focus:border-red-500={!iszipcodevalid} class:focus:border-red-500={!iszipcodevalid}
class:focus:ring-red-500={!iszipcodevalid} class:focus:ring-red-500={!iszipcodevalid}
@@ -345,18 +384,22 @@
bind:this={address_zipcode} bind:this={address_zipcode}
type="text" type="text"
name="zipcode" name="zipcode"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !iszipcodevalid} {#if !iszipcodevalid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('valid-zipcode-postal-code-is-required')} >
{$_("valid-zipcode-postal-code-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
<div class="col-span-6"> <div class="col-span-6">
<label <label
for="city" for="city"
class="block text-sm font-medium text-gray-700">City</label> class="block text-sm font-medium text-gray-700"
>City</label
>
<input <input
autocomplete="off" autocomplete="off"
placeholder="City" placeholder="City"
@@ -367,11 +410,13 @@
bind:this={address_city} bind:this={address_city}
type="text" type="text"
name="city" name="city"
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-gray-500 rounded-md p-2" /> 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-gray-500 rounded-md p-2"
/>
{#if !iscityvalid} {#if !iscityvalid}
<span <span
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"> class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
{$_('valid-city-is-required')} >
{$_("valid-city-is-required")}
</span> </span>
{/if} {/if}
</div> </div>
@@ -386,16 +431,18 @@
class:opacity-50={!createbtnenabled} class:opacity-50={!createbtnenabled}
on:click={submit} on:click={submit}
type="button" 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 sm:ml-3 sm:w-auto sm:text-sm"> 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 sm:ml-3 sm:w-auto sm:text-sm"
{$_('create')} >
{$_("create")}
</button> </button>
<button <button
on:click={() => { on:click={() => {
modal_open = false; modal_open = false;
}} }}
type="button" type="button"
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
{$_('cancel')} >
{$_("cancel")}
</button> </button>
</div> </div>
</div> </div>

View File

@@ -13,60 +13,61 @@
dispatch("cancelDelete", { id: delete_donor.id }); dispatch("cancelDelete", { id: delete_donor.id });
} }
function deleteDonor() { function deleteDonor() {
DonorService.donorControllerRemove( dispatch("delete", { id: delete_donor.id });
delete_donor.id,
true
)
.then((resp) => {
Toastify({
text: $_('donor-deleted'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
location.replace("./");
})
.catch((err) => {});
} }
</script> </script>
{#if modal_open} {#if modal_open}
<div <div
class="fixed z-10 inset-0 overflow-y-auto" class="fixed z-10 inset-0 overflow-y-auto"
use:clickOutside use:clickOutside
on:click_outside={cancelDelete}> on:click_outside={cancelDelete}
>
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"> class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
>
<div class="fixed inset-0 transition-opacity" aria-hidden="true"> <div class="fixed inset-0 transition-opacity" aria-hidden="true">
<div <div
class="absolute inset-0 bg-gray-500 opacity-75" class="absolute inset-0 bg-gray-500 opacity-75"
data-id="modal_backdrop" /> data-id="modal_backdrop"
/>
</div> </div>
<span <span
class="hidden sm:inline-block sm:align-middle sm:h-screen" class="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true">&#8203;</span> aria-hidden="true">&#8203;</span
>
<div <div
class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full" class="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
aria-labelledby="modal-headline"> aria-labelledby="modal-headline"
>
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4"> <div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
<div class="sm:flex sm:items-start"> <div class="sm:flex sm:items-start">
<div <div
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"> class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
<svg class="h-6 w-6 text-blue-600" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M9.33 11.5h2.17A4.5 4.5 0 0116 16H9v1h8v-1a5.58 5.58 0 00-.89-3H19a5 5 0 014.52 2.85A13.15 13.15 0 0113 21c-2.76 0-5.1-.59-7-1.63v-9.3a6.97 6.97 0 013.33 1.43zM5 19a1 1 0 01-1 1H2a1 1 0 01-1-1v-9a1 1 0 011-1h2a1 1 0 011 1v9zM18 5a3 3 0 110 6 3 3 0 010-6zm-7-3a3 3 0 110 6 3 3 0 010-6z"/></svg> >
<svg
class="h-6 w-6 text-blue-600"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
><path fill="none" d="M0 0h24v24H0z" /><path
d="M9.33 11.5h2.17A4.5 4.5 0 0116 16H9v1h8v-1a5.58 5.58 0 00-.89-3H19a5 5 0 014.52 2.85A13.15 13.15 0 0113 21c-2.76 0-5.1-.59-7-1.63v-9.3a6.97 6.97 0 013.33 1.43zM5 19a1 1 0 01-1 1H2a1 1 0 01-1-1v-9a1 1 0 011-1h2a1 1 0 011 1v9zM18 5a3 3 0 110 6 3 3 0 010-6zm-7-3a3 3 0 110 6 3 3 0 010-6z"
/></svg
>
</div> </div>
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left"> <div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
{$_('attention')} {$_("attention")}
</h3> </h3>
<div class="mt-2 mb-6"> <div class="mt-2 mb-6">
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
{$_( {$_(
'do-you-want-to-delete-this-donor-with-all-related-donations' "do-you-want-to-delete-this-donor-with-all-related-donations"
)} )}
<br /> <br />
{$_('all-associated-donations-will-get-deleted-as-well')} {$_("all-associated-donations-will-get-deleted-as-well")}
</p> </p>
</div> </div>
</div> </div>
@@ -76,14 +77,16 @@
<button <button
on:click={deleteDonor} on:click={deleteDonor}
type="button" 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 sm:ml-3 sm:w-auto sm:text-sm"> 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 sm:ml-3 sm:w-auto sm:text-sm"
{$_('confirm-delete-donor-with-all-donations')} >
{$_("confirm-delete-donor-with-all-donations")}
</button> </button>
<button <button
on:click={cancelDelete} on:click={cancelDelete}
type="button" type="button"
class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"> class="mt-3 w-full inline-flex 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 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
{$_('cancel-keep-donor')} >
{$_("cancel-keep-donor")}
</button> </button>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,14 @@
<script>
import { _ } from "svelte-i18n";
export let address;
</script>
{#if !address || !address.address1}
{$_("no-address")}
{:else}
{address.address1}<br />
<!-- {address.address2 || ''}<br /> -->
{address.postalcode}
{address.city}
{address.country}
{/if}

View File

@@ -0,0 +1,29 @@
<script>
import { _ } from "svelte-i18n";
export let donations;
</script>
{#if !donations || donations.length == 0}
{$_('donor-has-no-associated-donations')}
{:else}
{#each donations as donation}
{#if donation.responseType === "DISTANCEDONATION"}
<a
href="../donations/{donation.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1"
>{donation.runner.firstname}
{donation.runner.middlename || ""}
{donation.runner.lastname}</a
>
{:else}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1"
>{$_("fixed-donation")}:
{(d.amount / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}</a
>
{/if}
{/each}
{/if}

View File

@@ -5,50 +5,73 @@
import DonorsOverview from "./DonorsOverview.svelte"; import DonorsOverview from "./DonorsOverview.svelte";
$: current_donors = []; $: current_donors = [];
export let modal_open = false; export let modal_open = false;
let addDonors;
</script> </script>
<section class="container p-5"> <section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight"> <span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('donors')} {$_("donors")}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")}
<button <button
on:click={() => { on:click={() => {
modal_open = true; modal_open = true;
}} }}
type="button" 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 sm:ml-3 sm:w-auto sm:text-sm"> 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 sm:ml-3 sm:w-auto sm:text-sm"
{$_('add-donor')} >
{$_("add-donor")}
</button> </button>
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')} {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")}
<button <button
on:click={() => { on:click={() => {
const data = (current_donors.filter(d=>d.receiptNeeded===true)).map(function (d) { const data = current_donors
d.address.address2=d.address.address2===""?"":" "+d.address.address2; .filter((d) => d.receiptNeeded === true)
const address=`${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`; .map(function (d) {
return [d.firstname,d.middlename,d.lastname,d.paidDonationAmount,address]; d.address.address2 =
}) d.address.address2 === "" ? "" : " " + d.address.address2;
let csv = `${$_('csv_import__firstname')};${$_('csv_import__middlename')};${$_('csv_import__lastname')};${$_('total_donation_amount_in_eur')};${$_('address')}\n`; const address = `${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`;
data.forEach(function(row) { return [
csv += row.join(';'); d.firstname,
d.middlename,
d.lastname,
d.paidDonationAmount,
address,
];
});
let csv = `${$_("csv_import__firstname")};${$_(
"csv_import__middlename"
)};${$_("csv_import__lastname")};${$_(
"total_donation_amount_in_eur"
)};${$_("address")}\n`;
data.forEach(function (row) {
csv += row.join(";");
csv += "\n"; csv += "\n";
}); });
let hiddenElement = document.createElement('a'); let hiddenElement = document.createElement("a");
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv); hiddenElement.href = "data:text/csv;charset=utf-8," + encodeURI(csv);
hiddenElement.target = '_blank'; hiddenElement.target = "_blank";
hiddenElement.download = `${$_('filename_sponsoringquittungsliste')}.csv`; hiddenElement.download = `${$_(
hiddenElement.click(); "filename_sponsoringquittungsliste"
hiddenElement.remove(); )}.csv`;
hiddenElement.click();
hiddenElement.remove();
}} }}
type="button" 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 sm:ml-3 sm:w-auto sm:text-sm"> 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 sm:ml-3 sm:w-auto sm:text-sm"
{$_('sponsoring-quittungs-liste_herunterladen')} >
{$_("sponsoring-quittungs-liste_herunterladen")}
</button> </button>
{/if} {/if}
</span> </span>
<DonorsOverview bind:current_donors /> <DonorsOverview bind:current_donors bind:addDonors />
</section> </section>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:CREATE')} {#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:CREATE")}
<AddDonorModal bind:current_donors bind:modal_open /> <AddDonorModal
on:created={(event) => {
addDonors(event.detail.donors);
}}
bind:modal_open
/>
{/if} {/if}

View File

@@ -5,214 +5,262 @@
import DonorsEmptyState from "./DonorsEmptyState.svelte"; import DonorsEmptyState from "./DonorsEmptyState.svelte";
import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte"; import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import TableBottom from "../shared/TableBottom.svelte";
import {
createSvelteTable,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
renderComponent,
} from "@tanstack/svelte-table";
import { writable } from "svelte/store";
import { onMount } from "svelte";
import InputElement from "../shared/InputElement.svelte";
import TableHeader from "../shared/TableHeader.svelte";
import TableActions from "../shared/TableActions.svelte";
import DonorAddress from "./DonorAddress.svelte";
import DonorDonations from "./DonorDonations.svelte";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: current_donations = []; $: current_donations = [];
$: selectedDonors =
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
$: selected =
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: dataLoaded = false;
let modal_open = false; let modal_open = false;
let delete_donor = {}; let delete_donor = {};
export let current_donors = []; export let current_donors = [];
const donors_promise = DonorService.donorControllerGetAll().then((val) => { export const addDonors = (donors) => {
current_donors = val; current_donors = current_donors.concat(...donors);
options.update((options) => ({
...options,
data: current_donors,
}));
};
//Section table
const columns = [
{
accessorKey: "id",
header: () => "id",
filterFn: `equalsString`,
},
{
accessorKey: "name",
header: () => $_("name"),
cell: (info) => {
const d = info.row.original;
if (d.middlename) {
return `${d.firstname} ${d.middlename} ${d.lastname}`;
} else {
return `${d.firstname} ${d.lastname}`;
}
},
filterFn: `includesString`,
},
{
accessorKey: "address",
header: () => $_("contact-information"),
cell: (info) => {
return renderComponent(DonorAddress, { address: info.getValue() });
},
filterFn: `includesString`,
},
{
accessorKey: "sponsorings",
header: () => $_("sponsorings"),
cell: (info) => {
const donations = current_donations.filter(
(d) => d?.donor?.id == info.row.original.id
);
return renderComponent(DonorDonations, { donations });
},
enableColumnFilter: false,
},
{
accessorKey: "donationAmount",
header: () => $_("total-donation-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€`;
},
enableColumnFilter: false,
},
{
accessorKey: "paidDonationAmount",
header: () => $_("total-paid-amount"),
cell: (info) => {
return `${(info.getValue() / 100)
.toFixed(2)
.toLocaleString("de-DE", { valute: "EUR" })}€`;
},
enableColumnFilter: false,
},
{
accessorKey: "actions",
header: () => $_("action"),
cell: (info) => {
return renderComponent(TableActions, {
detailsLink: `./${info.row.original.id}`,
deleteAction: () => {
active_deletes = current_donors.filter(
(r) => r.id == info.row.original.id
);
},
deleteEnabled:
store.state.jwtinfo.userdetails.permissions.includes(
"DONOR:DELETE"
),
});
},
enableColumnFilter: false,
enableSorting: false,
},
];
const options = writable({
data: [],
columns: columns,
initialState: {
pagination: {
pageSize: 50,
},
},
enableRowSelection: true,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
}); });
const donation_promise = DonationService.donationControllerGetAll().then( const table = createSvelteTable(options);
(val) => {
current_donations = val;
}
);
function should_display_based_on_id(id) { function should_display_based_on_id(id) {
if (searchvalue.toString().slice(-1) === "*") { if (searchvalue.toString().slice(-1) === "*") {
return id.toString().startsWith(searchvalue.replace("*", "")); return id.toString().startsWith(searchvalue.replace("*", ""));
} }
return id.toString() === searchvalue; return id.toString() === searchvalue;
} }
onMount(async () => {
let page = 0;
while (page >= 0) {
const donors = await DonorService.donorControllerGetAll(page, 500);
const donations = await DonationService.donationControllerGetAll(
page,
500
);
if (donors.length == 0 && donations.length == 0) {
page = -2;
}
current_donors = current_donors.concat(...donors);
current_donations = current_donations.concat(...donors);
options.update((options) => ({
...options,
data: current_donors,
}));
dataLoaded = true;
page++;
}
console.log("All donors loaded");
});
</script> </script>
<ConfirmDonorDeletion <ConfirmDonorDeletion
on:cancelDelete={(event) => { on:cancelDelete={(event) => {
modal_open = false; active_deletes = active_deletes.filter((a) => a.id !== event.detail.id);
active_deletes[event.detail.id] = false;
}} }}
bind:modal_open on:delete={async (event) => {
bind:delete_donor /> await DonorService.donorControllerRemove(event.detail.id, true);
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')} Toastify({
{#await donors_promise && donation_promise} text: $_("donor-deleted"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_donors = current_donors.filter((d) => d.id !== event.detail.id);
active_deletes = active_deletes.filter((a) => a.id !== event.detail.id);
options.update((options) => ({
...options,
data: current_donors,
}));
}}
modal_open={active_deletes.length > 0}
delete_donor={active_deletes[0]}
/>
{active_deletes.length}
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")}
{#if !dataLoaded}
<div <div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert"> role="alert"
<p class="font-bold">{$_('donors-are-being-loaded')}</p> >
<p class="text-sm">{$_('this-might-take-a-moment')}</p> <p class="font-bold">{$_("donors-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:then} {:else if current_donors.length === 0}
{#if current_donors.length === 0} <DonorsEmptyState />
<DonorsEmptyState /> {:else}
{:else} <input
<input type="search"
type="search" bind:value={searchvalue}
bind:value={searchvalue} placeholder={$_("datatable.search")}
placeholder={$_('datatable.search')} aria-label={$_("datatable.search")}
aria-label={$_('datatable.search')} class="mb-4"
class="mb-4" /> />
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
<table class="divide-y divide-gray-200 w-full"> >
<thead class="bg-gray-50"> <table class="w-full">
<tr> <thead>
<th {#each $table.getHeaderGroups() as headerGroup}
scope="col" <tr class="select-none">
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> <th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
{$_('name')} <InputElement
</th> type="checkbox"
<th checked={$table.getIsAllRowsSelected()}
scope="col" indeterminate={$table.getIsSomeRowsSelected()}
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> on:change={() => $table.toggleAllRowsSelected()}
{$_('contact-information')} />
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donations')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('total-donation-amount')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('total-paid-amount')}
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span>
</th> </th>
{#each headerGroup.headers as header}
<TableHeader {header} />
{/each}
</tr> </tr>
</thead> {/each}
<tbody class="divide-y divide-gray-200"> </thead>
{#each current_donors as donor} <tbody>
{#if donor.firstname {#each $table.getRowModel().rows as row}
.toLowerCase() <tr>
.includes( <td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
searchvalue.toLowerCase() <InputElement
) || donor.lastname type="checkbox"
.toLowerCase() checked={row.getIsSelected()}
.includes( on:change={() => row.toggleSelected()}
searchvalue.toLowerCase() />
) || should_display_based_on_id(donor.id)} </td>
<tr data-rowid="donor_{donor.id}"> {#each row.getVisibleCells() as cell}
<td class="px-6 py-4 whitespace-nowrap"> <td>
<div class="flex items-center"> <svelte:component
<div class="ml-4"> this={flexRender(
<div class="text-sm font-medium text-gray-900"> cell.column.columnDef.cell,
{donor.firstname} cell.getContext()
{donor.middlename || ''} )}
{donor.lastname} />
</div> </td>
</div> {/each}
</div> </tr>
</td> {/each}
<td class="px-6 py-4 whitespace-nowrap"> </tbody>
{#if donor.email} </table>
<div class="text-sm text-gray-500">{donor.email}</div>
{/if}
{#if donor.phone}
<div class="text-sm text-gray-500">{donor.phone}</div>
{/if}
{#if donor.address.address1 !== null}
{donor.address.address1}<br />
<!-- {donor.address.address2 || ''}<br /> -->
{donor.address.postalcode}
{donor.address.city}
{donor.address.country}
{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{#if current_donations.filter((d) => d.donor.id == donor.id).length > 0}
{#each current_donations.filter((o) => o.donor.id == donor.id) as d}
{#if d.responseType === 'DISTANCEDONATION'}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1">{d.runner.firstname}
{d.runner.middlename || ''}
{d.runner.lastname}</a>
{:else}
<a
href="../donations/{d.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1">{$_('fixed-donation')}:
{(d.amount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}</a>
{/if}
{/each}
{:else}{$_('donor-has-no-associated-donations')}{/if}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{(donor.donationAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</td>
<td class="px-6 py-4 whitespace-nowrap">
{(donor.paidDonationAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}
</td>
{#if active_deletes[donor.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {
active_deletes[donor.id] = false;
}}
tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button
on:click={() => {
DonorService.donorControllerRemove(donor.id, false)
.then((resp) => {
current_donors = current_donors.filter((obj) => obj.id !== donor.id);
Toastify({
text: 'Donor deleted',
duration: 500,
backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast();
})
.catch((err) => {
modal_open = true;
delete_donor = donor;
});
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
</td>
{:else}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<a
href="./{donor.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:DELETE')}
<button
on:click={() => {
active_deletes[donor.id] = true;
}}
tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button>
{/if}
</td>
{/if}
</tr>
{/if}
{/each}
</tbody>
</table>
</div>
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_('general_promise_error')}</b>
{error}
</span>
</div> </div>
{/await} <div class="h-2" />
<TableBottom {table} {selected} />
{/if}
{/if} {/if}

View File

@@ -50,7 +50,6 @@
})); }));
}; };
//Section table //Section table
const columns = [ const columns = [
{ {
@@ -157,16 +156,7 @@
}).showToast(); }).showToast();
} }
onMount(() => { onMount(async () => {
RunnerService.runnerControllerGetAll().then((val) => {
current_runners = val;
dataLoaded = true;
options.update((options) => ({
...options,
data: current_runners,
}));
});
RunnerTeamService.runnerTeamControllerGetAll().then((val) => { RunnerTeamService.runnerTeamControllerGetAll().then((val) => {
teams = val; teams = val;
}); });
@@ -175,6 +165,24 @@
orgs = val; orgs = val;
} }
); );
let page = 0;
while (page >= 0) {
const runners = await RunnerService.runnerControllerGetAll(page, 1000);
if (runners.length == 0) {
page = -2;
}
current_runners = current_runners.concat(...runners);
options.update((options) => ({
...options,
data: current_runners,
}));
dataLoaded = true;
page++;
}
console.log("All runners loaded");
}); });
</script> </script>

View File

@@ -30,6 +30,7 @@
$table?.getSelectedRowModel().rows.map((row) => row.index) || []; $table?.getSelectedRowModel().rows.map((row) => row.index) || [];
$: active_delete = undefined; $: active_delete = undefined;
$: dataLoaded = false;
export let current_scans = []; export let current_scans = [];
export const addScans = (scans) => { export const addScans = (scans) => {
current_scans = current_scans.concat(...scans); current_scans = current_scans.concat(...scans);
@@ -39,15 +40,6 @@
})); }));
}; };
const scans_promise = ScanService.scanControllerGetAll().then((val) => {
current_scans = val;
// handler.setRows(val);
current_scans = val;
options.update((options) => ({
...options,
data: current_scans,
}));
});
let allTracks = []; let allTracks = [];
TrackService.trackControllerGetAll().then((val) => { TrackService.trackControllerGetAll().then((val) => {
allTracks = val; allTracks = val;
@@ -99,7 +91,7 @@
accessorKey: "timestamp", accessorKey: "timestamp",
header: () => $_("timestamp"), header: () => $_("timestamp"),
cell: (info) => { cell: (info) => {
return (new Date(parseInt(info.getValue())*1000)).toLocaleString() return new Date(parseInt(info.getValue()) * 1000).toLocaleString();
}, },
enableColumnFilter: false, enableColumnFilter: false,
}, },
@@ -183,6 +175,26 @@
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
} }
onMount(async () => {
let page = 0;
while (page >= 0) {
const scans = await ScanService.scanControllerGetAll(page, 500);
if (scans.length == 0) {
page = -2;
}
current_scans = current_scans.concat(...scans);
options.update((options) => ({
...options,
data: current_scans,
}));
dataLoaded = true;
page++;
}
console.log("All scans loaded");
});
</script> </script>
<DeleteScanModal <DeleteScanModal
@@ -193,7 +205,7 @@
}} }}
/> />
{#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")} {#if store.state.jwtinfo.userdetails.permissions.includes("SCAN:GET")}
{#await scans_promise} {#if !dataLoaded}
<div <div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2" class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert" role="alert"
@@ -201,105 +213,96 @@
<p class="font-bold">{$_("scans-are-being-loaded")}</p> <p class="font-bold">{$_("scans-are-being-loaded")}</p>
<p class="text-sm">{$_("this-might-take-a-moment")}</p> <p class="text-sm">{$_("this-might-take-a-moment")}</p>
</div> </div>
{:then} {:else if current_scans.length === 0}
{#if current_scans.length === 0} <ScansEmptyState />
<ScansEmptyState /> {:else}
{:else} {#if selected.length > 0}
{#if selected.length > 0} <button
<button type="button"
type="button" class="w-full 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 sm:ml-3 sm:w-auto sm:text-sm inline-flex"
class="w-full 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 sm:ml-3 sm:w-auto sm:text-sm inline-flex" id="options-menu"
id="options-menu" on:click={async () => {
on:click={async () => { const prom = [];
const prom = []; for (const scan of selectedScans) {
for (const scan of selectedScans) { prom.push(ScanService.scanControllerRemove(scan.id, true));
prom.push(ScanService.scanControllerRemove(scan.id, true)); }
} await Promise.all(prom);
await Promise.all(prom); for (const scan of selectedScans) {
for (const scan of selectedScans) { current_scans = current_scans.filter((r) => r.id !== scan.id);
current_scans = current_scans.filter((r) => r.id !== scan.id); }
} options.update((options) => ({
options.update((options) => ({ ...options,
...options, data: current_scans,
data: current_scans, }));
})); $table.resetRowSelection();
$table.resetRowSelection(); Toastify({
Toastify({ text: $_("scan-deleted"),
text: $_("scan-deleted"), duration: 3500,
duration: 3500, backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", }).showToast();
}).showToast(); }}
}} >
{$_("delete-scans")}
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
> >
{$_("delete-scans")} <path
<svg stroke-linecap="round"
xmlns="http://www.w3.org/2000/svg" stroke-linejoin="round"
fill="none" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
viewBox="0 0 24 24" />
stroke-width="1.5" </svg>
stroke="currentColor" </button>
class="w-5 h-5" {/if}
> <div class="overflow-x-auto">
<path <table class="w-full">
stroke-linecap="round" <thead>
stroke-linejoin="round" {#each $table.getHeaderGroups() as headerGroup}
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0" <tr class="select-none">
/> <th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
</svg> <InputElement
</button> type="checkbox"
{/if} checked={$table.getIsAllRowsSelected()}
<div class="overflow-x-auto"> indeterminate={$table.getIsSomeRowsSelected()}
<table class="w-full"> on:change={() => $table.toggleAllRowsSelected()}
<thead> />
{#each $table.getHeaderGroups() as headerGroup} </th>
<tr class="select-none"> {#each headerGroup.headers as header}
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px"> <TableHeader {header} />
<InputElement {/each}
type="checkbox" </tr>
checked={$table.getIsAllRowsSelected()} {/each}
indeterminate={$table.getIsSomeRowsSelected()} </thead>
on:change={() => $table.toggleAllRowsSelected()} <tbody>
/> {#each $table.getRowModel().rows as row}
</th> <tr>
{#each headerGroup.headers as header} <td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
<TableHeader {header} /> <InputElement
{/each} type="checkbox"
</tr> checked={row.getIsSelected()}
{/each} on:change={() => row.toggleSelected()}
</thead> />
<tbody> </td>
{#each $table.getRowModel().rows as row} {#each row.getVisibleCells() as cell}
<tr> <td>
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px"> <svelte:component
<InputElement this={flexRender(
type="checkbox" cell.column.columnDef.cell,
checked={row.getIsSelected()} cell.getContext()
on:change={() => row.toggleSelected()} )}
/> />
</td> </td>
{#each row.getVisibleCells() as cell} {/each}
<td> </tr>
<svelte:component {/each}
this={flexRender( </tbody>
cell.column.columnDef.cell, </table>
cell.getContext()
)}
/>
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
</div>
<TableBottom {table} {selected} />
{/if}
{:catch error}
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
<span class="inline-block align-middle mr-8">
<b class="capitalize">{$_("general_promise_error")}</b>
{error}
</span>
</div> </div>
{/await} <TableBottom {table} {selected} />
{/if}
{/if} {/if}

View File

@@ -53,7 +53,7 @@
let codeconfig = { let codeconfig = {
bcid, bcid,
text: `${text}`, text: `${text}`,
scale: 3, scale: 4,
includetext: true, includetext: true,
textxalign: "center", textxalign: "center",
backgroundcolor: "ffffff", backgroundcolor: "ffffff",
@@ -178,13 +178,17 @@
{$_("api-endpoint")} {$_("api-endpoint")}
</h3> </h3>
<img <img
class="w-full md:w-auto mb-2 mx-auto" class:w-[50%]={is_qrcode}
class:w-full={!is_qrcode}
class="md:w-auto mb-2 mx-auto"
alt="Registrierungscode" alt="Registrierungscode"
src={textToBase64Barcode(config.baseurl, is_qrcode)} src={textToBase64Barcode(config.baseurl, is_qrcode)}
/> />
<h3 class="leading-6 font-medium text-gray-900">{$_("token")}</h3> <h3 class="leading-6 font-medium text-gray-900">{$_("token")}</h3>
<img <img
class="w-full md:w-auto mb-2 mx-auto" class:w-[50%]={is_qrcode}
class:w-full={!is_qrcode}
class="md:w-auto mb-2 mx-auto"
alt="Registrierungscode" alt="Registrierungscode"
src={barcode} src={barcode}
/> />

View File

@@ -1,493 +1,500 @@
{ {
"404message": "Die gesuchte Seite wurde leider nicht gefunden.", "404message": "Die gesuchte Seite wurde leider nicht gefunden.",
"404title": "Fehler 404", "404title": "Fehler 404",
"about": "Über", "about": "Über",
"action": "Aktionen", "action": "Aktionen",
"active": "Aktiv", "active": "Aktiv",
"add-card": "Karte erstellen", "add-card": "Karte erstellen",
"add-donation": "Sponsoring erstellen", "add-donation": "Sponsoring erstellen",
"add-donor": "Sponsor:in erstellen", "add-donor": "Sponsor:in erstellen",
"add-or-update-a-payment": "Zahlung hinzufügen oder bearbeiten", "add-or-update-a-payment": "Zahlung hinzufügen oder bearbeiten",
"add-scan": "Scan erstellen", "add-scan": "Scan erstellen",
"add-the-first-scanstation": "Erstelle deine erste Scannerstation.", "add-the-first-scanstation": "Erstelle deine erste Scannerstation.",
"add-the-first-statsclient": "Erstelle deinen ersten Statsclient.", "add-the-first-statsclient": "Erstelle deinen ersten Statsclient.",
"add-user-group": "Neue Gruppe erstellen", "add-user-group": "Neue Gruppe erstellen",
"add-your-first-card": "Erstelle deine erste Läuferkarte", "add-your-first-card": "Erstelle deine erste Läuferkarte",
"add-your-first-contact": "Erstelle den ersten Kontakt", "add-your-first-contact": "Erstelle den ersten Kontakt",
"add-your-first-donor": "Erstelle die erste Sponsor:in", "add-your-first-donor": "Erstelle die erste Sponsor:in",
"add-your-first-group": "Erstelle die erste Gruppe", "add-your-first-group": "Erstelle die erste Gruppe",
"add-your-first-organization": "Erstelle die erste Organisation", "add-your-first-organization": "Erstelle die erste Organisation",
"add-your-first-runner": "Erstelle die erste Läufer:in", "add-your-first-runner": "Erstelle die erste Läufer:in",
"add-your-first-team": "Erstelle das erste Team", "add-your-first-team": "Erstelle das erste Team",
"add-your-first-track": "Erstelle den ersten Track (Laufstrecke).", "add-your-first-track": "Erstelle den ersten Track (Laufstrecke).",
"add-your-first-user": "Erstelle die erste Benutzer:in", "add-your-first-user": "Erstelle die erste Benutzer:in",
"add-your-fist-donation": "Erstelle dein erstes Sponsoring", "add-your-fist-donation": "Erstelle dein erstes Sponsoring",
"add-your-fist-scan": "Füge deinen ersten Scan hinzu", "add-your-fist-scan": "Füge deinen ersten Scan hinzu",
"adding-card": "Karte wird erstellt", "adding-card": "Karte wird erstellt",
"adding-donation": "Sponsoring wird erstellt...", "adding-donation": "Sponsoring wird erstellt...",
"adding-scan": "Scan wird hinzugefügt", "adding-scan": "Scan wird hinzugefügt",
"address": "Adresse", "address": "Adresse",
"address-is-required": "Du musst eine Adresse angeben", "address-is-required": "Du musst eine Adresse angeben",
"after-deletion-we-cant-restore-your-old-profile": "Nach der Löschung können auch die Admins dein Profil nicht wiederherstellen!", "after-deletion-we-cant-restore-your-old-profile": "Nach der Löschung können auch die Admins dein Profil nicht wiederherstellen!",
"after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that": "Nach der Änderung wirst du abgemeldet - bitte melde dich dann mit deinem neuen Passwort an.", "after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that": "Nach der Änderung wirst du abgemeldet - bitte melde dich dann mit deinem neuen Passwort an.",
"all": "Alle", "all": "Alle",
"all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht", "all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht",
"all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!", "all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!",
"all-associated-scans-will-get-deleted-as-well": "Alle Scans dieser Station werden ebenfalls gelöscht", "all-associated-scans-will-get-deleted-as-well": "Alle Scans dieser Station werden ebenfalls gelöscht",
"all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!", "all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!",
"already-paid": "Bereits bezahlt", "already-paid": "Bereits bezahlt",
"amount": "Anzahl", "amount": "Anzahl",
"amount-per-kilometer": "Betrag pro Kilometer", "amount-per-kilometer": "Betrag pro Kilometer",
"apartment-suite-etc": "Apartment, Wohnung, etc.", "apartment-suite-etc": "Apartment, Wohnung, etc.",
"application_name": "Lauf für Kaya! - Admin", "api-endpoint": "API-Endpunkt",
"applying-changes": "Änderungen anwenden", "application_name": "Lauf für Kaya! - Admin",
"attention": "Achtung!", "applying-changes": "Änderungen anwenden",
"author": "Autor:in", "attention": "Achtung!",
"bitte-bestaetige-diese-laeufer-fuer-den-import": "Bitte die Läufer:innen für den Import bestätigen.", "author": "Autor:in",
"by": "von", "average-distance": "Durchschnittliche Strecke/Läufer:in",
"cancel": "Abbrechen", "average-donation": "Durchschnittliches Sponsoring",
"cancel-delete": "Löschen abbrechen", "bitte-bestaetige-diese-laeufer-fuer-den-import": "Bitte die Läufer:innen für den Import bestätigen.",
"cancel-keep-donor": "Abbrechen, Sponsor:in behalten", "by": "von",
"cancel-keep-my-profile": "Abbrechen, mein Profil behalten", "cancel": "Abbrechen",
"cancel-keep-organization": "Abbrechen und Organisation bearbeiten", "cancel-delete": "Löschen abbrechen",
"cancel-keep-station": "Abbrechen und Station behalten", "cancel-keep-donor": "Abbrechen, Sponsor:in behalten",
"cancel-keep-statsclient": "Abbrechen und Statsclient behalten", "cancel-keep-my-profile": "Abbrechen, mein Profil behalten",
"cancel-keep-team": "Abbrechen, Team behalten", "cancel-keep-organization": "Abbrechen und Organisation bearbeiten",
"cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.", "cancel-keep-station": "Abbrechen und Station behalten",
"card": "Läuferkarte", "cancel-keep-statsclient": "Abbrechen und Statsclient behalten",
"card-added": "Karte wurde hinzugefügt", "cancel-keep-team": "Abbrechen, Team behalten",
"card-deleted": "Karte gelöscht", "cannot-reset-your-password-directly": "Schade. \nWir können das Passwort leider nicht direkt zurücksetzen.\nBitte sende uns eine Mail in der du deine Identität bestätigst.",
"card-updated": "Karte aktualisiert", "card": "Läuferkarte",
"cards": "Läuferkarten", "card-added": "Karte wurde hinzugefügt",
"cards-deleted": "Karten gelöscht", "card-deleted": "Karte gelöscht",
"certificates": "Urkunden", "card-updated": "Karte aktualisiert",
"change-your-password-here": "Hier kannst du dein Passwort ändern", "cards": "Läuferkarten",
"changing-your-password": "Passwort wird geändert", "cards-deleted": "Karten gelöscht",
"city": "Stadt", "certificates": "Urkunden",
"click-to-copy-the-link-into-your-clipboard": "Klicke auf den Link, um ihn in deine Zwischenablage zu kopieren", "change-your-password-here": "Hier kannst du dein Passwort ändern",
"click-to-copy-token-to-clipboard": "Klicke auf den Token, um ihn in deine Zwischenablage zu kopieren", "changing-your-password": "Passwort wird geändert",
"close": "Schließen", "city": "Stadt",
"code": "Code", "click-to-copy-the-link-into-your-clipboard": "Klicke auf den Link, um ihn in deine Zwischenablage zu kopieren",
"configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit", "click-to-copy-token-to-clipboard": "Klicke auf den Token, um ihn in deine Zwischenablage zu kopieren",
"confirm": "Bestätigen", "close": "Schließen",
"confirm-delete": "Löschung Bestätigen", "code": "Code",
"confirm-delete-donor-with-all-donations": "Bestätigen, Sponsor:in mit allen Sponsorings löschen", "config-codes": "Konfigurations-Codes",
"confirm-delete-my-user-profile": "Bestätigung, mein Benutzerprofil löschen", "configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit",
"confirm-delete-organization-and-associated-teams-runners": "Bestätugung, lösche die Organisation und alle zugehörigen Teams und Läufer:innen.", "confirm": "Bestätigen",
"confirm-delete-station-with-all-scans": "Löschen der Scannerstation mit allen Scans bestätigen", "confirm-delete": "Löschung Bestätigen",
"confirm-delete-statsclient": "Bestätigung, Statsclient löschen", "confirm-delete-donor-with-all-donations": "Bestätigen, Sponsor:in mit allen Sponsorings löschen",
"confirm-delete-team-and-associated-runners": "Bestätigung, lösche das Team mitsamt seinen Läufer:innen.", "confirm-delete-my-user-profile": "Bestätigung, mein Benutzerprofil löschen",
"confirm-deletion": "Löschung Bestätigen", "confirm-delete-organization-and-associated-teams-runners": "Bestätugung, lösche die Organisation und alle zugehörigen Teams und Läufer:innen.",
"confirm-the-new-password": "Neues Passwort bestätigen", "confirm-delete-station-with-all-scans": "Löschen der Scannerstation mit allen Scans bestätigen",
"contact": "Kontakt", "confirm-delete-statsclient": "Bestätigung, Statsclient löschen",
"contact-added": "Kontakt wurde hinzugefügt", "confirm-delete-team-and-associated-runners": "Bestätigung, lösche das Team mitsamt seinen Läufer:innen.",
"contact-deleted": "Kontakt gelöscht", "confirm-deletion": "Löschung Bestätigen",
"contact-information": "Kontaktinformation", "confirm-the-new-password": "Neues Passwort bestätigen",
"contact-is-being-added": "Kontakt wird erstellt...", "contact": "Kontakt",
"contact-is-being-updated": "Kontakt wird aktualisiert ...", "contact-added": "Kontakt wurde hinzugefügt",
"contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe", "contact-deleted": "Kontakt gelöscht",
"contacts": "Kontakte", "contact-information": "Kontaktinformation",
"contacts-are-being-loaded": "Kontakte werden geladen ...", "contact-is-being-added": "Kontakt wird erstellt...",
"copied-link-to-clipboard": "Link wurde in die Zwischenablage kopiert", "contact-is-being-updated": "Kontakt wird aktualisiert ...",
"copied-token-to-clipboard": "Token wurde in die Zwischenablage kopiert", "contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe",
"count_organizations": "Organisationen (Anzahl)", "contacts": "Kontakte",
"count_teams": "Teams (Anzahl)", "contacts-are-being-loaded": "Kontakte werden geladen ...",
"create": "Erstellen", "copied-link-to-clipboard": "Link wurde in die Zwischenablage kopiert",
"create-a-new": "Erstelle eine neue", "copied-token-to-clipboard": "Token wurde in die Zwischenablage kopiert",
"create-a-new-card": "Neue Läuferkarte erstellen", "count_organizations": "Organisationen (Anzahl)",
"create-a-new-contact": "Kontakt erstellen", "count_teams": "Teams (Anzahl)",
"create-a-new-distance-donation": "Erstelle ein neues Sponsoring", "create": "Erstellen",
"create-a-new-donor": "Neue Sponsor:in erstellen", "create-a-new": "Erstelle eine neue",
"create-a-new-fixed-donation": "Erstelle eine neue Festbetragsspende", "create-a-new-card": "Neue Läuferkarte erstellen",
"create-a-new-organization": "Neue Organisation anlegen", "create-a-new-contact": "Kontakt erstellen",
"create-a-new-runner": "Neue Läufer:in erstellen", "create-a-new-distance-donation": "Erstelle ein neues Sponsoring",
"create-a-new-scan-fixed-only": "Neuen Scan erstellen (nur mit Festdistanz)", "create-a-new-donor": "Neue Sponsor:in erstellen",
"create-a-new-scanstation": "Neue Station erstellen", "create-a-new-fixed-donation": "Erstelle eine neue Festbetragsspende",
"create-a-new-statsclient": "Neuen Statsclient erstellen", "create-a-new-organization": "Neue Organisation anlegen",
"create-a-new-team": "Erstelle ein neues Team", "create-a-new-runner": "Neue Läufer:in erstellen",
"create-a-new-track": "Neuen Track erstellen", "create-a-new-scan-fixed-only": "Neuen Scan erstellen (nur mit Festdistanz)",
"create-a-new-user": "Neue Benutzer:in anlegen", "create-a-new-scanstation": "Neue Station erstellen",
"create-a-new-user-group": "Erstelle eine neue Gruppe", "create-a-new-statsclient": "Neuen Statsclient erstellen",
"create-and-generate-pdf": "Erstellen und PDF herunterladen", "create-a-new-team": "Erstelle ein neues Team",
"create-bulk-blanco-cards": "Blankokarten erstellen", "create-a-new-track": "Neuen Track erstellen",
"create-bulk-cards": "Blankokarten erstellen", "create-a-new-user": "Neue Benutzer:in anlegen",
"create-organization": "Organisation erstellen", "create-a-new-user-group": "Erstelle eine neue Gruppe",
"create-team": "Team erstellen", "create-and-generate-pdf": "Erstellen und PDF herunterladen",
"create-track": "Track erstellen", "create-bulk-blanco-cards": "Blankokarten erstellen",
"create-user": "Benutzer anlegen", "create-bulk-cards": "Blankokarten erstellen",
"create-without-pdf": "Ohne PDF erstellen", "create-organization": "Organisation erstellen",
"created-blanco-cards": "Blankokarten wurden erstellt", "create-team": "Team erstellen",
"creating-blanco-cards": "Erstelle Blankokarten", "create-track": "Track erstellen",
"credits": "Credits", "create-user": "Benutzer anlegen",
"csv_import__class": "Klasse", "create-without-pdf": "Ohne PDF erstellen",
"csv_import__firstname": "Vorname", "created-blanco-cards": "Blankokarten wurden erstellt",
"csv_import__lastname": "Nachname", "creating-blanco-cards": "Erstelle Blankokarten",
"csv_import__middlename": "Mittelname", "credits": "Credits",
"csv_import__team": "Team", "csv_import__class": "Klasse",
"danger-zone": "Gefahrenzone", "csv_import__firstname": "Vorname",
"dashboard-greeting": "Hallo", "csv_import__lastname": "Nachname",
"dashboard-title": "Dashboard", "csv_import__middlename": "Mittelname",
"datatable": { "csv_import__team": "Team",
"search": "🔍 Suche ...", "danger-zone": "Gefahrenzone",
"an_error_happened_while_fetching_the_data": "Beim Abrufen der Daten ist ein Fehler aufgetreten", "dashboard-greeting": "Hallo",
"loading": "Wird geladen...", "dashboard-title": "Dashboard",
"next": "Nächste", "datatable": {
"of": "von", "search": "🔍 Suche ...",
"previous": "Vorherige", "an_error_happened_while_fetching_the_data": "Beim Abrufen der Daten ist ein Fehler aufgetreten",
"to": "bis", "loading": "Wird geladen...",
"showing": "Zeige", "next": "Nächste",
"no_matching_records_found": "Keine passenden Einträge gefunden", "of": "von",
"page": "Seite", "previous": "Vorherige",
"records": "Einträge", "to": "bis",
"sort_column_ascending": "Spalte aufsteigend sortieren", "showing": "Zeige",
"sort_column_descending": "Spalte absteigend sortieren" "no_matching_records_found": "Keine passenden Einträge gefunden",
}, "page": "Seite",
"delete": "Löschen", "records": "Einträge",
"delete-cards": "Karten löschen", "sort_column_ascending": "Spalte aufsteigend sortieren",
"delete-contact": "Kontakt löschen", "sort_column_descending": "Spalte absteigend sortieren"
"delete-donation": "Sponsoring löschen", },
"delete-donor": "Sponsor:in löschen", "delete": "Löschen",
"delete-group": "Gruppe löschen", "delete-cards": "Karten löschen",
"delete-organization": "Organisation löschen", "delete-contact": "Kontakt löschen",
"delete-profile": "Profil löschen", "delete-donation": "Sponsoring löschen",
"delete-runner": "Läufer:in löschen", "delete-donor": "Sponsor:in löschen",
"delete-scan": "Scan löschen", "delete-group": "Gruppe löschen",
"delete-scans": "Scans löschen", "delete-organization": "Organisation löschen",
"delete-station": "Station löschen", "delete-profile": "Profil löschen",
"delete-statsclient": "Statsclient löschen", "delete-runner": "Läufer:in löschen",
"delete-team": "Team Löschen", "delete-scan": "Scan löschen",
"delete-user": "Benutzer:in löschen", "delete-scans": "Scans löschen",
"deleted-scan": "Scan wurde gelöscht", "delete-station": "Station löschen",
"dependency_name": "Name", "delete-statsclient": "Statsclient löschen",
"description": "Beschreibung", "delete-team": "Team Löschen",
"description-optional": "Beschreibung (optional)", "delete-user": "Benutzer:in löschen",
"deselect-all": "Alle abwählen", "deleted-scan": "Scan wurde gelöscht",
"details": "Details", "dependency_name": "Name",
"disabled": "deaktiviert", "description": "Beschreibung",
"distance": "Distanz", "description-optional": "Beschreibung (optional)",
"distance-donation": "Sponsoring", "deselect-all": "Alle abwählen",
"distance-in-km": "Distanz (in KM)", "details": "Details",
"distance-track": "Distanz (+Track)", "disabled": "deaktiviert",
"do-you-really-want-to-delete-your-profile": "Möchtest du dein Profil wirklich löschen?", "distance": "Distanz",
"do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?", "distance-donation": "Sponsoring",
"do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?", "distance-in-km": "Distanz (in KM)",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?", "distance-track": "Distanz (+Track)",
"documentation": "Dokumentation", "do-you-really-want-to-delete-your-profile": "Möchtest du dein Profil wirklich löschen?",
"donation-amount": "Sponsoringbetrag", "do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?",
"donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.", "do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?",
"donation-deleted": "Sponsoring gelöscht", "do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?",
"donation-updated": "Sponsoring wurde aktualisiert", "documentation": "Dokumentation",
"donation_added": "Sponsoring hinzugefügt", "donation-amount": "Sponsoringbetrag",
"donations": "Sponsorings", "donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.",
"donor": "Sponsor:in", "donation-deleted": "Sponsoring gelöscht",
"donor-added": "Sponsor:in hinzugefügt", "donation-updated": "Sponsoring wurde aktualisiert",
"donor-deleted": "Sponsor:in gelöscht", "donation_added": "Sponsoring hinzugefügt",
"donor-has-no-associated-donations": "Zur Sponsor:in gibt es noch keine Sponsorings", "donations": "Sponsorings",
"donor-is-being-added": "Sponsor:in wird hinzugefügt...", "donations-are-being-loaded": "Sponsorings werden geladen...",
"donor-is-being-updated": "Sponsor:in wird aktualisiert", "donor": "Sponsor:in",
"donors": "Sponsor:innen", "donor-added": "Sponsor:in hinzugefügt",
"donors-are-being-loaded": "Sponsor:innen werden geladen", "donor-deleted": "Sponsor:in gelöscht",
"dont-have-your-email-connected": "Deine E-Mail ist nicht verknüpft?", "donor-has-no-associated-donations": "Zur Sponsor:in gibt es noch keine Sponsorings",
"dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌", "donor-is-being-added": "Sponsor:in wird hinzugefügt...",
"e-mail-adress": "E-Mail-Adresse", "donor-is-being-updated": "Sponsor:in wird aktualisiert",
"edit": "Bearbeiten", "donors": "Sponsor:innen",
"edit-a-card": "Läuferkarte bearbeiten", "donors-are-being-loaded": "Sponsor:innen werden geladen",
"edit-permissions": "Berechtigungen bearbeiten", "dont-have-your-email-connected": "Deine E-Mail ist nicht verknüpft?",
"email_address_or_username": "E-Mail-Adresse/ Benutzername", "dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌",
"enabled": "aktiviert", "e-mail-adress": "E-Mail-Adresse",
"enabled_large": "Aktiviert", "edit": "Bearbeiten",
"english": "Englisch", "edit-a-card": "Läuferkarte bearbeiten",
"enter-payment": "Zahlung eingeben", "edit-permissions": "Berechtigungen bearbeiten",
"error-during-import": "Fehler beim Importieren", "email_address_or_username": "E-Mail-Adresse/ Benutzername",
"error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage", "enabled": "aktiviert",
"error_on_login": "😢Fehler beim Login", "enabled_large": "Aktiviert",
"erteilte": "Direkt erteilte", "english": "Englisch",
"everything-concerning-your-profile": "Alles zu deinem Profil", "enter-payment": "Zahlung eingeben",
"everything-is-more-fun-together": "Im Team macht's mehr Spaß 🏃‍♂️🏃‍♀️🏃‍♂️", "error-during-import": "Fehler beim Importieren",
"faq": "FAQ", "error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage",
"filename_sponsoringquittungsliste": "SponsoringQuittungsListe", "error_on_login": "😢Fehler beim Login",
"filter-by-organization-team": "Filtern nach Organisation / Team", "erteilte": "Direkt erteilte",
"first-name": "Vorname", "everything-concerning-your-profile": "Alles zu deinem Profil",
"first-name-is-required": "Vorname muss angegeben werden", "everything-is-more-fun-together": "Im Team macht's mehr Spaß 🏃‍♂️🏃‍♀️🏃‍♂️",
"first-scan-of-the-day": "Erster Scan des Tages", "faq": "FAQ",
"fixed-donation": "Festbetragsspende", "filename_sponsoringquittungsliste": "SponsoringQuittungsListe",
"forgot_password": "Passwort vergessen?", "filter-by-organization-team": "Filtern nach Organisation / Team",
"geerbte": "geerbte", "first-name": "Vorname",
"general-stats": "Allgemeine Statistiken", "first-name-is-required": "Vorname muss angegeben werden",
"general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten", "first-scan-of-the-day": "Erster Scan des Tages",
"generate-runner-certificate": "Urkunde generieren", "fixed-donation": "Festbetragsspende",
"generate-runner-certificates": "Urkunden generieren", "forgot_password": "Passwort vergessen?",
"generate-runnercards": "Läuferkarten generieren", "geerbte": "geerbte",
"generate-sponsoring-contract": "Sponsoringvertrag generieren", "general-stats": "Allgemeine Statistiken",
"generate-sponsoring-contracts": "Sponsoringverträge generieren", "general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten",
"generating-pdf": "PDF wird generiert...", "generate-runner-certificate": "Urkunde generieren",
"generating-pdfs": "PDFs werden generiert...", "generate-runner-certificates": "Urkunden generieren",
"generic-ui-logic-error": "Etwas ist in der Benutzeroberfläche schiefgelaufen.", "generate-runnercards": "Läuferkarten generieren",
"german": "Deutsch", "generate-sponsoring-contract": "Sponsoringvertrag generieren",
"go-to-login": "Zum Login", "generate-sponsoring-contracts": "Sponsoringverträge generieren",
"goback": "Zur Startseite", "generating-pdf": "PDF wird generiert...",
"granted": "Gewährt", "generating-pdfs": "PDFs werden generiert...",
"group": "Gruppe", "generic-ui-logic-error": "Etwas ist in der Benutzeroberfläche schiefgelaufen.",
"group-added": "Gruppe hinzugefügt", "german": "Deutsch",
"group-is-being-added": "Gruppe wird erstellt", "go-to-login": "Zum Login",
"group-name-is-required": "Der Gruppenname muss angegeben werden.", "goback": "Zur Startseite",
"group-updated": "Gruppe aktualisiert", "granted": "Gewährt",
"groups": "Gruppen", "group": "Gruppe",
"groups-are-being-loaded": "Gruppen werden geladen", "group-added": "Gruppe hinzugefügt",
"home": "Start", "group-is-being-added": "Gruppe wird erstellt",
"icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:", "group-name-is-required": "Der Gruppenname muss angegeben werden.",
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "Wenn du mehrere Blankokarten erstellen willst, nutze doch den \"Blankokarten erstellen\" Knopf.", "group-updated": "Gruppe aktualisiert",
"import-finished": "Import abgeschlossen", "groups": "Gruppen",
"import-runners": "Läufer:innen importieren", "groups-are-being-loaded": "Gruppen werden geladen",
"import__target-organization": "Ziel Organisation", "home": "Start",
"imprint": "Impressum ", "icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:",
"imprint-loading": "Impressum lädt...", "if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "Wenn du mehrere Blankokarten erstellen willst, nutze doch den \"Blankokarten erstellen\" Knopf.",
"inactive": "Inaktiv", "import-finished": "Import abgeschlossen",
"installed-version": "Installierte Version", "import-runners": "Läufer:innen importieren",
"internal-error": "Interner Fehler", "import__target-organization": "Ziel Organisation",
"invalid": "Ungültig", "imprint": "Impressum ",
"invalid-mail-reset": "Das ist keine gültige E-Mail", "imprint-loading": "Impressum lädt...",
"just-enter-how-many-you-want-and-the-system-will-create-them": "Gebe einfach ein, wie viele Blankokarten das System erstellen soll.", "inactive": "Inaktiv",
"key": "Schlüssel", "installed-version": "Installierte Version",
"laeufer-hinzufuegen": "Läufer:in hinzufügen", "internal-error": "Interner Fehler",
"laeufer-importieren": "Läufer:innen importieren", "invalid": "Ungültig",
"laptime": "Rundenzeit", "invalid-mail-reset": "Das ist keine gültige E-Mail",
"last-name": "Nachname", "just-enter-how-many-you-want-and-the-system-will-create-them": "Gebe einfach ein, wie viele Blankokarten das System erstellen soll.",
"last-name-is-required": "Nachname muss angegeben werden", "key": "Schlüssel",
"lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", "laeufer-hinzufuegen": "Läufer:in hinzufügen",
"license": "Lizenz", "laeufer-importieren": "Läufer:innen importieren",
"licenses-are-being-loaded": "Lizenzen werden geladen...", "laptime": "Rundenzeit",
"loading-cards": "Läuferkarten werden geladen", "last-name": "Nachname",
"loading-contact-details": "Kontaktdaten werden geladen ...", "last-name-is-required": "Nachname muss angegeben werden",
"loading-donation-details": "Lade Sponsoringdetails", "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.",
"loading-donor-details": "Lade Details", "license": "Lizenz",
"loading-group-detail": "Lade Gruppendetails...", "licenses-are-being-loaded": "Lizenzen werden geladen...",
"loading-profile-data": "Lade Profildaten", "loading-cards": "Läuferkarten werden geladen",
"loading-runners": "Läufer:innen werden geladen...", "loading-contact-details": "Kontaktdaten werden geladen ...",
"loading-station-details": "Lade Scanstation-Details ...", "loading-donation-details": "Lade Sponsoringdetails",
"log_in": "Anmelden", "loading-donor-details": "Lade Details",
"log_in_to_your_account": "Bitte melde dich an", "loading-group-detail": "Lade Gruppendetails...",
"login_is_checked": "Login wird überprüft", "loading-profile-data": "Lade Profildaten",
"logout": "Abmelden", "loading-runners": "Läufer:innen werden geladen...",
"mail-validation-in-progress": "E-Mail Verifizierung läuft... ", "loading-station-details": "Lade Scanstation-Details ...",
"manage-admin-users": "Nutzer verwalten", "log_in": "Anmelden",
"middle-name": "Mittelname", "log_in_to_your_account": "Bitte melde dich an",
"minimum-lap-time-in-s": "Minimale Rundenzeit (in Sekunden)", "login_is_checked": "Login wird überprüft",
"minimum-lap-time-must-be-a-positive-number-or-0": "Die minimale Rundenzeit muss eine positive Zahl oder 0 sein", "logout": "Abmelden",
"must-be-at-least-10-characters-long": "Passwort muss mindestens 10 Zeichen lang sein!", "mail-validation-in-progress": "E-Mail Verifizierung läuft... ",
"must-contain-a-lowercase-letter": "Passwort muss einen Großbuchstaben enthalten!", "manage-admin-users": "Nutzer verwalten",
"must-contain-a-number": "Passwort muss eine Zahl enthalten!", "middle-name": "Mittelname",
"must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!", "minimum-lap-time-in-s": "Minimale Rundenzeit (in Sekunden)",
"name": "Name", "minimum-lap-time-must-be-a-positive-number-or-0": "Die minimale Rundenzeit muss eine positive Zahl oder 0 sein",
"name-is-required": "Der Gruppenname muss angegeben werden", "must-be-at-least-10-characters-long": "Passwort muss mindestens 10 Zeichen lang sein!",
"new-password": "Neues Passwort", "must-contain-a-lowercase-letter": "Passwort muss einen Großbuchstaben enthalten!",
"no-contact-found": "Keine Kontakte gefunden", "must-contain-a-number": "Passwort muss eine Zahl enthalten!",
"no-contact-selected": "Kein Kontakt ausgewählt", "must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!",
"no-contact-specified": "Kein Kontakt angegeben", "name": "Name",
"no-donors-found": "Keine Spender:innen gefunden", "name-is-required": "Der Gruppenname muss angegeben werden",
"no-license-text-could-be-found": "Kein Lizenz-Text gefunden 😢", "new-password": "Neues Passwort",
"no-organization-or-team-found": "Keine Organisationen oder Teams gefunden", "no-address": "Keine Adresse hinterlegt",
"no-organization-specified": "Keine Organisation angegeben", "no-contact-found": "Keine Kontakte gefunden",
"no-organizations-found": "Keine Organisationen gefunden", "no-contact-selected": "Kein Kontakt ausgewählt",
"no-runners-found": "Keine Läufer:innen gefunden", "no-contact-specified": "Kein Kontakt angegeben",
"no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.", "no-donors-found": "Keine Spender:innen gefunden",
"non-blanko": "Keine/Blankokarte", "no-license-text-could-be-found": "Kein Lizenz-Text gefunden 😢",
"open": "OFFEN", "no-organization-or-team-found": "Keine Organisationen oder Teams gefunden",
"organization": "Organisation", "no-organization-specified": "Keine Organisation angegeben",
"organization-added": "Organisation hinzugefügt", "no-organizations-found": "Keine Organisationen gefunden",
"organization-deleted": "Organisation gelöscht", "no-runners-found": "Keine Läufer:innen gefunden",
"organization-detail-is-being-loaded": "Organisationsdetails werden geladen ...", "no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.",
"organization-is-being-added": "Organisation wird hinzugefügt ...", "non-blanko": "Keine/Blankokarte",
"organization-name-is-required": "Der Name muss angegeben werden", "open": "OFFEN",
"organizations": "Organisationen", "organization": "Organisation",
"organizations-are-being-loaded": "Organisationen werden geladen ...", "organization-added": "Organisation hinzugefügt",
"orgs": "Organisationen", "organization-deleted": "Organisation gelöscht",
"oss_credit_description": "Wir verwenden eine Menge Open Source-Software bei diesen Projekten und möchten uns bei den folgenden Projekten und Mitwirkenden bedanken, die dazu beitragen, Open Source großartig zu machen!", "organization-detail-is-being-loaded": "Organisationsdetails werden geladen ...",
"paid": "BEZAHLT", "organization-is-being-added": "Organisation wird hinzugefügt ...",
"paid-amount": "Gezahlter Betrag", "organization-name-is-required": "Der Name muss angegeben werden",
"password": "Passwort", "organizations": "Organisationen",
"password-changed": "Passwort wurde aktualisiert!", "organizations-are-being-loaded": "Organisationen werden geladen ...",
"password-is-required": "Passwort muss angegeben werden", "orgs": "Organisationen",
"password-reset-failed": "Passwort zurücksetzen ist fehlgeschlagen!", "oss_credit_description": "Wir verwenden eine Menge Open Source-Software bei diesen Projekten und möchten uns bei den folgenden Projekten und Mitwirkenden bedanken, die dazu beitragen, Open Source großartig zu machen!",
"password-reset-in-progress": "Passwort wird zurückgesetzt...", "paid": "BEZAHLT",
"password-reset-mail-sent": "Passwort-Reset Mail wurde an \"{usersEmail}\" geschickt.", "paid-amount": "Gezahlter Betrag",
"password-reset-successful": "Passwort erfolgreich zurückgesetzt!", "password": "Passwort",
"passwords-dont-match": "Die Passwörter stimmen nicht überein!", "password-changed": "Passwort wurde aktualisiert!",
"payment-amount-must-be-greater-than-0-00eur": "Der Zahlungsbetrag muss größer als 0.00€ sein!", "password-is-required": "Passwort muss angegeben werden",
"pdf-generation-failed": "PDF Generierung fehlgeschlagen!", "password-reset-failed": "Passwort zurücksetzen ist fehlgeschlagen!",
"pdf-successfully-generated": "PDF wurde erfolgreich generiert!", "password-reset-in-progress": "Passwort wird zurückgesetzt...",
"pdfs-successfully-generated": "Alle PDFs wurden generiert!", "password-reset-mail-sent": "Passwort-Reset Mail wurde an \"{usersEmail}\" geschickt.",
"per-kilometer": "pro Kilometer", "password-reset-successful": "Passwort erfolgreich zurückgesetzt!",
"permissions": "Berechtigungen", "passwords-dont-match": "Die Passwörter stimmen nicht überein!",
"permissions-updated": "Berechtigungen aktualisiert!", "payment-amount-must-be-greater-than-0-00eur": "Der Zahlungsbetrag muss größer als 0.00€ sein!",
"phone": "Telefon", "pdf-generation-failed": "PDF Generierung fehlgeschlagen!",
"please-confirm-the-deletion-of-card": "Bitte bestätige die Löschung der Karte", "pdf-successfully-generated": "PDF wurde erfolgreich generiert!",
"please-confirm-the-deletion-of-runner": "Bitte bestätige die Löschung der Läufer:in", "pdfs-successfully-generated": "Alle PDFs wurden generiert!",
"please-confirm-the-deletion-of-scan": "Bitte bestätige die Löschung des Scans", "per-kilometer": "pro Kilometer",
"please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.", "permissions": "Berechtigungen",
"please-provide-a-password": "Bitte gebe ein Passwort an...", "permissions-updated": "Berechtigungen aktualisiert!",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", "phone": "Telefon",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.", "please-confirm-the-deletion-of-card": "Bitte bestätige die Löschung der Karte",
"please-provide-the-nessecary-information-to-create-a-new-scan": "Bitte gebe alle notwendigen Informationen an, um einen neuen Scan zu erstellen.", "please-confirm-the-deletion-of-donation": "Bitte bestätige die Löschung des Sponsorings",
"please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.", "please-confirm-the-deletion-of-runner": "Bitte bestätige die Löschung der Läufer:in",
"please-provide-the-required-information-for-creating-a-new-user-group": "Bitte gebe alle für eine neue Gruppe notwendigen Informationen an.", "please-confirm-the-deletion-of-scan": "Bitte bestätige die Löschung des Scans",
"please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.", "please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.",
"please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.", "please-provide-a-password": "Bitte gebe ein Passwort an...",
"please-provide-the-required-information-to-add-a-new-runner": "Bitte die benötigten Informationen angeben.", "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen",
"please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.", "please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.",
"please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.", "please-provide-the-nessecary-information-to-create-a-new-scan": "Bitte gebe alle notwendigen Informationen an, um einen neuen Scan zu erstellen.",
"please-provide-the-required-information-to-add-a-new-user": "Bitte gebe alle nötigen Informationen an, im die neue Benutzer:in zu erstellen.", "please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.",
"please-provide-the-required-information-to-create-a-new-scanstation": "Bitte gebe alle für eine Scannerstation notwendigen Informationen an", "please-provide-the-required-information-for-creating-a-new-user-group": "Bitte gebe alle für eine neue Gruppe notwendigen Informationen an.",
"please-provide-the-required-information-to-create-a-new-statsclient": "Bitte gebe alle für einen Statsclient notwendigen Informationen an", "please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.",
"please-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...", "please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.",
"please-wait-a-moment-your-login-is-still-being-processed": "Bitte warte einen Moment, deine Anmeldung wird verarbeitet", "please-provide-the-required-information-to-add-a-new-runner": "Bitte die benötigten Informationen angeben.",
"prefix": "Prefix", "please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.",
"privacy": "Datenschutz", "please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.",
"privacy-loading": "Datenschutzerklärung lädt...", "please-provide-the-required-information-to-add-a-new-user": "Bitte gebe alle nötigen Informationen an, im die neue Benutzer:in zu erstellen.",
"profile": "Profil", "please-provide-the-required-information-to-create-a-new-scanstation": "Bitte gebe alle für eine Scannerstation notwendigen Informationen an",
"profile-deleted": "Profil gelöscht!", "please-provide-the-required-information-to-create-a-new-statsclient": "Bitte gebe alle für einen Statsclient notwendigen Informationen an",
"profile-picture": "Profilbild", "please-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...",
"profile-updated": "Profil wurde aktualisiert!", "please-wait-a-moment-your-login-is-still-being-processed": "Bitte warte einen Moment, deine Anmeldung wird verarbeitet",
"read-license": "Lizenz-Text lesen", "prefix": "Prefix",
"receipt-needed": "Spendenquittung benötigt", "privacy": "Datenschutz",
"repo_link": "Link", "privacy-loading": "Datenschutzerklärung lädt...",
"request-a-new-reset-mail": "Neue Reset-Mail anfordern", "profile": "Profil",
"reset-my-password": "Passwort zurücksetzen", "profile-deleted": "Profil gelöscht!",
"reset-password": "Passwort zurücksetzen", "profile-picture": "Profilbild",
"runner": "Läufer:in", "profile-updated": "Profil wurde aktualisiert!",
"runner-added": "Läufer:in hinzugefügt", "read-license": "Lizenz-Text lesen",
"runner-deleted": "Läufer:in gelöscht", "receipt-needed": "Spendenquittung benötigt",
"runner-import": "Läufer:innen Import", "repo_link": "Link",
"runner-is-being-added": "Läufer:in wird hinzugefügt...", "request-a-new-reset-mail": "Neue Reset-Mail anfordern",
"runner-updated": "Läufer:in aktualisiert!", "reset-my-password": "Passwort zurücksetzen",
"runnercards": "Laeuferkarten", "reset-password": "Passwort zurücksetzen",
"runnerimport_verify_runners_org": "Bitte die Läufer:innen für den Import in die Organisation \"{org_name}\" bestätigen", "runner": "Läufer:in",
"runners": "Läufer", "runner-added": "Läufer:in hinzugefügt",
"runners-are-being-imported": "Läufer:innen werden importiert ...", "runner-deleted": "Läufer:in gelöscht",
"runners-are-being-loaded": "Läufer:innen werden geladen ...", "runner-import": "Läufer:innen Import",
"save": "Speichern", "runner-is-being-added": "Läufer:in wird hinzugefügt...",
"save-changes": "Änderungen speichern", "runner-updated": "Läufer:in aktualisiert!",
"scan-added": "Scan hinzugefügt", "runnercards": "Laeuferkarten",
"scan-deleted": "Scan gelöscht", "runnerimport_verify_runners_org": "Bitte die Läufer:innen für den Import in die Organisation \"{org_name}\" bestätigen",
"scan-is-being-updated": "Scan wird aktualisiert", "runners": "Läufer",
"scan-with-fixed-distance": "Scan mit Festdistanz", "runners-are-being-imported": "Läufer:innen werden importiert ...",
"scans": "Scans", "runners-are-being-loaded": "Läufer:innen werden geladen ...",
"scans-are-being-loaded": "Scans werden geladen", "save": "Speichern",
"scanstation": "Scanner Station", "save-changes": "Änderungen speichern",
"scanstation-added": "Station wurde erstellt", "scan-added": "Scan hinzugefügt",
"scanstation-is-being-added": "Scannerstation wird angelegt...", "scan-deleted": "Scan gelöscht",
"scanstations": "Scanner Stationen", "scan-is-being-updated": "Scan wird aktualisiert",
"scanstations-are-being-loaded": "Scannerstationen werden geladen...", "scan-with-fixed-distance": "Scan mit Festdistanz",
"search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)", "scans": "Scans",
"search-for-an-organization-or-team-by-name-or-id": "Suche eine Organisation oder ein Team (via Name oder Id)", "scans-are-being-loaded": "Scans werden geladen",
"search-for-donor-name-or-id": "Suche eine Spender:in (via Name oder Id)", "scanstation": "Scanner Station",
"search-for-permission": "Berechtigungen durchsuchen", "scanstation-added": "Station wurde erstellt",
"search-for-runner-by-name-or-id": "Suche eine Läufer:in (via Name oder Id)", "scanstation-is-being-added": "Scannerstation wird angelegt...",
"select-all": "Alle auswählen", "scanstations": "Scanner Stationen",
"select-language": "Sprache auswählen", "scanstations-are-being-loaded": "Scannerstationen werden geladen...",
"selfservice-registration": "Selfservice Registrierung", "search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)",
"send-a-mail-to-lfk-odit-services": "Sende eine Mail an lfk@odit.services", "search-for-an-organization-or-team-by-name-or-id": "Suche eine Organisation oder ein Team (via Name oder Id)",
"set-the-user-active-inactive": "Den Benutzer auf (in)aktiv setzen", "search-for-donor-name-or-id": "Suche eine Spender:in (via Name oder Id)",
"settings": "Einstellungen", "search-for-permission": "Berechtigungen durchsuchen",
"settings-for-your-profile": "Die Einstellungen deines Accounts", "search-for-runner-by-name-or-id": "Suche eine Läufer:in (via Name oder Id)",
"something-about-the-group": "Infos zur Gruppe", "select-all": "Alle auswählen",
"sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen", "select-language": "Sprache auswählen",
"sponsorings": "Sponsoringerklaerungen", "selfservice-registration": "Selfservice Registrierung",
"station-deleted": "Scannerstation gelöscht", "send-a-mail-to-lfk-odit-services": "Sende eine Mail an lfk@odit.services",
"stats-are-being-loaded": "Die Statistiken werden geladen...", "set-the-user-active-inactive": "Den Benutzer auf (in)aktiv setzen",
"statsclient-deleted": "Statsclient wurde gelöscht", "settings": "Einstellungen",
"statsclient-is-being-added": "Statsclient wird angelegt...", "settings-for-your-profile": "Die Einstellungen deines Accounts",
"statsclients": "Statsclient (aka Beamershow)", "something-about-the-group": "Infos zur Gruppe",
"statsclients-are-being-loaded": "Statsclients werden geladen", "sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen",
"status": "Status", "sponsorings": "Sponsoringerklaerungen",
"stuff-that-could-harm-your-profile": "Einstellungen, die deinem Profil nachhaltig schaden können", "station-deleted": "Scannerstation gelöscht",
"successful-password-reset": "Passwort erfolgreich zurückgesetzt!", "stats-are-being-loaded": "Die Statistiken werden geladen...",
"team": "Team", "statsclient-deleted": "Statsclient wurde gelöscht",
"team-added": "Team wurde hinzugefügt", "statsclient-is-being-added": "Statsclient wird angelegt...",
"team-deleted": "Team gelöscht", "statsclients": "Statsclient (aka Beamershow)",
"team-detail-is-being-loaded": "Team wird geladen...", "statsclients-are-being-loaded": "Statsclients werden geladen",
"team-is-being-added": "Team wird erstellt...", "status": "Status",
"team-name": "Teamname", "stuff-that-could-harm-your-profile": "Einstellungen, die deinem Profil nachhaltig schaden können",
"team-name-is-required": "Teamname ist erforderlich", "successful-password-reset": "Passwort erfolgreich zurückgesetzt!",
"teams": "Teams", "team": "Team",
"teams-are-being-loaded": "Teams werden geladen ...", "team-added": "Team wurde hinzugefügt",
"the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "Die angegebene Telefonnummer ist nicht korrekt. <br /> Bitte gebe eine Telefonnummer im internationalen Format an...", "team-deleted": "Team gelöscht",
"the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.", "team-detail-is-being-loaded": "Team wird geladen...",
"the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "Der Scannerstation Token wird nur einmal angezeigt - du kannst ihn nicht ändern oder ihn dir nochmal anzeigen lassen!", "team-is-being-added": "Team wird erstellt...",
"the-statsclient-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "Der Statsclient Token wird nur einmal angezeigt - du kannst ihn nicht ändern oder ihn dir nochmal anzeigen lassen!", "team-name": "Teamname",
"there-are-no-cards-yet": "Es gibt noch keine Läuferkarten.", "team-name-is-required": "Teamname ist erforderlich",
"there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.", "teams": "Teams",
"there-are-no-donations-yet": "Es gibt noch keine Sponsorings", "teams-are-being-loaded": "Teams werden geladen ...",
"there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen", "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "Die angegebene Telefonnummer ist nicht korrekt. <br /> Bitte gebe eine Telefonnummer im internationalen Format an...",
"there-are-no-groups-yet": "Es gibt noch keine Gruppen", "the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.",
"there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.", "the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "Der Scannerstation Token wird nur einmal angezeigt - du kannst ihn nicht ändern oder ihn dir nochmal anzeigen lassen!",
"there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.", "the-statsclient-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "Der Statsclient Token wird nur einmal angezeigt - du kannst ihn nicht ändern oder ihn dir nochmal anzeigen lassen!",
"there-are-no-scans-yet": "Es gibt noch keine Scans", "there-are-no-cards-yet": "Es gibt noch keine Läuferkarten.",
"there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.", "there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.",
"there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.", "there-are-no-donations-yet": "Es gibt noch keine Sponsorings",
"this-card-is": "Diese Karte ist", "there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen",
"this-might-take-a-moment": "Das könnte einen kleinen Moment dauern", "there-are-no-groups-yet": "Es gibt noch keine Gruppen",
"this-scanstation-is": "Diese Station ist", "there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.",
"timestamp": "Timestamp", "there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.",
"token": "Token", "there-are-no-scans-yet": "Es gibt noch keine Scans",
"total-distance": "gelaufene Strecke", "there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.",
"total-donation-amount": "Gesamtbetrag", "there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.",
"total-donations": "Spendensumme", "this-card-is": "Diese Karte ist",
"total-paid-amount": "Gezahlter Gesamtbetrag", "this-might-take-a-moment": "Das könnte einen kleinen Moment dauern",
"total-scans": "gesamte Scans", "this-scanstation-is": "Diese Station ist",
"total_donation_amount_in_eur": "Gesamtbetrag in €", "timestamp": "Timestamp",
"track": "Track", "token": "Token",
"track-added": "Track hinzugefügt", "total-distance": "gelaufene Strecke",
"track-data-is-being-loaded": "Trackdaten werden geladen", "total-donation-amount": "Gesamtbetrag",
"track-is-being-added": "Track wird hinzugefügt...", "total-donation-count": "Gesamte Sponsorings",
"track-is-being-updated": "Track wird aktualisiert...", "total-donations": "Spendensumme",
"track-length-in-m": "Tracklänge (in Metern)", "total-donors": "gesamte Sponsor:innen",
"track-length-must-be-greater-than-0": "Die Länge muss größer als 0 (Meter) sein", "total-paid-amount": "Gezahlter Gesamtbetrag",
"track-name": "Trackname", "total-scans": "gesamte Scans",
"track-name-must-not-be-empty": "Der Name muss angegeben werden", "total_donation_amount_in_eur": "Gesamtbetrag in €",
"track-was-updated": "Track wurde aktualisiert", "track": "Track",
"tracks": "Tracks", "track-added": "Track hinzugefügt",
"unpaid": "Offen", "track-data-is-being-loaded": "Trackdaten werden geladen",
"update-card": "Karte aktualisieren", "track-is-being-added": "Track wird hinzugefügt...",
"update-password": "Passwort ändern", "track-is-being-updated": "Track wird aktualisiert...",
"updated-contact": "Kontakt aktualisiert!", "track-length-in-m": "Tracklänge (in Metern)",
"updated-donor": "Sponsor:in wurde aktualisiert", "track-length-must-be-greater-than-0": "Die Länge muss größer als 0 (Meter) sein",
"updated-organization": "Organisation wurde aktualisiert", "track-name": "Trackname",
"updated-scan": "Scan wurde aktualisiert", "track-name-must-not-be-empty": "Der Name muss angegeben werden",
"updated-team": "Team wurde aktualisiert", "track-was-updated": "Track wurde aktualisiert",
"updateing-group": "Gruppe wird aktualisiert...", "tracks": "Tracks",
"updating-card": "Karte wird aktualisiert", "unpaid": "Offen",
"updating-donation": "Sponsoring wird aktualisiert", "update-card": "Karte aktualisieren",
"updating-organization": "Organisation wird aktualisiert", "update-password": "Passwort ändern",
"updating-permissions": "Berechtigungen werden aktualisiert...", "updated-contact": "Kontakt aktualisiert!",
"updating-runner": "Läufer:in wird aktualisiert.", "updated-donor": "Sponsor:in wurde aktualisiert",
"updating-team": "Team wird aktualisiert", "updated-organization": "Organisation wurde aktualisiert",
"updating-user": "Benutzer:in wird aktualisiert...", "updated-scan": "Scan wurde aktualisiert",
"updating-your-profile": "Profil wird aktualisiert...", "updated-team": "Team wurde aktualisiert",
"user-added": "Benutzer hinzugefügt", "updateing-group": "Gruppe wird aktualisiert...",
"user-groups": "Benutzergruppen", "updating-card": "Karte wird aktualisiert",
"user-is-being-added": "Benutzer wird hinzugefügt ...", "updating-donation": "Sponsoring wird aktualisiert",
"user-updated": "Benutzer:in wurde aktualisiert", "updating-organization": "Organisation wird aktualisiert",
"username": "Benutzername", "updating-permissions": "Berechtigungen werden aktualisiert...",
"users": "Benutzer", "updating-runner": "Läufer:in wird aktualisiert.",
"valid": "Gültig", "updating-team": "Team wird aktualisiert",
"valid-city-is-required": "Du musst eine Stadt angeben", "updating-user": "Benutzer:in wird aktualisiert...",
"valid-email-is-required": "Es wird eine valide E-Mail Adresse benötigt", "updating-your-profile": "Profil wird aktualisiert...",
"valid-international-phone-number-is-required": "Du musst eine Telefonnummer im internationalen Format angeben...", "user-added": "Benutzer hinzugefügt",
"valid-zipcode-postal-code-is-required": "Du musst eine valide Postleitzahl angeben", "user-groups": "Benutzergruppen",
"verfuegbare": "Verfügbar", "user-is-being-added": "Benutzer wird hinzugefügt ...",
"welcome_wavinghand": "Willkommen 👋", "user-updated": "Benutzer:in wurde aktualisiert",
"yes-i-copied-the-token": "Ja, ich habe den Token kopiert", "username": "Benutzername",
"you-are-going-to-loose-all-permissions-and-access-to-the-runner-system": "Du wirst all deine Berechtigungen und den Zugriff aufs Läufersystem verlieren!", "users": "Benutzer",
"you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount": "Du kannst den Betrag der Zahlung entweder manuell eingeben oder über den MAX Button auf den Spendenbetrag setzen", "valid": "Gültig",
"you-can-now-use-your-new-password-to-log-in-to-your-account": "Du kannst dich jetzt mit deinem neuen Passwort anmelden! 🎉", "valid-city-is-required": "Du musst eine Stadt angeben",
"you-can-provide-a-runner-but-you-dont-have-to": "Du kannst eine Läufer:in angeben, musst aber nicht.", "valid-email-is-required": "Es wird eine valide E-Mail Adresse benötigt",
"you-dont-have-any-scanclients-yet": "Es gibt noch keine Statsclients", "valid-international-phone-number-is-required": "Du musst eine Telefonnummer im internationalen Format angeben...",
"you-dont-have-any-scanstations-yet": "Es gibt noch keine Scannerstationen", "valid-zipcode-postal-code-is-required": "Du musst eine valide Postleitzahl angeben",
"you-have-to-provide-an-organization": "Du musst eine Organisation angeben", "verfuegbare": "Verfügbar",
"you-have-to-save-your-changes-to-generate-a-link": "Du musst deine Änderungen speichern, um einen Link zu generieren.", "welcome_wavinghand": "Willkommen 👋",
"you-must-create-at-least-one-card-or-cancel": "Du musst mindestens eine Blankokarte erstellen (oder abbrechen).", "yes-i-copied-the-token": "Ja, ich habe den Token kopiert",
"zip-postal-code": "Postleitzahl", "you-are-going-to-loose-all-permissions-and-access-to-the-runner-system": "Du wirst all deine Berechtigungen und den Zugriff aufs Läufersystem verlieren!",
"config-codes": "Konfigurations-Codes", "you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount": "Du kannst den Betrag der Zahlung entweder manuell eingeben oder über den MAX Button auf den Spendenbetrag setzen",
"api-endpoint": "API-Endpunkt" "you-can-now-use-your-new-password-to-log-in-to-your-account": "Du kannst dich jetzt mit deinem neuen Passwort anmelden! 🎉",
"you-can-provide-a-runner-but-you-dont-have-to": "Du kannst eine Läufer:in angeben, musst aber nicht.",
"you-dont-have-any-scanclients-yet": "Es gibt noch keine Statsclients",
"you-dont-have-any-scanstations-yet": "Es gibt noch keine Scannerstationen",
"you-have-to-provide-an-organization": "Du musst eine Organisation angeben",
"you-have-to-save-your-changes-to-generate-a-link": "Du musst deine Änderungen speichern, um einen Link zu generieren.",
"you-must-create-at-least-one-card-or-cancel": "Du musst mindestens eine Blankokarte erstellen (oder abbrechen).",
"zip-postal-code": "Postleitzahl"
} }

View File

@@ -1,493 +1,500 @@
{ {
"404message": "Sorry, the page you are looking for could not be found.", "404message": "Sorry, the page you are looking for could not be found.",
"404title": "Error 404", "404title": "Error 404",
"about": "About", "about": "About",
"action": "Action", "action": "Action",
"active": "Active", "active": "Active",
"add-card": "Add Card", "add-card": "Add Card",
"add-donation": "Add donation", "add-donation": "Add donation",
"add-donor": "Add donor", "add-donor": "Add donor",
"add-or-update-a-payment": "Add or update a payment", "add-or-update-a-payment": "Add or update a payment",
"add-scan": "Add scan", "add-scan": "Add scan",
"add-the-first-scanstation": "Add your first scanstation.", "add-the-first-scanstation": "Add your first scanstation.",
"add-the-first-statsclient": "Add your first statsclient.", "add-the-first-statsclient": "Add your first statsclient.",
"add-user-group": "Add User Group", "add-user-group": "Add User Group",
"add-your-first-card": "Add your first card", "add-your-first-card": "Add your first card",
"add-your-first-contact": "Add your first contact", "add-your-first-contact": "Add your first contact",
"add-your-first-donor": "add your first donor", "add-your-first-donor": "add your first donor",
"add-your-first-group": "Add your first group", "add-your-first-group": "Add your first group",
"add-your-first-organization": "Add your first organization", "add-your-first-organization": "Add your first organization",
"add-your-first-runner": "Add your first runner", "add-your-first-runner": "Add your first runner",
"add-your-first-team": "Add your first team", "add-your-first-team": "Add your first team",
"add-your-first-track": "Add your first track.", "add-your-first-track": "Add your first track.",
"add-your-first-user": "Add your first user", "add-your-first-user": "Add your first user",
"add-your-fist-donation": "Add your fist donation", "add-your-fist-donation": "Add your fist donation",
"add-your-fist-scan": "Add your fist scan", "add-your-fist-scan": "Add your fist scan",
"adding-card": "Adding Card", "adding-card": "Adding Card",
"adding-donation": "Adding donation...", "adding-donation": "Adding donation...",
"adding-scan": "Adding Scan", "adding-scan": "Adding Scan",
"address": "Address", "address": "Address",
"address-is-required": "Address is required", "address-is-required": "Address is required",
"after-deletion-we-cant-restore-your-old-profile": "After deletion we can't restore your old profile!", "after-deletion-we-cant-restore-your-old-profile": "After deletion we can't restore your old profile!",
"after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that": "After the update you'll get logged out - Please login with your new password after that.", "after-the-update-youll-get-logged-out-please-login-with-your-new-password-after-that": "After the update you'll get logged out - Please login with your new password after that.",
"all": "all", "all": "all",
"all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well", "all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well",
"all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!", "all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!",
"all-associated-scans-will-get-deleted-as-well": "All associated scans will get deleted as well", "all-associated-scans-will-get-deleted-as-well": "All associated scans will get deleted as well",
"all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!", "all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!",
"already-paid": "Already paid", "already-paid": "Already paid",
"amount": "Amount", "amount": "Amount",
"amount-per-kilometer": "Amount per kilometer", "amount-per-kilometer": "Amount per kilometer",
"apartment-suite-etc": "Apartment, suite, etc.", "apartment-suite-etc": "Apartment, suite, etc.",
"application_name": "Lauf für Kaya! - Admin", "api-endpoint": "API-Endpoint",
"applying-changes": "Applying Changes", "application_name": "Lauf für Kaya! - Admin",
"attention": "Attention!", "applying-changes": "Applying Changes",
"author": "Author", "attention": "Attention!",
"bitte-bestaetige-diese-laeufer-fuer-den-import": "Please confirm these runners for import.", "author": "Author",
"by": "by", "average-distance": "average distance",
"cancel": "Cancel", "average-donation": "average donation",
"cancel-delete": "Cancel Delete", "bitte-bestaetige-diese-laeufer-fuer-den-import": "Please confirm these runners for import.",
"cancel-keep-donor": "Cancel, keep donor", "by": "by",
"cancel-keep-my-profile": "Cancel, keep my profile", "cancel": "Cancel",
"cancel-keep-organization": "Cancel, keep organization", "cancel-delete": "Cancel Delete",
"cancel-keep-station": "Cancel, keep station", "cancel-keep-donor": "Cancel, keep donor",
"cancel-keep-statsclient": "Cancel and keep statsclient", "cancel-keep-my-profile": "Cancel, keep my profile",
"cancel-keep-team": "Cancel, keep team", "cancel-keep-organization": "Cancel, keep organization",
"cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", "cancel-keep-station": "Cancel, keep station",
"card": "card", "cancel-keep-statsclient": "Cancel and keep statsclient",
"card-added": "Card added", "cancel-keep-team": "Cancel, keep team",
"card-deleted": "Card deleted", "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity",
"card-updated": "Card updated", "card": "card",
"cards": "Cards", "card-added": "Card added",
"cards-deleted": "Cards deleted", "card-deleted": "Card deleted",
"certificates": "Certificates", "card-updated": "Card updated",
"change-your-password-here": "Change your password here", "cards": "Cards",
"changing-your-password": "Changing your password", "cards-deleted": "Cards deleted",
"city": "City", "certificates": "Certificates",
"click-to-copy-the-link-into-your-clipboard": "Click to copy the link into your clipboard", "change-your-password-here": "Change your password here",
"click-to-copy-token-to-clipboard": "Click to copy the token to your clipboard", "changing-your-password": "Changing your password",
"close": "Close", "city": "City",
"code": "Code", "click-to-copy-the-link-into-your-clipboard": "Click to copy the link into your clipboard",
"configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times", "click-to-copy-token-to-clipboard": "Click to copy the token to your clipboard",
"confirm": "Confirm", "close": "Close",
"confirm-delete": "Confirm Delete", "code": "Code",
"confirm-delete-donor-with-all-donations": "Confirm, delete donor with all donations", "config-codes": "Config codes",
"confirm-delete-my-user-profile": "Confirm, delete my user profile", "configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times",
"confirm-delete-organization-and-associated-teams-runners": "Confirm, delete organization and associated teams+runners.", "confirm": "Confirm",
"confirm-delete-station-with-all-scans": "Confirm deletion of station with all scans", "confirm-delete": "Confirm Delete",
"confirm-delete-statsclient": "Confirm, delete statsclient", "confirm-delete-donor-with-all-donations": "Confirm, delete donor with all donations",
"confirm-delete-team-and-associated-runners": "Confirm, delete team and associated runners.", "confirm-delete-my-user-profile": "Confirm, delete my user profile",
"confirm-deletion": "Confirm Deletion", "confirm-delete-organization-and-associated-teams-runners": "Confirm, delete organization and associated teams+runners.",
"confirm-the-new-password": "Confirm the new password", "confirm-delete-station-with-all-scans": "Confirm deletion of station with all scans",
"contact": "Contact", "confirm-delete-statsclient": "Confirm, delete statsclient",
"contact-added": "Contact added", "confirm-delete-team-and-associated-runners": "Confirm, delete team and associated runners.",
"contact-deleted": "Contact deleted", "confirm-deletion": "Confirm Deletion",
"contact-information": "Contact Information", "confirm-the-new-password": "Confirm the new password",
"contact-is-being-added": "Contact is being added...", "contact": "Contact",
"contact-is-being-updated": "Contact is being updated...", "contact-added": "Contact added",
"contact-is-not-a-member-in-any-group": "Contact is not a member in any group", "contact-deleted": "Contact deleted",
"contacts": "Contacts", "contact-information": "Contact Information",
"contacts-are-being-loaded": "contacts are being loaded...", "contact-is-being-added": "Contact is being added...",
"copied-link-to-clipboard": "Copied link to clipboard", "contact-is-being-updated": "Contact is being updated...",
"copied-token-to-clipboard": "Copied token to clipboard", "contact-is-not-a-member-in-any-group": "Contact is not a member in any group",
"count_organizations": "# Organizations", "contacts": "Contacts",
"count_teams": "# Teams", "contacts-are-being-loaded": "contacts are being loaded...",
"create": "Create", "copied-link-to-clipboard": "Copied link to clipboard",
"create-a-new": "Create a new", "copied-token-to-clipboard": "Copied token to clipboard",
"create-a-new-card": "Create a new card", "count_organizations": "# Organizations",
"create-a-new-contact": "Create a new contact", "count_teams": "# Teams",
"create-a-new-distance-donation": "Create a new distance donation", "create": "Create",
"create-a-new-donor": "Create a new donor", "create-a-new": "Create a new",
"create-a-new-fixed-donation": "Create a new fixed donation", "create-a-new-card": "Create a new card",
"create-a-new-organization": "Create a new Organization", "create-a-new-contact": "Create a new contact",
"create-a-new-runner": "Create a new Runner", "create-a-new-distance-donation": "Create a new distance donation",
"create-a-new-scan-fixed-only": "Create a new scan (fixed only)", "create-a-new-donor": "Create a new donor",
"create-a-new-scanstation": "Create a new station", "create-a-new-fixed-donation": "Create a new fixed donation",
"create-a-new-statsclient": "Create a new statsclient", "create-a-new-organization": "Create a new Organization",
"create-a-new-team": "Create a new team", "create-a-new-runner": "Create a new Runner",
"create-a-new-track": "Create a new Track", "create-a-new-scan-fixed-only": "Create a new scan (fixed only)",
"create-a-new-user": "Create a new User", "create-a-new-scanstation": "Create a new station",
"create-a-new-user-group": "Create a new user group", "create-a-new-statsclient": "Create a new statsclient",
"create-and-generate-pdf": "Create and generate PDF", "create-a-new-team": "Create a new team",
"create-bulk-blanco-cards": "Create bulk blanco cards", "create-a-new-track": "Create a new Track",
"create-bulk-cards": "Add blanco cards", "create-a-new-user": "Create a new User",
"create-organization": "Create Organization", "create-a-new-user-group": "Create a new user group",
"create-team": "Create Team", "create-and-generate-pdf": "Create and generate PDF",
"create-track": "Create Track", "create-bulk-blanco-cards": "Create bulk blanco cards",
"create-user": "Create User", "create-bulk-cards": "Add blanco cards",
"create-without-pdf": "Create without PDF", "create-organization": "Create Organization",
"created-blanco-cards": "Created blanco cards", "create-team": "Create Team",
"creating-blanco-cards": "Creating blanco cards", "create-track": "Create Track",
"credits": "Credits", "create-user": "Create User",
"csv_import__class": "Class", "create-without-pdf": "Create without PDF",
"csv_import__firstname": "Firstname", "created-blanco-cards": "Created blanco cards",
"csv_import__lastname": "Lastname", "creating-blanco-cards": "Creating blanco cards",
"csv_import__middlename": "Middlename", "credits": "Credits",
"csv_import__team": "Team", "csv_import__class": "Class",
"danger-zone": "Danger zone", "csv_import__firstname": "Firstname",
"dashboard-greeting": "Hello", "csv_import__lastname": "Lastname",
"dashboard-title": "Dashboard", "csv_import__middlename": "Middlename",
"datatable": { "csv_import__team": "Team",
"search": "🔍 Search...", "danger-zone": "Danger zone",
"sort_column_ascending": "Sort column ascending", "dashboard-greeting": "Hello",
"sort_column_descending": "Sort column descending", "dashboard-title": "Dashboard",
"previous": "Previous", "datatable": {
"next": "Next", "search": "🔍 Search...",
"page": "Page", "sort_column_ascending": "Sort column ascending",
"showing": "Showing", "sort_column_descending": "Sort column descending",
"records": "Records", "previous": "Previous",
"of": "of", "next": "Next",
"to": "to", "page": "Page",
"loading": "Loading...", "showing": "Showing",
"no_matching_records_found": "No matching records found", "records": "Records",
"an_error_happened_while_fetching_the_data": "An error happened while fetching the data" "of": "of",
}, "to": "to",
"delete": "Delete", "loading": "Loading...",
"delete-cards": "Delete cards", "no_matching_records_found": "No matching records found",
"delete-contact": "Delete Contact", "an_error_happened_while_fetching_the_data": "An error happened while fetching the data"
"delete-donation": "Delete Donation", },
"delete-donor": "Delete donor", "delete": "Delete",
"delete-group": "Delete Group", "delete-cards": "Delete cards",
"delete-organization": "Delete Organization", "delete-contact": "Delete Contact",
"delete-profile": "Delete Profile", "delete-donation": "Delete Donation",
"delete-runner": "Delete Runner", "delete-donor": "Delete donor",
"delete-scan": "Delete scan", "delete-group": "Delete Group",
"delete-scans": "Delete scans", "delete-organization": "Delete Organization",
"delete-station": "Delete station", "delete-profile": "Delete Profile",
"delete-statsclient": "Delete statsclient", "delete-runner": "Delete Runner",
"delete-team": "Delete Team", "delete-scan": "Delete scan",
"delete-user": "Delete User", "delete-scans": "Delete scans",
"deleted-scan": "Deleted scan", "delete-station": "Delete station",
"dependency_name": "Name", "delete-statsclient": "Delete statsclient",
"description": "description", "delete-team": "Delete Team",
"description-optional": "Description (optional)", "delete-user": "Delete User",
"deselect-all": "deselect all", "deleted-scan": "Deleted scan",
"details": "Details", "dependency_name": "Name",
"disabled": "disabled", "description": "description",
"distance": "Distance", "description-optional": "Description (optional)",
"distance-donation": "distance donation", "deselect-all": "deselect all",
"distance-in-km": "Distance in km", "details": "Details",
"distance-track": "Distance (+Track)", "disabled": "disabled",
"do-you-really-want-to-delete-your-profile": "Do you really want to delete your profile?", "distance": "Distance",
"do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?", "distance-donation": "distance donation",
"do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?", "distance-in-km": "Distance in km",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations", "distance-track": "Distance (+Track)",
"documentation": "Documentation", "do-you-really-want-to-delete-your-profile": "Do you really want to delete your profile?",
"donation-amount": "Donation amount", "do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?",
"donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€", "do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?",
"donation-deleted": "Donation deleted", "do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations",
"donation-updated": "Donation updated", "documentation": "Documentation",
"donation_added": "Donation_added", "donation-amount": "Donation amount",
"donations": "Donations", "donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€",
"donor": "Donor", "donation-deleted": "Donation deleted",
"donor-added": "Donor added", "donation-updated": "Donation updated",
"donor-deleted": "donor deleted", "donation_added": "Donation_added",
"donor-has-no-associated-donations": "Donor has no associated donations.", "donations": "Donations",
"donor-is-being-added": "Donor is being added...", "donations-are-being-loaded": "donations are being loaded",
"donor-is-being-updated": "Donor is being updated", "donor": "Donor",
"donors": "Donors", "donor-added": "Donor added",
"donors-are-being-loaded": "donors are being loaded", "donor-deleted": "donor deleted",
"dont-have-your-email-connected": "Don't have your email connected?", "donor-has-no-associated-donations": "Donor has no associated donations.",
"dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌", "donor-is-being-added": "Donor is being added...",
"e-mail-adress": "E-Mail Adress", "donor-is-being-updated": "Donor is being updated",
"edit": "Edit", "donors": "Donors",
"edit-a-card": "Edit a card", "donors-are-being-loaded": "donors are being loaded",
"edit-permissions": "edit permissions", "dont-have-your-email-connected": "Don't have your email connected?",
"email_address_or_username": "Email / username", "dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌",
"enabled": "enabled", "e-mail-adress": "E-Mail Adress",
"enabled_large": "Enabled", "edit": "Edit",
"english": "English", "edit-a-card": "Edit a card",
"enter-payment": "Enter payment", "edit-permissions": "edit permissions",
"error-during-import": "Error during import", "email_address_or_username": "Email / username",
"error-whyile-copying-to-clipboard": "Error while copying to clipboard", "enabled": "enabled",
"error_on_login": "Error on login", "enabled_large": "Enabled",
"erteilte": "Directly granted", "english": "English",
"everything-concerning-your-profile": "Everything concerning your profile", "enter-payment": "Enter payment",
"everything-is-more-fun-together": "everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️", "error-during-import": "Error during import",
"faq": "FAQ", "error-whyile-copying-to-clipboard": "Error while copying to clipboard",
"filename_sponsoringquittungsliste": "DonorReceiptList", "error_on_login": "Error on login",
"filter-by-organization-team": "Filter by Organization/ Team", "erteilte": "Directly granted",
"first-name": "First name", "everything-concerning-your-profile": "Everything concerning your profile",
"first-name-is-required": "First Name is required", "everything-is-more-fun-together": "everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️",
"first-scan-of-the-day": "First scan of the day.", "faq": "FAQ",
"fixed-donation": "fixed donation", "filename_sponsoringquittungsliste": "DonorReceiptList",
"forgot_password": "Forgot your password?", "filter-by-organization-team": "Filter by Organization/ Team",
"geerbte": "inherited", "first-name": "First name",
"general-stats": "General Stats", "first-name-is-required": "First Name is required",
"general_promise_error": "😢 Error", "first-scan-of-the-day": "First scan of the day.",
"generate-runner-certificate": "Generate runner certificate", "fixed-donation": "fixed donation",
"generate-runner-certificates": "Generate runner certificates", "forgot_password": "Forgot your password?",
"generate-runnercards": "Generate Runnercards", "geerbte": "inherited",
"generate-sponsoring-contract": "generate sponsoring contract", "general-stats": "General Stats",
"generate-sponsoring-contracts": "generate sponsoring contracts", "general_promise_error": "😢 Error",
"generating-pdf": "generating PDF...", "generate-runner-certificate": "Generate runner certificate",
"generating-pdfs": "generating PDFs...", "generate-runner-certificates": "Generate runner certificates",
"generic-ui-logic-error": "Something went wrong in the UI logic", "generate-runnercards": "Generate Runnercards",
"german": "German", "generate-sponsoring-contract": "generate sponsoring contract",
"go-to-login": "Go To Login", "generate-sponsoring-contracts": "generate sponsoring contracts",
"goback": "Go Home", "generating-pdf": "generating PDF...",
"granted": "granted", "generating-pdfs": "generating PDFs...",
"group": "Group", "generic-ui-logic-error": "Something went wrong in the UI logic",
"group-added": "Group added", "german": "German",
"group-is-being-added": "Group is being added...", "go-to-login": "Go To Login",
"group-name-is-required": "Group name is required", "goback": "Go Home",
"group-updated": "group updated", "granted": "granted",
"groups": "Groups", "group": "Group",
"groups-are-being-loaded": "Groups are being loaded", "group-added": "Group added",
"home": "Home", "group-is-being-added": "Group is being added...",
"icon-image-credits": "We also want to thank these projects for illustrations and icons:", "group-name-is-required": "Group name is required",
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "If you want to create multiple blanco cards: Try the 'Add blanco cards' button.", "group-updated": "group updated",
"import-finished": "Import finished", "groups": "Groups",
"import-runners": "Import runners", "groups-are-being-loaded": "Groups are being loaded",
"import__target-organization": "Target Organization", "home": "Home",
"imprint": "Imprint", "icon-image-credits": "We also want to thank these projects for illustrations and icons:",
"imprint-loading": "Imprint loading...", "if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button": "If you want to create multiple blanco cards: Try the 'Add blanco cards' button.",
"inactive": "Inactive", "import-finished": "Import finished",
"installed-version": "Installed version", "import-runners": "Import runners",
"internal-error": "Internal Error", "import__target-organization": "Target Organization",
"invalid": "Invalid", "imprint": "Imprint",
"invalid-mail-reset": "the provided email is invalid", "imprint-loading": "Imprint loading...",
"just-enter-how-many-you-want-and-the-system-will-create-them": "Just enter how many you want and the system will create them", "inactive": "Inactive",
"key": "Key", "installed-version": "Installed version",
"laeufer-hinzufuegen": "Add runner", "internal-error": "Internal Error",
"laeufer-importieren": "Läufer importieren", "invalid": "Invalid",
"laptime": "Laptime", "invalid-mail-reset": "the provided email is invalid",
"last-name": "Last name", "just-enter-how-many-you-want-and-the-system-will-create-them": "Just enter how many you want and the system will create them",
"last-name-is-required": "Last Name is required", "key": "Key",
"lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", "laeufer-hinzufuegen": "Add runner",
"license": "License", "laeufer-importieren": "Läufer importieren",
"licenses-are-being-loaded": "Licenses are being loaded...", "laptime": "Laptime",
"loading-cards": "Loading cards", "last-name": "Last name",
"loading-contact-details": "Loading contact details...", "last-name-is-required": "Last Name is required",
"loading-donation-details": "Loading donation details", "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.",
"loading-donor-details": "Loading donor details", "license": "License",
"loading-group-detail": "Loading group detail...", "licenses-are-being-loaded": "Licenses are being loaded...",
"loading-profile-data": "Loading profile data", "loading-cards": "Loading cards",
"loading-runners": "loading runners...", "loading-contact-details": "Loading contact details...",
"loading-station-details": "Loading station details", "loading-donation-details": "Loading donation details",
"log_in": "Log in", "loading-donor-details": "Loading donor details",
"log_in_to_your_account": "Log in to your account", "loading-group-detail": "Loading group detail...",
"login_is_checked": "Login is being checked...", "loading-profile-data": "Loading profile data",
"logout": "Logout", "loading-runners": "loading runners...",
"mail-validation-in-progress": "mail validation in progress...", "loading-station-details": "Loading station details",
"manage-admin-users": "manage admin users", "log_in": "Log in",
"middle-name": "Middle name", "log_in_to_your_account": "Log in to your account",
"minimum-lap-time-in-s": "minimum lap time in s", "login_is_checked": "Login is being checked...",
"minimum-lap-time-must-be-a-positive-number-or-0": "minimum lap time must be a positive number or 0", "logout": "Logout",
"must-be-at-least-10-characters-long": "Must be at least 10 characters long!", "mail-validation-in-progress": "mail validation in progress...",
"must-contain-a-lowercase-letter": "Must contain a lowercase letter!", "manage-admin-users": "manage admin users",
"must-contain-a-number": "Must contain a number!", "middle-name": "Middle name",
"must-contain-a-uppercase-letter": "Must contain a uppercase letter!", "minimum-lap-time-in-s": "minimum lap time in s",
"name": "Name", "minimum-lap-time-must-be-a-positive-number-or-0": "minimum lap time must be a positive number or 0",
"name-is-required": "Name is required", "must-be-at-least-10-characters-long": "Must be at least 10 characters long!",
"new-password": "New password", "must-contain-a-lowercase-letter": "Must contain a lowercase letter!",
"no-contact-found": "No contacts found", "must-contain-a-number": "Must contain a number!",
"no-contact-selected": "No contact selected", "must-contain-a-uppercase-letter": "Must contain a uppercase letter!",
"no-contact-specified": "no contact specified", "name": "Name",
"no-donors-found": "No donors found", "name-is-required": "Name is required",
"no-license-text-could-be-found": "No license text could be found 😢", "new-password": "New password",
"no-organization-or-team-found": "No organization or team found", "no-address": "no address",
"no-organization-specified": "no organization specified", "no-contact-found": "No contacts found",
"no-organizations-found": "No organizations found", "no-contact-selected": "No contact selected",
"no-runners-found": "No runners found", "no-contact-specified": "no contact specified",
"no-tracks-added-yet": "there are no tracks added yet.", "no-donors-found": "No donors found",
"non-blanko": "Non/Blanko", "no-license-text-could-be-found": "No license text could be found 😢",
"open": "OPEN", "no-organization-or-team-found": "No organization or team found",
"organization": "Organization", "no-organization-specified": "no organization specified",
"organization-added": "Organization added", "no-organizations-found": "No organizations found",
"organization-deleted": "Organization deleted", "no-runners-found": "No runners found",
"organization-detail-is-being-loaded": "organization detail is being loaded...", "no-tracks-added-yet": "there are no tracks added yet.",
"organization-is-being-added": "Organization is being added...", "non-blanko": "Non/Blanko",
"organization-name-is-required": "Organization name is required", "open": "OPEN",
"organizations": "Organizations", "organization": "Organization",
"organizations-are-being-loaded": "organizations are being loaded...", "organization-added": "Organization added",
"orgs": "Organizations", "organization-deleted": "Organization deleted",
"oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!", "organization-detail-is-being-loaded": "organization detail is being loaded...",
"paid": "PAID", "organization-is-being-added": "Organization is being added...",
"paid-amount": "Paid amount", "organization-name-is-required": "Organization name is required",
"password": "Password", "organizations": "Organizations",
"password-changed": "Password changed!", "organizations-are-being-loaded": "organizations are being loaded...",
"password-is-required": "Password is required", "orgs": "Organizations",
"password-reset-failed": "Password reset failed!", "oss_credit_description": "We use a lot of open source software on these projects, and would like to thank the following projects and contributors who help make open source great!",
"password-reset-in-progress": "Password Reset in Progress...", "paid": "PAID",
"password-reset-mail-sent": "Password reset mail was sent to \"{usersEmail}\".", "paid-amount": "Paid amount",
"password-reset-successful": "Password Reset successful!", "password": "Password",
"passwords-dont-match": "Passwords don't match!", "password-changed": "Password changed!",
"payment-amount-must-be-greater-than-0-00eur": "Payment amount must be greater than 0.00€!", "password-is-required": "Password is required",
"pdf-generation-failed": "PDF generation failed!", "password-reset-failed": "Password reset failed!",
"pdf-successfully-generated": "PDF successfully generated!", "password-reset-in-progress": "Password Reset in Progress...",
"pdfs-successfully-generated": "PDFs successfully generated!", "password-reset-mail-sent": "Password reset mail was sent to \"{usersEmail}\".",
"per-kilometer": "per Kilometer", "password-reset-successful": "Password Reset successful!",
"permissions": "Permissions", "passwords-dont-match": "Passwords don't match!",
"permissions-updated": "Permissions updated!", "payment-amount-must-be-greater-than-0-00eur": "Payment amount must be greater than 0.00€!",
"phone": "Phone", "pdf-generation-failed": "PDF generation failed!",
"please-confirm-the-deletion-of-card": "Please confirm the deletion of this card", "pdf-successfully-generated": "PDF successfully generated!",
"please-confirm-the-deletion-of-runner": "Please confirm the deletion of this runner", "pdfs-successfully-generated": "PDFs successfully generated!",
"please-confirm-the-deletion-of-scan": "Please confirm the deletion of scan", "per-kilometer": "per Kilometer",
"please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.", "permissions": "Permissions",
"please-provide-a-password": "Please provide a password...", "permissions-updated": "Permissions updated!",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", "phone": "Phone",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation", "please-confirm-the-deletion-of-card": "Please confirm the deletion of this card",
"please-provide-the-nessecary-information-to-create-a-new-scan": "Please provide the nessecary information to create a new scan.", "please-confirm-the-deletion-of-donation": "Please confirm the deletion of this donation",
"please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file", "please-confirm-the-deletion-of-runner": "Please confirm the deletion of this runner",
"please-provide-the-required-information-for-creating-a-new-user-group": "Please provide the required information for creating a new user group.", "please-confirm-the-deletion-of-scan": "Please confirm the deletion of scan",
"please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.", "please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.",
"please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.", "please-provide-a-password": "Please provide a password...",
"please-provide-the-required-information-to-add-a-new-runner": "Please provide the required information to add a new runner.", "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor",
"please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.", "please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation",
"please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.", "please-provide-the-nessecary-information-to-create-a-new-scan": "Please provide the nessecary information to create a new scan.",
"please-provide-the-required-information-to-add-a-new-user": "Please provide the required information to add a new user.", "please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file",
"please-provide-the-required-information-to-create-a-new-scanstation": "Please provide the required information to create a new scanstation", "please-provide-the-required-information-for-creating-a-new-user-group": "Please provide the required information for creating a new user group.",
"please-provide-the-required-information-to-create-a-new-statsclient": "Please provide the required information to create a new statsclient", "please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.",
"please-request-a-new-reset-mail": "Please request a new reset mail...", "please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.",
"please-wait-a-moment-your-login-is-still-being-processed": "Please wait a moment, your login is still being processed", "please-provide-the-required-information-to-add-a-new-runner": "Please provide the required information to add a new runner.",
"prefix": "Prefix", "please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.",
"privacy": "Privacy", "please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.",
"privacy-loading": "Privacy loading...", "please-provide-the-required-information-to-add-a-new-user": "Please provide the required information to add a new user.",
"profile": "Profile", "please-provide-the-required-information-to-create-a-new-scanstation": "Please provide the required information to create a new scanstation",
"profile-deleted": "Profile deleted!", "please-provide-the-required-information-to-create-a-new-statsclient": "Please provide the required information to create a new statsclient",
"profile-picture": "Profile Picture", "please-request-a-new-reset-mail": "Please request a new reset mail...",
"profile-updated": "Profile updated!", "please-wait-a-moment-your-login-is-still-being-processed": "Please wait a moment, your login is still being processed",
"read-license": "Read License", "prefix": "Prefix",
"receipt-needed": "Receipt needed", "privacy": "Privacy",
"repo_link": "Link", "privacy-loading": "Privacy loading...",
"request-a-new-reset-mail": "Request a new reset mail", "profile": "Profile",
"reset-my-password": "Reset my password", "profile-deleted": "Profile deleted!",
"reset-password": "Reset your password", "profile-picture": "Profile Picture",
"runner": "Runner", "profile-updated": "Profile updated!",
"runner-added": "Runner added", "read-license": "Read License",
"runner-deleted": "runner deleted", "receipt-needed": "Receipt needed",
"runner-import": "Runner Import", "repo_link": "Link",
"runner-is-being-added": "Runner is being added...", "request-a-new-reset-mail": "Request a new reset mail",
"runner-updated": "Runner updated!", "reset-my-password": "Reset my password",
"runnercards": "Runnercards", "reset-password": "Reset your password",
"runnerimport_verify_runners_org": "Please confirm these runners for import into the organization \"{org_name}\"", "runner": "Runner",
"runners": "Runners", "runner-added": "Runner added",
"runners-are-being-imported": "Runners are being imported...", "runner-deleted": "runner deleted",
"runners-are-being-loaded": "runners are being loaded...", "runner-import": "Runner Import",
"save": "Save", "runner-is-being-added": "Runner is being added...",
"save-changes": "Save Changes", "runner-updated": "Runner updated!",
"scan-added": "Scan added", "runnercards": "Runnercards",
"scan-deleted": "scan deleted", "runnerimport_verify_runners_org": "Please confirm these runners for import into the organization \"{org_name}\"",
"scan-is-being-updated": "Scan is being updated", "runners": "Runners",
"scan-with-fixed-distance": "Scan with fixed distance", "runners-are-being-imported": "Runners are being imported...",
"scans": "Scans", "runners-are-being-loaded": "runners are being loaded...",
"scans-are-being-loaded": "Scans are being loaded", "save": "Save",
"scanstation": "Scanstation", "save-changes": "Save Changes",
"scanstation-added": "Scanstation added", "scan-added": "Scan added",
"scanstation-is-being-added": "Adding scanstation...", "scan-deleted": "scan deleted",
"scanstations": "Scanstations", "scan-is-being-updated": "Scan is being updated",
"scanstations-are-being-loaded": "Loading scanstations...", "scan-with-fixed-distance": "Scan with fixed distance",
"search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)", "scans": "Scans",
"search-for-an-organization-or-team-by-name-or-id": "Search for an organization or team (by name or id)", "scans-are-being-loaded": "Scans are being loaded",
"search-for-donor-name-or-id": "Search for donor (by name or id)", "scanstation": "Scanstation",
"search-for-permission": "Search for permission", "scanstation-added": "Scanstation added",
"search-for-runner-by-name-or-id": "Search for runner (by name or id)", "scanstation-is-being-added": "Adding scanstation...",
"select-all": "select all", "scanstations": "Scanstations",
"select-language": "Select language", "scanstations-are-being-loaded": "Loading scanstations...",
"selfservice-registration": "Selfservice registration", "search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)",
"send-a-mail-to-lfk-odit-services": "send a mail to lfk@odit.services", "search-for-an-organization-or-team-by-name-or-id": "Search for an organization or team (by name or id)",
"set-the-user-active-inactive": "set the user active/ inactive", "search-for-donor-name-or-id": "Search for donor (by name or id)",
"settings": "Settings", "search-for-permission": "Search for permission",
"settings-for-your-profile": "Settings for your profile", "search-for-runner-by-name-or-id": "Search for runner (by name or id)",
"something-about-the-group": "Something about the group...", "select-all": "select all",
"sponsoring-quittungs-liste_herunterladen": "Download donor receipt list", "select-language": "Select language",
"sponsorings": "Sponsorings", "selfservice-registration": "Selfservice registration",
"station-deleted": "station deleted", "send-a-mail-to-lfk-odit-services": "send a mail to lfk@odit.services",
"stats-are-being-loaded": "stats are being loaded...", "set-the-user-active-inactive": "set the user active/ inactive",
"statsclient-deleted": "Deleted statsclient", "settings": "Settings",
"statsclient-is-being-added": "Statsclient is being added...", "settings-for-your-profile": "Settings for your profile",
"statsclients": "Statsclients (aka Beamershow)", "something-about-the-group": "Something about the group...",
"statsclients-are-being-loaded": "Loading statsclients", "sponsoring-quittungs-liste_herunterladen": "Download donor receipt list",
"status": "Status", "sponsorings": "Sponsorings",
"stuff-that-could-harm-your-profile": "Stuff that could harm your profile", "station-deleted": "station deleted",
"successful-password-reset": "Successful password reset!", "stats-are-being-loaded": "stats are being loaded...",
"team": "Team", "statsclient-deleted": "Deleted statsclient",
"team-added": "Team added", "statsclient-is-being-added": "Statsclient is being added...",
"team-deleted": "Team deleted", "statsclients": "Statsclients (aka Beamershow)",
"team-detail-is-being-loaded": "team detail is being loaded...", "statsclients-are-being-loaded": "Loading statsclients",
"team-is-being-added": "Team is being added...", "status": "Status",
"team-name": "Team name", "stuff-that-could-harm-your-profile": "Stuff that could harm your profile",
"team-name-is-required": "team name is required", "successful-password-reset": "Successful password reset!",
"teams": "Teams", "team": "Team",
"teams-are-being-loaded": "teams are being loaded...", "team-added": "Team added",
"the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "the provided phone number is invalid.<br />please enter a valid international number...", "team-deleted": "Team deleted",
"the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m", "team-detail-is-being-loaded": "team detail is being loaded...",
"the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "The scanstation api token will only get displayed once - you won't be able to change or view it again!", "team-is-being-added": "Team is being added...",
"the-statsclient-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "The statsclient api token will only get displayed once - you won't be able to change or view it again!", "team-name": "Team name",
"there-are-no-cards-yet": "There are no cards yet.", "team-name-is-required": "team name is required",
"there-are-no-contacts-added-yet": "There are no contacts added yet.", "teams": "Teams",
"there-are-no-donations-yet": "There are no donations yet", "teams-are-being-loaded": "teams are being loaded...",
"there-are-no-donors-yet": "There are no donors yet", "the-provided-phone-number-is-invalid-less-than-br-greater-than-please-enter-a-valid-international-number": "the provided phone number is invalid.<br />please enter a valid international number...",
"there-are-no-groups-yet": "There are no groups yet", "the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m",
"there-are-no-organizations-added-yet": "There are no organizations added yet.", "the-scanstations-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "The scanstation api token will only get displayed once - you won't be able to change or view it again!",
"there-are-no-runners-added-yet": "There are no runners added yet.", "the-statsclient-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again": "The statsclient api token will only get displayed once - you won't be able to change or view it again!",
"there-are-no-scans-yet": "There are no scans yet", "there-are-no-cards-yet": "There are no cards yet.",
"there-are-no-teams-added-yet": "There are no teams added yet.", "there-are-no-contacts-added-yet": "There are no contacts added yet.",
"there-are-no-users-added-yet": "There are no users added yet.", "there-are-no-donations-yet": "There are no donations yet",
"this-card-is": "This card is", "there-are-no-donors-yet": "There are no donors yet",
"this-might-take-a-moment": "This might take a moment 👀", "there-are-no-groups-yet": "There are no groups yet",
"this-scanstation-is": "This scanstation is", "there-are-no-organizations-added-yet": "There are no organizations added yet.",
"timestamp": "timestamp", "there-are-no-runners-added-yet": "There are no runners added yet.",
"token": "Token", "there-are-no-scans-yet": "There are no scans yet",
"total-distance": "total distance", "there-are-no-teams-added-yet": "There are no teams added yet.",
"total-donation-amount": "total donation amount", "there-are-no-users-added-yet": "There are no users added yet.",
"total-donations": "total donations", "this-card-is": "This card is",
"total-paid-amount": "Total paid amount", "this-might-take-a-moment": "This might take a moment 👀",
"total-scans": "total scans", "this-scanstation-is": "This scanstation is",
"total_donation_amount_in_eur": "Total donation amount in €", "timestamp": "timestamp",
"track": "Track", "token": "Token",
"track-added": "Track added", "total-distance": "total distance",
"track-data-is-being-loaded": "Track data is being loaded", "total-donation-amount": "total donation amount",
"track-is-being-added": "Track is being added...", "total-donation-count": "total donations (count)",
"track-is-being-updated": "Track is being updated...", "total-donations": "total donations",
"track-length-in-m": "Track Length in m", "total-donors": "total donors",
"track-length-must-be-greater-than-0": "Track length must be greater than 0", "total-paid-amount": "Total paid amount",
"track-name": "Track name", "total-scans": "total scans",
"track-name-must-not-be-empty": "Track name must not be empty", "total_donation_amount_in_eur": "Total donation amount in €",
"track-was-updated": "Track was updated!", "track": "Track",
"tracks": "Tracks", "track-added": "Track added",
"unpaid": "Unpaid", "track-data-is-being-loaded": "Track data is being loaded",
"update-card": "Update Card", "track-is-being-added": "Track is being added...",
"update-password": "Update password", "track-is-being-updated": "Track is being updated...",
"updated-contact": "Updated contact!", "track-length-in-m": "Track Length in m",
"updated-donor": "updated donor", "track-length-must-be-greater-than-0": "Track length must be greater than 0",
"updated-organization": "updated organization", "track-name": "Track name",
"updated-scan": "updated scan", "track-name-must-not-be-empty": "Track name must not be empty",
"updated-team": "Updated team", "track-was-updated": "Track was updated!",
"updateing-group": "updateing group...", "tracks": "Tracks",
"updating-card": "Updating card", "unpaid": "Unpaid",
"updating-donation": "Updating donation", "update-card": "Update Card",
"updating-organization": "updating organization", "update-password": "Update password",
"updating-permissions": "updating permissions...", "updated-contact": "Updated contact!",
"updating-runner": "Updating runner...", "updated-donor": "updated donor",
"updating-team": "Updating team", "updated-organization": "updated organization",
"updating-user": "updating user...", "updated-scan": "updated scan",
"updating-your-profile": "Updating your profile...", "updated-team": "Updated team",
"user-added": "User added", "updateing-group": "updateing group...",
"user-groups": "User Groups", "updating-card": "Updating card",
"user-is-being-added": "User is being added...", "updating-donation": "Updating donation",
"user-updated": "User updated", "updating-organization": "updating organization",
"username": "Username", "updating-permissions": "updating permissions...",
"users": "Users", "updating-runner": "Updating runner...",
"valid": "Valid", "updating-team": "Updating team",
"valid-city-is-required": "Valid city is required", "updating-user": "updating user...",
"valid-email-is-required": "valid email is required", "updating-your-profile": "Updating your profile...",
"valid-international-phone-number-is-required": "valid international phone number is required...", "user-added": "User added",
"valid-zipcode-postal-code-is-required": "Valid zipcode/ postal code is required", "user-groups": "User Groups",
"verfuegbare": "availdable", "user-is-being-added": "User is being added...",
"welcome_wavinghand": "Welcome 👋", "user-updated": "User updated",
"yes-i-copied-the-token": "Yes, I copied the token", "username": "Username",
"you-are-going-to-loose-all-permissions-and-access-to-the-runner-system": "You are going to loose all permissions and access to the runner system!", "users": "Users",
"you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount": "You can enter the donation's paid amount manually or use the MAX button to use the donation's exact amount.", "valid": "Valid",
"you-can-now-use-your-new-password-to-log-in-to-your-account": "You can now use your new password to log in to your account! 🎉", "valid-city-is-required": "Valid city is required",
"you-can-provide-a-runner-but-you-dont-have-to": "You can provide a runner, but you don't have to.", "valid-email-is-required": "valid email is required",
"you-dont-have-any-scanclients-yet": "You don't have any statsclients yet", "valid-international-phone-number-is-required": "valid international phone number is required...",
"you-dont-have-any-scanstations-yet": "You don't have any scanstations yet", "valid-zipcode-postal-code-is-required": "Valid zipcode/ postal code is required",
"you-have-to-provide-an-organization": "You have to provide an organization", "verfuegbare": "availdable",
"you-have-to-save-your-changes-to-generate-a-link": "You have to save your changes to generate a link.", "welcome_wavinghand": "Welcome 👋",
"you-must-create-at-least-one-card-or-cancel": "You must create at least one card (or cancel).", "yes-i-copied-the-token": "Yes, I copied the token",
"zip-postal-code": "ZIP/ postal code", "you-are-going-to-loose-all-permissions-and-access-to-the-runner-system": "You are going to loose all permissions and access to the runner system!",
"config-codes": "Config codes", "you-can-enter-the-donations-paid-amount-manually-or-use-the-max-button-to-use-the-donations-exact-amount": "You can enter the donation's paid amount manually or use the MAX button to use the donation's exact amount.",
"api-endpoint": "API-Endpoint" "you-can-now-use-your-new-password-to-log-in-to-your-account": "You can now use your new password to log in to your account! 🎉",
"you-can-provide-a-runner-but-you-dont-have-to": "You can provide a runner, but you don't have to.",
"you-dont-have-any-scanclients-yet": "You don't have any statsclients yet",
"you-dont-have-any-scanstations-yet": "You don't have any scanstations yet",
"you-have-to-provide-an-organization": "You have to provide an organization",
"you-have-to-save-your-changes-to-generate-a-link": "You have to save your changes to generate a link.",
"you-must-create-at-least-one-card-or-cancel": "You must create at least one card (or cancel).",
"zip-postal-code": "ZIP/ postal code"
} }