Compare commits

...

138 Commits

Author SHA1 Message Date
65e8998894 set table-layout:fixed + display when loaded
ref #146
2023-02-16 11:26:37 +01:00
449948050b 🚀RELEASE v0.16.1
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-15 15:05:33 +01:00
cf97281592 fix: donor detail: sponsorings: unset middlename will show as "null"
All checks were successful
continuous-integration/drone/push Build is passing
close #145
2023-02-15 15:05:01 +01:00
75684efa1a 🚀RELEASE v0.16.0
All checks were successful
continuous-integration/drone/push Build is passing
2023-02-03 14:07:27 +01:00
2c4f27a943 new license file version [CI SKIP] 2023-02-03 13:05:38 +00:00
53b7dec7cd Merge pull request 'feature/143-beamershow_clients' (#144) from feature/143-beamershow_clients into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #144
2023-02-03 13:05:01 +00:00
e0cbfb000b Tailwind bump 2023-02-02 17:27:18 +01:00
3a66f4c862 new license file version [CI SKIP] 2023-02-02 16:23:56 +00:00
85ceaa464f Merge branch 'dev' into feature/143-beamershow_clients 2023-02-02 17:23:33 +01:00
976755338b Updated docker base images
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-02 17:21:58 +01:00
1c980059cf Switched drone to kaniko 2023-02-02 17:20:01 +01:00
2d8c4c1698 Ignore pnpm lock 2023-02-02 17:19:51 +01:00
19a333d7bd Added missing translation
ref #143
2023-02-02 17:16:24 +01:00
96c55db63d Added translation
ref #143
2023-02-02 17:13:16 +01:00
fecb07ee37 Re-added copy modal
ref #143
2023-02-02 17:11:46 +01:00
e10c6480a5 Removed Key after creation
ref #143
2023-02-02 17:08:29 +01:00
f3cc07c009 Fixed imports and naming 2023-02-02 17:05:34 +01:00
068076dd47 Added Statsclients to sidebar
ref #143
2023-02-02 17:03:18 +01:00
02158605be Basic statsclient detail
ref #143
2023-02-02 17:00:49 +01:00
674e6a90ec Updated mounted variables 2023-02-02 16:54:37 +01:00
f679330466 Updated Add modal
ref #143
2023-02-02 16:51:39 +01:00
93fc7c2e83 Updated deletion modal
ref #143
2023-02-02 16:46:18 +01:00
f299617c60 First page for statsclients
ref #143
2023-02-02 16:42:17 +01:00
28cbc5b98c Bumped apiclient
ref #143
2023-02-02 16:21:11 +01:00
c28f1ee0bc Bumped apiclient
ref #143
2023-02-02 16:04:21 +01:00
cff112d705 Pinned versions
Some checks failed
continuous-integration/drone/push Build is failing
2023-02-02 16:02:52 +01:00
9fc4ad63c4 🚀RELEASE v0.15.6
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-19 17:52:02 +02:00
97054a71c1 new license file version [CI SKIP] 2021-07-19 15:49:32 +00:00
2391668a25 Fixed donations getting reduced to the first one on certificates
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-19 17:47:27 +02:00
717d33547c 🚀RELEASE v0.15.5
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-05 17:23:43 +02:00
997be32679 Merge pull request 'Fixed kilometer conversion' (#142) from bugfix/141-runner_kilometers into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #142
2021-07-05 15:22:55 +00:00
134f00c40e Fixed kilometer conversion
ref #141
2021-07-05 17:15:50 +02:00
47c898bdfd Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-07-05 17:01:59 +02:00
e752ee12d1 new license file version [CI SKIP] 2021-07-05 15:01:42 +00:00
cc4515ff66 🚀RELEASE v0.15.4 2021-07-05 17:01:31 +02:00
f190292171 Merge pull request 'fix total donation sum in dashboard' (#140) from bugfix/139-total-donation-sum-is-wrong into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #140

close #139
2021-07-05 15:00:44 +00:00
b246f2b349 divide by 100 + toFixes(2)
ref #139
2021-07-05 13:30:17 +02:00
76b69d851a 🚀RELEASE v0.15.3
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-16 18:22:27 +02:00
224f586368 Small bugfix (null got displayed) 🛠 2021-04-16 18:22:00 +02:00
9add6c8ff1 🚀RELEASE v0.15.2
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-16 18:10:50 +02:00
7a63d4eed1 Merge branch 'dev' of https://git.odit.services/lfk/frontend into dev
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-16 18:09:37 +02:00
e54a4807f7 NGINX cache assets 2021-04-16 18:09:30 +02:00
cee04c1d6f Footer - noopener link 2021-04-16 18:09:22 +02:00
cbec78589d Hotfix: Team change recognition 🐞
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-16 18:06:53 +02:00
a85db7cb3f 🚀RELEASE v0.15.1
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-16 17:53:38 +02:00
2bd3779839 Merge pull request '🐞🐳 fix Dockerfile' (#138) from bugfix/136-opacity_reactivity into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #138
2021-04-16 15:51:37 +00:00
303e33cafb 🐞🐳 fix Dockerfile
ref #136
2021-04-16 17:46:15 +02:00
b4e689dddf Dockerfile now uses selfhosted registry
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-15 19:50:37 +02:00
98a0b036c5 new license file version [CI SKIP] 2021-04-15 17:46:04 +00:00
fb3f30fb10 Merge pull request 'Opacity import fix bugfix/136-opacity_reactivity' (#137) from bugfix/136-opacity_reactivity into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #137
2021-04-15 17:44:49 +00:00
6213952007 Added bs import fix
ref #136
2021-04-15 19:43:43 +02:00
07ac041d69 🚚 move to tailwind
ref #136
2021-04-15 19:22:57 +02:00
5c02028841 🚀RELEASE v0.15.0
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-15 18:30:38 +02:00
c561b53670 Merge pull request 'Mark donations as payed feature/133-donation_payments' (#135) from feature/133-donation_payments into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #135
2021-04-15 16:29:39 +00:00
dcd0d5a362 Merge branch 'feature/133-donation_payments' of https://git.odit.services/lfk/frontend into feature/133-donation_payments 2021-04-15 18:27:47 +02:00
18acac83bc AddDonationModal - vertical alignment for paid status
ref #133
2021-04-15 18:27:35 +02:00
d7d44470bb DonationsOverview contrast on action
ref #133
2021-04-15 18:25:52 +02:00
0f0aae7ba4 Fixed chante recognition bug for fixed donation
ref #133
2021-04-15 18:21:23 +02:00
4c0886a5d9 Fixed typo
ref #133
2021-04-15 18:04:03 +02:00
04a3038369 Added missing updated comparison
ref #133
2021-04-15 16:56:03 +02:00
bdcf5d3fc0 Added payment updating via detail
ref #133
2021-04-15 15:54:14 +02:00
c7a858eed7 Sorted translations
ref #133
2021-04-15 15:42:47 +02:00
de5aa9237d Added **all** missing toast translations
ref #133
2021-04-15 15:42:29 +02:00
d015f97395 Added translations 🌎
ref #113
2021-04-15 15:34:36 +02:00
57618156b4 Added msiisng runner id conversion
ref #133
2021-04-15 15:30:23 +02:00
865254d646 Fixed styling
ref #133
2021-04-15 15:25:17 +02:00
1dbab03fe7 You can now add payments from the donation overview
ref #133
2021-04-15 15:24:31 +02:00
a943aaf5fc You can now open a modal to add a payment to a donation from the donation overview
ref #133
2021-04-15 15:05:05 +02:00
6e6e8b2617 Added Add Payment button to donor overview
ref #133
2021-04-15 14:40:46 +02:00
4c2c24af2c Changed top info style for donation overview
ref #133
2021-04-15 14:33:35 +02:00
3d3a10aafb You can now mark fixed donations as already paid on creation
ref #133
2021-04-15 14:31:24 +02:00
000fc97beb Changed top info style for donation detail
ref #133
2021-04-15 14:18:28 +02:00
5645eeaafa Added paid donation amount and status to donation detail
ref #133
2021-04-15 14:17:28 +02:00
961477d522 Added total donation amount to donation overview
ref #133
2021-04-15 14:12:11 +02:00
a5f71015a6 Added total donation amount to donor detail
ref #133
2021-04-15 14:10:35 +02:00
e42ea943b7 Added total donation amount to donor overview
ref #133
2021-04-15 14:09:23 +02:00
9c5fc6b61c 🚀RELEASE v0.14.0
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-14 19:28:00 +02:00
302caf015f new license file version [CI SKIP] 2021-04-14 17:27:30 +00:00
e11296071a Merge pull request 'added donor receipt list download to DonorsOverview' (#134) from feature/132-export-donors-receipt-list into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #134
close #132
2021-04-14 17:26:10 +00:00
112eb29f93 Switched to selfhosted images
ref #132
2021-04-14 19:24:06 +02:00
c6c97516b3 Sorted translations 🌎
ref #132
2021-04-14 19:23:26 +02:00
03676b2894 Fixed typos in translations
ref #132
2021-04-14 19:23:07 +02:00
9ca57fac2e bump @odit/lfk-client-js@0.11.0
ref #132
2021-04-14 18:58:57 +02:00
18f151c1fb general version bump
ref #132
2021-04-14 18:57:14 +02:00
e90e56d8b2 replace donationAmount with paidDonationAmount
ref #132
2021-04-14 18:54:05 +02:00
d241ca5698 added donor receipt list download to DonorsOverview
ref #132
2021-04-14 18:43:51 +02:00
b512cf8667 🚀RELEASE v0.13.1
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-11 21:14:03 +02:00
a24d2923c6 For await fix
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-11 21:13:44 +02:00
467808abef 🚀RELEASE v0.13.0
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-11 21:08:58 +02:00
861f1f2216 Merge pull request 'Better org pdf generation feature/130-org_doc_splitting' (#131) from feature/130-org_doc_splitting into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #131
2021-04-11 19:07:53 +00:00
509b22bea0 Org certificate generation now runs in sequence
ref #130
2021-04-11 21:00:33 +02:00
7447b2f4c1 Fixed const -> let
ref #130
2021-04-11 20:54:38 +02:00
fef14b6e4f Org card generation now runs in sequence
ref #130
2021-04-11 20:53:58 +02:00
01d2a7e6aa Org contract generation now runs in sequence
ref #130
2021-04-11 20:48:20 +02:00
ac586fec5a Hotfix: Org * generation🐞
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-11 20:17:34 +02:00
5476808683 Emergency document server url change
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-11 20:10:08 +02:00
331d737796 🚀RELEASE v0.12.5
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-08 19:30:20 +02:00
ef81b8adf9 Merge pull request 'Added runner team's parentorg name to runenr overciew' (#129) from feature/128-runner_orgs into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #129
2021-04-08 17:29:27 +00:00
8a7d635cef Switched to html entity
ref #128
2021-04-08 18:00:47 +02:00
4c259c1eef Added runner team's parentorg name to runenr overciew
ref #128
2021-04-08 17:58:49 +02:00
5b4ede5e2f 🚀RELEASE v0.12.4
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-08 17:34:32 +02:00
d0ab3dda78 🚑 [HOTFIX] - drop "svelte-infinite-loading"
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-08 17:34:04 +02:00
d9cf51b4bb 🚀RELEASE v0.12.3
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-08 17:30:23 +02:00
aa17f24220 new license file version [CI SKIP] 2021-04-08 15:28:50 +00:00
cf60edf7d4 Merge pull request 'fix' (#126) from bugfix/125-mobile into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #126
close #125
2021-04-08 15:27:22 +00:00
ffbc243194 custom css fix for collapsed_navigation
ref #125
2021-04-07 21:44:29 +02:00
b6b07cf30c 🐞 bugfix for svelte x tailwind class names
ref #125
2021-04-07 21:35:01 +02:00
495a6b22bd almost fixed... 2021-04-07 21:28:21 +02:00
0acaffbdfa fix
ref #125
2021-04-07 20:25:04 +02:00
6043bc4517 🚀RELEASE v0.12.2
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-07 20:11:21 +02:00
e6ed066e3f Merge pull request 'feature/110-virtual_list' (#124) from feature/110-virtual_list into dev
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #124
2021-04-07 18:10:02 +00:00
ee4e8655b8 Merge branch 'dev' into feature/110-virtual_list 2021-04-07 20:09:35 +02:00
37970d2be6 pre-merge fixes
ref #110
2021-04-07 18:59:46 +02:00
1376788016 updated virtual scroll list 2021-04-07 18:38:52 +02:00
4cad86cf85 fixed height table 2021-04-07 18:19:58 +02:00
6304116edb wip on virtuallist 2021-04-06 22:16:24 +02:00
834ff8fa63 🚀RELEASE v0.12.1
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-06 16:47:37 +02:00
1f428a535e Merge pull request 'ImportRunnerModal Cancel Button feature/122-import_cancel' (#123) from feature/112-import_cancel into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #123
2021-04-06 14:42:37 +00:00
0c40966970 Added cancel button for the first stage of runner import
ref #112
2021-04-05 16:23:24 +02:00
9da071fe9b Escape now triggers foll modal close (including reset) instead of just hiding th modal
ref #112
2021-04-05 16:14:43 +02:00
892a04f289 🚀RELEASE v0.12.0
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-05 16:09:17 +02:00
27cc9727f1 Fixed package version
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-05 16:08:41 +02:00
f0738d451b Merge pull request 'Implmented certificate generation feature/119-Certificate_generation' (#120) from feature/119-Certificate_generation into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #120
2021-04-05 14:05:38 +00:00
9e6a8daf2c Sorted translations 🌍
ref #119
2021-04-05 16:04:44 +02:00
bfacfec765 The PFS Prefixes now get translated via i18n
ref #119
2021-04-05 16:04:26 +02:00
0bae5bf32b sponsoring pdf names now include their locale
ref #119
2021-04-05 15:37:12 +02:00
22b09d16d0 Cleaned up generation strings and added the schem for single runner generations for sponsoring contracts
ref #119
2021-04-05 15:36:01 +02:00
9c867e106e Cleaned up generation strings and added the schem for single runner generations for cards
ref #119
2021-04-05 15:33:55 +02:00
304f28a3c1 certificate pdf names now include their locale
ref #119
2021-04-05 15:31:52 +02:00
d65d3793de Changed the basic nameing generation for runenr certificate files
ref #119
2021-04-05 15:31:01 +02:00
3638d87bd2 Runnercard pdfs now include their locale
ref #119
2021-04-05 15:28:13 +02:00
b97a92860d Fixed wrong permissiong getting checked
ref #119
2021-04-05 15:24:42 +02:00
7c86a5eeb3 added missing/ wrong translations + formatting!
ref #119
2021-04-05 12:02:18 +02:00
d23dbaaf69 Removed useless console.log
ref #119
2021-04-03 20:05:27 +02:00
e6ffc371e1 Certificate generation from org detail
ref #119
2021-04-03 20:03:57 +02:00
3177c6eaa3 Certificate generation from org overview
ref #119
2021-04-03 20:02:52 +02:00
acd2f0519d Certificate generation from team detail
ref #119
2021-04-03 20:00:51 +02:00
18ec100c33 Certificate generation from team overview
ref #119
2021-04-03 19:59:34 +02:00
57 changed files with 3618 additions and 1874 deletions

View File

@@ -27,7 +27,7 @@ name: build:dev
steps: steps:
- name: run full license export - name: run full license export
depends_on: ["clone"] depends_on: ["clone"]
image: node:alpine image: registry.odit.services/hub/library/node:alpine
commands: commands:
- yarn - yarn
- yarn licenses:export - yarn licenses:export
@@ -43,18 +43,23 @@ steps:
ssh_key: ssh_key:
from_secret: git_ssh from_secret: git_ssh
- name: build dev - name: build dev
image: plugins/docker depends_on: ["clone"]
depends_on: [clone] image: registry.odit.services/library/drone-kaniko
settings: settings:
username: username:
from_secret: docker_username from_secret: docker_username
password: password:
from_secret: docker_password from_secret: docker_password
repo: registry.odit.services/lfk/frontend build_args:
- NPM_REGISTRY_DOMAIN:
from_secret: npmjs_domain
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/frontend
tags: tags:
- dev - dev
cache: true
registry: registry.odit.services registry: registry.odit.services
mtu: 1000
trigger: trigger:
branch: branch:
- dev - dev
@@ -67,18 +72,23 @@ type: kubernetes
name: build:tags name: build:tags
steps: steps:
- name: build $DRONE_TAG - name: build $DRONE_TAG
image: plugins/docker depends_on: ["clone"]
depends_on: [clone] image: registry.odit.services/library/drone-kaniko
settings: settings:
username: username:
from_secret: docker_username from_secret: docker_username
password: password:
from_secret: docker_password from_secret: docker_password
repo: registry.odit.services/lfk/frontend build_args:
- NPM_REGISTRY_DOMAIN:
from_secret: npmjs_domain
- NPM_REGISTRY_TOKEN:
from_secret: npmjs_token
repo: lfk/frontend
tags: tags:
- '${DRONE_TAG}' - "${DRONE_TAG}"
cache: true
registry: registry.odit.services registry: registry.odit.services
mtu: 1000
trigger: trigger:
event: event:
- tag - tag

1
.gitignore vendored
View File

@@ -8,3 +8,4 @@ public/index.html
.yarn .yarn
.pnp.js .pnp.js
.yarnrc.yml .yarnrc.yml
pnpm-lock.yaml

View File

@@ -2,15 +2,275 @@
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.
#### [0.16.1](https://git.odit.services/lfk/frontend/compare/0.16.0...0.16.1)
- fix: donor detail: sponsorings: unset middlename will show as "null" [`#145`](https://git.odit.services/lfk/frontend/issues/145)
#### [0.16.0](https://git.odit.services/lfk/frontend/compare/0.15.6...0.16.0)
> 3 February 2023
- First page for statsclients [`f299617`](https://git.odit.services/lfk/frontend/commit/f299617c600d2bba7b4405c7c3acae9fd93aefa8)
- 🚀RELEASE v0.16.0 [`75684ef`](https://git.odit.services/lfk/frontend/commit/75684efa1ae0edb4b4d414757c5acf2a77c572e5)
- Basic statsclient detail [`0215860`](https://git.odit.services/lfk/frontend/commit/02158605be824e5ac21a6284731138190988c794)
- Updated Add modal [`f679330`](https://git.odit.services/lfk/frontend/commit/f679330466205e6480cd7f2b7c2b4fdc41c51525)
- Switched drone to kaniko [`1c98005`](https://git.odit.services/lfk/frontend/commit/1c980059cff5c87c452428b53513507c2339451f)
- Re-added copy modal [`fecb07e`](https://git.odit.services/lfk/frontend/commit/fecb07ee373dcaaeaea69fdf8d4c6ee2c257c89c)
- Added Statsclients to sidebar [`068076d`](https://git.odit.services/lfk/frontend/commit/068076dd47373c673a25e730cb8a57c686682810)
- Fixed imports and naming [`f3cc07c`](https://git.odit.services/lfk/frontend/commit/f3cc07c009ed0a34e61f1aad47a1a31778145439)
- new license file version [CI SKIP] [`2c4f27a`](https://git.odit.services/lfk/frontend/commit/2c4f27a943bb35be6728bb49bd5c2263cba78165)
- Merge pull request 'feature/143-beamershow_clients' (#144) from feature/143-beamershow_clients into dev [`53b7dec`](https://git.odit.services/lfk/frontend/commit/53b7dec7cd516c908d45591b855f4be09371f9b1)
- Updated deletion modal [`93fc7c2`](https://git.odit.services/lfk/frontend/commit/93fc7c2e83f78dd88f15d9246127bb9e69f1a8ee)
- Updated mounted variables [`674e6a9`](https://git.odit.services/lfk/frontend/commit/674e6a90ec23dde9377bea64c14a50e41ffa450d)
- Removed Key after creation [`e10c648`](https://git.odit.services/lfk/frontend/commit/e10c6480a504338b21e30fdf2577e5b6c3b635db)
- Updated docker base images [`9767553`](https://git.odit.services/lfk/frontend/commit/976755338b8621064f9a73147aa600af1f77cd51)
- Added translation [`96c55db`](https://git.odit.services/lfk/frontend/commit/96c55db63dbfed92b78ff0e7bdab7a8cce4d76e9)
- Pinned versions [`cff112d`](https://git.odit.services/lfk/frontend/commit/cff112d705a74a135286943298f3f344341325ac)
- Tailwind bump [`e0cbfb0`](https://git.odit.services/lfk/frontend/commit/e0cbfb000bee59a71e06bd58a9c7ef6a0fc7091d)
- Added missing translation [`19a333d`](https://git.odit.services/lfk/frontend/commit/19a333d7bda525fbcb3c68f3cbf85a4f925a9707)
- Bumped apiclient [`c28f1ee`](https://git.odit.services/lfk/frontend/commit/c28f1ee0bc4456595c21858f38e52ed6f16871c5)
- new license file version [CI SKIP] [`3a66f4c`](https://git.odit.services/lfk/frontend/commit/3a66f4c862db9f35c223cc7007b0560fef4e1d63)
- Bumped apiclient [`28cbc5b`](https://git.odit.services/lfk/frontend/commit/28cbc5b98ca09657100e1740b83aa2617243b26b)
- Ignore pnpm lock [`2d8c4c1`](https://git.odit.services/lfk/frontend/commit/2d8c4c1698a1675f618e85e678012f310f87c6ee)
#### [0.15.6](https://git.odit.services/lfk/frontend/compare/0.15.5...0.15.6)
> 19 July 2021
- 🚀RELEASE v0.15.6 [`9fc4ad6`](https://git.odit.services/lfk/frontend/commit/9fc4ad63c4f77b46d645e83c94b51747b91247b8)
- Fixed donations getting reduced to the first one on certificates [`2391668`](https://git.odit.services/lfk/frontend/commit/2391668a25a1e11a1409df572d77ad1635070fbc)
- new license file version [CI SKIP] [`97054a7`](https://git.odit.services/lfk/frontend/commit/97054a71c1ab8a045762a55148124965c6994373)
#### [0.15.5](https://git.odit.services/lfk/frontend/compare/0.15.4...0.15.5)
> 5 July 2021
- 🚀RELEASE v0.15.5 [`717d335`](https://git.odit.services/lfk/frontend/commit/717d33547c3378424dd720005da9952f8a753f1a)
- Merge pull request 'Fixed kilometer conversion' (#142) from bugfix/141-runner_kilometers into dev [`997be32`](https://git.odit.services/lfk/frontend/commit/997be32679dc38c9fb0e92b6ce011057b854d99d)
- Fixed kilometer conversion [`134f00c`](https://git.odit.services/lfk/frontend/commit/134f00c40e0c8252e7604a73151e8d6685b2c61d)
- new license file version [CI SKIP] [`e752ee1`](https://git.odit.services/lfk/frontend/commit/e752ee12d17a4423f4364f7766eafbe7d4cef2d1)
#### [0.15.4](https://git.odit.services/lfk/frontend/compare/0.15.3...0.15.4)
> 5 July 2021
- Merge pull request 'fix total donation sum in dashboard' (#140) from bugfix/139-total-donation-sum-is-wrong into dev [`#139`](https://git.odit.services/lfk/frontend/issues/139)
- 🚀RELEASE v0.15.4 [`cc4515f`](https://git.odit.services/lfk/frontend/commit/cc4515ff66b1c1de3747d0ee6cc465574accedb7)
- divide by 100 + toFixes(2) [`b246f2b`](https://git.odit.services/lfk/frontend/commit/b246f2b349b06d1adea318dfad58f97fb1a249bb)
#### [0.15.3](https://git.odit.services/lfk/frontend/compare/0.15.2...0.15.3)
> 16 April 2021
- 🚀RELEASE v0.15.3 [`76b69d8`](https://git.odit.services/lfk/frontend/commit/76b69d851aa590ecf8caac135b72962a72e83635)
- Small bugfix (null got displayed) 🛠 [`224f586`](https://git.odit.services/lfk/frontend/commit/224f5863683ae2543a4a435510ed2c558dc5d307)
#### [0.15.2](https://git.odit.services/lfk/frontend/compare/0.15.1...0.15.2)
> 16 April 2021
- 🚀RELEASE v0.15.2 [`9add6c8`](https://git.odit.services/lfk/frontend/commit/9add6c8ff1fbeed91fe97a7cf262921b716f4e3c)
- Footer - noopener link [`cee04c1`](https://git.odit.services/lfk/frontend/commit/cee04c1d6fb6005cefe77fb95855ab6fe2cc448f)
- Hotfix: Team change recognition 🐞 [`cbec785`](https://git.odit.services/lfk/frontend/commit/cbec78589d2fa21f12ce87e71bff2b49c3a7d345)
- NGINX cache assets [`e54a480`](https://git.odit.services/lfk/frontend/commit/e54a4807f70bc333396885f81d3dcc7ae6c115d9)
#### [0.15.1](https://git.odit.services/lfk/frontend/compare/0.15.0...0.15.1)
> 16 April 2021
- 🚀RELEASE v0.15.1 [`a85db7c`](https://git.odit.services/lfk/frontend/commit/a85db7cb3f89881794e37a66ecd822f8ad5873f1)
- Merge pull request '🐞🐳 fix Dockerfile' (#138) from bugfix/136-opacity_reactivity into dev [`2bd3779`](https://git.odit.services/lfk/frontend/commit/2bd3779839de16a89b91a3da93033e2a2b742ab7)
- 🚚 move to tailwind [`07ac041`](https://git.odit.services/lfk/frontend/commit/07ac041d69b3b1810e5db538b53fe62084490f7a)
- 🐞🐳 fix Dockerfile [`303e33c`](https://git.odit.services/lfk/frontend/commit/303e33cafb4a1be01e4c4b43f46ff0c651cb4620)
- Dockerfile now uses selfhosted registry [`b4e689d`](https://git.odit.services/lfk/frontend/commit/b4e689dddf0b93a2794aa30ea83e8c6505d6bbfd)
- new license file version [CI SKIP] [`98a0b03`](https://git.odit.services/lfk/frontend/commit/98a0b036c5490b4bc4992e83f3bca02be39927fa)
- Merge pull request 'Opacity import fix bugfix/136-opacity_reactivity' (#137) from bugfix/136-opacity_reactivity into dev [`fb3f30f`](https://git.odit.services/lfk/frontend/commit/fb3f30fb1024de61ce1c541dae90374454f6ef96)
- Added bs import fix [`6213952`](https://git.odit.services/lfk/frontend/commit/621395200751c2d42b9ad44c77e84bda03b62e83)
#### [0.15.0](https://git.odit.services/lfk/frontend/compare/0.14.0...0.15.0)
> 15 April 2021
- 🚀RELEASE v0.15.0 [`5c02028`](https://git.odit.services/lfk/frontend/commit/5c02028841c68d9a284bf6971eec2b6bc2fdf1f3)
- Merge pull request 'Mark donations as payed feature/133-donation_payments' (#135) from feature/133-donation_payments into dev [`c561b53`](https://git.odit.services/lfk/frontend/commit/c561b536705a68215d9c0a6b320587d1647bf57f)
- Sorted translations [`c7a858e`](https://git.odit.services/lfk/frontend/commit/c7a858eed7962294bc9df3c92ce2e46b0a354796)
- Added total donation amount to donor overview [`e42ea94`](https://git.odit.services/lfk/frontend/commit/e42ea943b7821d433fe21599edbd9f76c3128ef2)
- Added Add Payment button to donor overview [`6e6e8b2`](https://git.odit.services/lfk/frontend/commit/6e6e8b26171f16542c101520800b4b6ea7c023d3)
- You can now open a modal to add a payment to a donation from the donation overview [`a943aaf`](https://git.odit.services/lfk/frontend/commit/a943aaf5fce8f113dd967d3842e2b0d7d50604e9)
- You can now add payments from the donation overview [`1dbab03`](https://git.odit.services/lfk/frontend/commit/1dbab03fe73b5e0fc011f9b0af7199bd71bc79c5)
- Added payment updating via detail [`bdcf5d3`](https://git.odit.services/lfk/frontend/commit/bdcf5d3fc08d250377226a253642d79b2e82d624)
- Added **all** missing toast translations [`de5aa92`](https://git.odit.services/lfk/frontend/commit/de5aa9237d261b5d47a8def35afa7f8e0089aea6)
- You can now mark fixed donations as already paid on creation [`3d3a10a`](https://git.odit.services/lfk/frontend/commit/3d3a10aafb16d371be9471eb5172f9251fb2583f)
- Added translations 🌎 [`d015f97`](https://git.odit.services/lfk/frontend/commit/d015f9739570c44a7a2fe6ba248c9a45c3047c62)
- Changed top info style for donation overview [`4c2c24a`](https://git.odit.services/lfk/frontend/commit/4c2c24af2ca5c2874a583b0fd93bee147a17f449)
- Added paid donation amount and status to donation detail [`5645eea`](https://git.odit.services/lfk/frontend/commit/5645eeaafaa4254edf1a81bc597ce0c7a9b03ff0)
- Added total donation amount to donation overview [`961477d`](https://git.odit.services/lfk/frontend/commit/961477d5224bc44b552d2fc2851d8514116f4e20)
- Fixed chante recognition bug for fixed donation [`0f0aae7`](https://git.odit.services/lfk/frontend/commit/0f0aae7ba4cf5dfab15d56ce48edbdbc7cb7e403)
- Added total donation amount to donor detail [`a5f7101`](https://git.odit.services/lfk/frontend/commit/a5f71015a6557d664e9d3f505613352792fc38cb)
- Added msiisng runner id conversion [`5761815`](https://git.odit.services/lfk/frontend/commit/57618156b49b2b0f0274f2126fef36a017d90022)
- AddDonationModal - vertical alignment for paid status [`18acac8`](https://git.odit.services/lfk/frontend/commit/18acac83bc6532e14d36b3399d867e026d0c88ac)
- Added missing updated comparison [`04a3038`](https://git.odit.services/lfk/frontend/commit/04a3038369f2717c43459318b7b5754ebbaa9e45)
- DonationsOverview contrast on action [`d7d4447`](https://git.odit.services/lfk/frontend/commit/d7d44470bb08ac06594bc400608c17eeacb0434b)
- Fixed typo [`4c0886a`](https://git.odit.services/lfk/frontend/commit/4c0886a5d9b91439967bc8f66b09a57177f967d0)
- Fixed styling [`865254d`](https://git.odit.services/lfk/frontend/commit/865254d646b5f7de15720551c67ae649601cbcd2)
- Changed top info style for donation detail [`000fc97`](https://git.odit.services/lfk/frontend/commit/000fc97beb14427f69d421ff2c96975dbbdc7a3a)
#### [0.14.0](https://git.odit.services/lfk/frontend/compare/0.13.1...0.14.0)
> 14 April 2021
- Merge pull request 'added donor receipt list download to DonorsOverview' (#134) from feature/132-export-donors-receipt-list into dev [`#132`](https://git.odit.services/lfk/frontend/issues/132)
- Sorted translations 🌎 [`c6c9751`](https://git.odit.services/lfk/frontend/commit/c6c97516b3981ef580d620c0c8a6fcc42f26facd)
- Fixed typos in translations [`03676b2`](https://git.odit.services/lfk/frontend/commit/03676b2894892c3559118b93e969c063b53b081e)
- added donor receipt list download to DonorsOverview [`d241ca5`](https://git.odit.services/lfk/frontend/commit/d241ca569838abbe9581fbd319f7f3b563cb7dcc)
- 🚀RELEASE v0.14.0 [`9c5fc6b`](https://git.odit.services/lfk/frontend/commit/9c5fc6b61c0bb2a6d831d4a23ef8679c6e68c6a1)
- ⏫ general version bump [`18f151c`](https://git.odit.services/lfk/frontend/commit/18f151c1fb878a74c3d1a2c2a2debf7913739417)
- new license file version [CI SKIP] [`302caf0`](https://git.odit.services/lfk/frontend/commit/302caf015f88f77e2b2ae2b67680e79f987ad81e)
- Switched to selfhosted images [`112eb29`](https://git.odit.services/lfk/frontend/commit/112eb29f932cd936f1d6c2308dcaeaf8cb642490)
- ⏫ bump @odit/lfk-client-js@0.11.0 [`9ca57fa`](https://git.odit.services/lfk/frontend/commit/9ca57fac2eeabbf25142a507fb9c0fa3c90b4e74)
- replace donationAmount with paidDonationAmount [`e90e56d`](https://git.odit.services/lfk/frontend/commit/e90e56d8b26aef23aba2bbb0c3942ba4d7feb224)
#### [0.13.1](https://git.odit.services/lfk/frontend/compare/0.13.0...0.13.1)
> 11 April 2021
- 🚀RELEASE v0.13.1 [`b512cf8`](https://git.odit.services/lfk/frontend/commit/b512cf86674f1c60b5ac790985ededdfd6554185)
- For await fix [`a24d292`](https://git.odit.services/lfk/frontend/commit/a24d2923c6e6da90d610c05183d29d47eaf2ed30)
#### [0.13.0](https://git.odit.services/lfk/frontend/compare/0.12.5...0.13.0)
> 11 April 2021
- 🚀RELEASE v0.13.0 [`467808a`](https://git.odit.services/lfk/frontend/commit/467808abefe127dac66a2837fcce3197dddb140f)
- Merge pull request 'Better org pdf generation feature/130-org_doc_splitting' (#131) from feature/130-org_doc_splitting into dev [`861f1f2`](https://git.odit.services/lfk/frontend/commit/861f1f221653283e7586aa2c67b205337fd44398)
- Org card generation now runs in sequence [`fef14b6`](https://git.odit.services/lfk/frontend/commit/fef14b6e4fb47ad92da61de91fedce96aea26b2c)
- Org certificate generation now runs in sequence [`509b22b`](https://git.odit.services/lfk/frontend/commit/509b22bea0dd3e4446e6ecc37d27644e9bf2ad50)
- Org contract generation now runs in sequence [`01d2a7e`](https://git.odit.services/lfk/frontend/commit/01d2a7e6aa709b3f2d71575f705fc962e97e2742)
- Emergency document server url change [`5476808`](https://git.odit.services/lfk/frontend/commit/5476808683a919bc34dbaea1f1ed276d49750096)
- Fixed const -> let [`7447b2f`](https://git.odit.services/lfk/frontend/commit/7447b2f4c134a585905db6733093eab13e6f7c47)
- Hotfix: Org * generation🐞 [`ac586fe`](https://git.odit.services/lfk/frontend/commit/ac586fec5abd324d590ba99cdfe8ddddefbf95e6)
#### [0.12.5](https://git.odit.services/lfk/frontend/compare/0.12.4...0.12.5)
> 8 April 2021
- 🚀RELEASE v0.12.5 [`331d737`](https://git.odit.services/lfk/frontend/commit/331d737796c82454b1c19fa1840ccc20e36d2626)
- Merge pull request 'Added runner team's parentorg name to runenr overciew' (#129) from feature/128-runner_orgs into dev [`ef81b8a`](https://git.odit.services/lfk/frontend/commit/ef81b8adf9bef685a55936d7544bf645c0d6ecbe)
- Switched to html entity [`8a7d635`](https://git.odit.services/lfk/frontend/commit/8a7d635cef2d465e70c84e1f7a7b90b98a8dbab1)
- Added runner team's parentorg name to runenr overciew [`4c259c1`](https://git.odit.services/lfk/frontend/commit/4c259c1eef2b0166ce6a8493d0c9e9d5ede11146)
#### [0.12.4](https://git.odit.services/lfk/frontend/compare/0.12.3...0.12.4)
> 8 April 2021
- 🚀RELEASE v0.12.4 [`5b4ede5`](https://git.odit.services/lfk/frontend/commit/5b4ede5e2f6a26b475a7a4b430a4146d21fb9671)
- 🚑 [HOTFIX] - drop "svelte-infinite-loading" [`d0ab3dd`](https://git.odit.services/lfk/frontend/commit/d0ab3dda78bbad2cea18a2491056530897d56607)
#### [0.12.3](https://git.odit.services/lfk/frontend/compare/0.12.2...0.12.3)
> 8 April 2021
- Merge pull request 'fix' (#126) from bugfix/125-mobile into dev [`#125`](https://git.odit.services/lfk/frontend/issues/125)
- almost fixed... [`495a6b2`](https://git.odit.services/lfk/frontend/commit/495a6b22bd8036593f390bdb862d325524cefbcc)
- 🐞 bugfix for svelte x tailwind class names [`b6b07cf`](https://git.odit.services/lfk/frontend/commit/b6b07cf30cc6533bd5dbfec1f813c16fde85634d)
- fix [`0acaffb`](https://git.odit.services/lfk/frontend/commit/0acaffbdfa359e52654a5afe2788aa59fe6f9036)
- 🚀RELEASE v0.12.3 [`d9cf51b`](https://git.odit.services/lfk/frontend/commit/d9cf51b4bbc2136594a03c5d0eeb8cb3f3440b2a)
- custom css fix for collapsed_navigation [`ffbc243`](https://git.odit.services/lfk/frontend/commit/ffbc243194c7faeb4fe61c12711a1c441c3994ef)
- new license file version [CI SKIP] [`aa17f24`](https://git.odit.services/lfk/frontend/commit/aa17f242209f7e7cecff774ace7a35b581adec1f)
#### [0.12.2](https://git.odit.services/lfk/frontend/compare/0.12.1...0.12.2)
> 7 April 2021
- 🚀RELEASE v0.12.2 [`6043bc4`](https://git.odit.services/lfk/frontend/commit/6043bc45174d51ab110b0ed10a8679d96127ab87)
- Merge pull request 'feature/110-virtual_list' (#124) from feature/110-virtual_list into dev [`e6ed066`](https://git.odit.services/lfk/frontend/commit/e6ed066e3ffabba6519f94d801d21a27819d0492)
- wip on virtuallist [`6304116`](https://git.odit.services/lfk/frontend/commit/6304116edb7f5e3c7b67c15e0b1740d34c513155)
- fixed height table [`4cad86c`](https://git.odit.services/lfk/frontend/commit/4cad86cf852468428d77103d052c6974b17c34c3)
- pre-merge fixes [`37970d2`](https://git.odit.services/lfk/frontend/commit/37970d2be6b6502701914e41e5bfe2c418438480)
- updated virtual scroll list [`1376788`](https://git.odit.services/lfk/frontend/commit/1376788016e767f006661f8c9e6747781f2dce55)
#### [0.12.1](https://git.odit.services/lfk/frontend/compare/0.12.0...0.12.1)
> 6 April 2021
- 🚀RELEASE v0.12.1 [`834ff8f`](https://git.odit.services/lfk/frontend/commit/834ff8fa63178f36dcacf931c128ba67a3e7bd1b)
- Merge pull request 'ImportRunnerModal Cancel Button feature/122-import_cancel' (#123) from feature/112-import_cancel into dev [`1f428a5`](https://git.odit.services/lfk/frontend/commit/1f428a535e3ae619cbf8db51d04255aac8dd8614)
- Added cancel button for the first stage of runner import [`0c40966`](https://git.odit.services/lfk/frontend/commit/0c409669700d3a8096cc04716154b0fdca458fe5)
- Escape now triggers foll modal close (including reset) instead of just hiding th modal [`9da071f`](https://git.odit.services/lfk/frontend/commit/9da071fe9ba067160334682bf00163e3630fe919)
#### [0.12.0](https://git.odit.services/lfk/frontend/compare/0.11.0...0.12.0)
> 5 April 2021
- Merge pull request 'feature/108_vite_migration' (#118) from feature/108_vite_migration into dev [`#108`](https://git.odit.services/lfk/frontend/issues/108)
- 🚀RELEASE v0.12.0 [`892a04f`](https://git.odit.services/lfk/frontend/commit/892a04f28930481715eb486b1ef4efeb98a6e999)
- Fixed package version [`27cc972`](https://git.odit.services/lfk/frontend/commit/27cc9727f1d02d186c3ccadb06e5b4b1b1d6202d)
- Merge pull request 'Implmented certificate generation feature/119-Certificate_generation' (#120) from feature/119-Certificate_generation into dev [`f0738d4`](https://git.odit.services/lfk/frontend/commit/f0738d451b02e4a298b5f9cb8ab0be16aed10a38)
- The PFS Prefixes now get translated via i18n [`bfacfec`](https://git.odit.services/lfk/frontend/commit/bfacfec76511cae3015f52698fdcbd80a7a15981)
- Sorted translations 🌍 [`9e6a8da`](https://git.odit.services/lfk/frontend/commit/9e6a8daf2c394cf17da532382ec7d049a0f89577)
- added missing/ wrong translations + formatting! [`7c86a5e`](https://git.odit.services/lfk/frontend/commit/7c86a5eeb370a43451d180a09a501066b023b9a0)
- Added i18n [`17f6f4e`](https://git.odit.services/lfk/frontend/commit/17f6f4e616bf57424ee12ad53b939429c02a0171)
- Added basic certificate generation component [`af63ce6`](https://git.odit.services/lfk/frontend/commit/af63ce67ae7d8f8a70706c3bd6755197908996ff)
- basic ViteJS migration [`ae79e9f`](https://git.odit.services/lfk/frontend/commit/ae79e9fea1963e977ef468e8e56f87d68916fadd)
- Implemented generation for orgs [`2e3ac15`](https://git.odit.services/lfk/frontend/commit/2e3ac154be0bf0776cd00f7d510f41ec676ae690)
- Implemented generation for teams [`2472640`](https://git.odit.services/lfk/frontend/commit/2472640755e3e41259a44127a875d00517a25842)
- updated default entrypoint [`95c8fde`](https://git.odit.services/lfk/frontend/commit/95c8fde72fca5cd5a644d51a33dc88e0b59fce92)
- ⏫📍 version bump + pin [`b065b4f`](https://git.odit.services/lfk/frontend/commit/b065b4ff218d07952fa45989e6e2ee7df13e07c1)
- 🧹 reorder + fix package [`12433f7`](https://git.odit.services/lfk/frontend/commit/12433f7c236906fe2b29848a0acaa6be1724da56)
- 🔨 re-added VS Code devcontainer config [`9318709`](https://git.odit.services/lfk/frontend/commit/93187099d32c506329b1437642aae985f2850689)
- 🐳 new Dockerfiles [`0f32968`](https://git.odit.services/lfk/frontend/commit/0f32968fae8b55a13d387918211983d0e61f85ab)
- 📃 added readme [`aa24b1d`](https://git.odit.services/lfk/frontend/commit/aa24b1dce5d6d73c8f42fc57f81b692350bf9665)
- Copy-paste fix [`f47d5e3`](https://git.odit.services/lfk/frontend/commit/f47d5e347d97ee127fa0380620138a9672665cd5)
- 🔨🔥 alpine based devcontainer with working yarn PnP [`777304f`](https://git.odit.services/lfk/frontend/commit/777304f2593df36f4e89d2ba7680add183ff062f)
- Copy-paste fix [`7488a8b`](https://git.odit.services/lfk/frontend/commit/7488a8b597a148c309e1b4499d277fed7f3bf9f4)
- You can now generate certificates from the runner overview [`bb9b779`](https://git.odit.services/lfk/frontend/commit/bb9b779cee909ab85ef52f13be0a917f1c0a9e62)
- Cleaned up generation strings and added the schem for single runner generations for cards [`9c867e1`](https://git.odit.services/lfk/frontend/commit/9c867e106edd68784e6d19743519c1952a0f0bc7)
- Changed the basic nameing generation for runenr certificate files [`d65d379`](https://git.odit.services/lfk/frontend/commit/d65d3793de869bcd6733a1bbdac378d0bc1128b3)
- ⏫ version bumps [`d7fecfb`](https://git.odit.services/lfk/frontend/commit/d7fecfbd0bc01f1cd44dea3c3837e0cc44afab12)
- Cleaned up generation strings and added the schem for single runner generations for sponsoring contracts [`22b09d1`](https://git.odit.services/lfk/frontend/commit/22b09d16d0acc2883e3448dad95ed0f4ea7c6aeb)
- Certificate generation from org overview [`3177c6e`](https://git.odit.services/lfk/frontend/commit/3177c6eaa31636ed4546f4797775a0f0a930f5d1)
- certificate pdf names now include their locale [`304f28a`](https://git.odit.services/lfk/frontend/commit/304f28a3c10bc4745aa5b7c80d7ba0e651540706)
- Runnercard pdfs now include their locale [`3638d87`](https://git.odit.services/lfk/frontend/commit/3638d87bd2ff83618eefda5af18ba19e38e3c2eb)
- 🐞 fix await for esNext [`a922776`](https://git.odit.services/lfk/frontend/commit/a9227768de29305b51d10c8a6e4fa1d39b7d998f)
- Certificate generation from team overview [`18ec100`](https://git.odit.services/lfk/frontend/commit/18ec100c33a1fbab526187e769dbae54d9db0867)
- Added certificate generation from runner overview and detail [`7b685d6`](https://git.odit.services/lfk/frontend/commit/7b685d6cad97d2f7f48c4b19bfc128e1355b70c4)
- package cleanup [`6be2ee6`](https://git.odit.services/lfk/frontend/commit/6be2ee626addaf5113b4b4821bd99a276bf4f329)
- sponsoring pdf names now include their locale [`0bae5bf`](https://git.odit.services/lfk/frontend/commit/0bae5bf32b8687057dca50cde21022ea8c3abee8)
- ✨ update licenses.json [`e99e9e0`](https://git.odit.services/lfk/frontend/commit/e99e9e07089520d5a48021e10d2af7739656641a)
- added windicss settings for VSCode [`008027d`](https://git.odit.services/lfk/frontend/commit/008027db0e2736a9bb9defd67178ab3fe580de04)
- Certificate generation from team detail [`acd2f05`](https://git.odit.services/lfk/frontend/commit/acd2f0519d62e55dad8e9c3c41e77b6967212502)
- ⚡💾 prevent env.js from being cached [`c5d1553`](https://git.odit.services/lfk/frontend/commit/c5d155396a92dfee6d592fb24a936ab521215f6d)
- for await fix - ViteJS [`aec5e34`](https://git.odit.services/lfk/frontend/commit/aec5e3473e687415fbfd69c550d9b012e1b1be43)
- Certificate generation from org detail [`e6ffc37`](https://git.odit.services/lfk/frontend/commit/e6ffc371e1ca2d4451e7dd4a3ca3c05564edb5fb)
- 🧹 drop unused dependencies [`ce50fa2`](https://git.odit.services/lfk/frontend/commit/ce50fa2a62f8ff98e8be9c66432caeebb3952019)
- 🐞 fix NGINX config [`5352410`](https://git.odit.services/lfk/frontend/commit/5352410d0c76fd14575d7beafc6a83f028062efe)
- Fixed wrong permissiong getting checked [`b97a928`](https://git.odit.services/lfk/frontend/commit/b97a92860d71eb0384170e245a67fa3ea3fd8e85)
- new license file version [CI SKIP] [`5cc4871`](https://git.odit.services/lfk/frontend/commit/5cc4871ec4be9f0af07738f6e3d44bdbe31cd25a)
- ⏫ bump @odit/lfk-client-js@0.10.1 [`8b74d6d`](https://git.odit.services/lfk/frontend/commit/8b74d6d759c8481f012c201e2ea0d12b29ddef90)
- 🔨 dev container open ⚡ [`ceb2146`](https://git.odit.services/lfk/frontend/commit/ceb2146c1b08bbe9250e4db7846e06bd89526c21)
- ⏫ version bump: vite-plugin-windicss@0.12.2 [`8d006d8`](https://git.odit.services/lfk/frontend/commit/8d006d8c74d71c43a9031d58f5a8c7fc55ed95fc)
- 🚚 move @svitejs/vite-plugin-svelte to @sveltejs/vite-plugin-svelte [`44b53da`](https://git.odit.services/lfk/frontend/commit/44b53da34516b00671b3e5060ba831e409ac3dd5)
- ⏫ upgrade vite-plugin-windicss@0.12.1 [`ab45fc1`](https://git.odit.services/lfk/frontend/commit/ab45fc144eaf14f63d86ee53c1db4eefd88f9c7f)
- 🐞 fix main.js linking [`467404b`](https://git.odit.services/lfk/frontend/commit/467404bfc87f3c08c5e227f194d71eea7cc48921)
- 🐞 fix vite config for production system [`10a011d`](https://git.odit.services/lfk/frontend/commit/10a011d8426e475105ff5d2d5cf4adca2ef7625c)
- fix dev script [`eb3ede9`](https://git.odit.services/lfk/frontend/commit/eb3ede9593e2e527df3e3a2f81c8e179bb555f51)
- ⏫ bump vite to 2.1.3 [`0cd3e93`](https://git.odit.services/lfk/frontend/commit/0cd3e937d852eeabe43eb6298bfabe20834240b2)
- Removed useless console.log [`d23dbaa`](https://git.odit.services/lfk/frontend/commit/d23dbaaf695a60fe5ebbc9945646a16b5fc45a16)
- Removed useless console log [`48cfc15`](https://git.odit.services/lfk/frontend/commit/48cfc15cfb09096db1bd5ddbe9138b1a604d581f)
#### [0.11.0](https://git.odit.services/lfk/frontend/compare/0.10.0...0.11.0) #### [0.11.0](https://git.odit.services/lfk/frontend/compare/0.10.0...0.11.0)
- Merge pull request 'Generate and print bulk blank cards feature/116-download_blanc_cards' (#117) from feature/116-download_blanc_cards into dev [`25d8b86`](https://git.odit.services/lfk/frontend/commit/25d8b86efd89c442d1bf308a8743134820acfd1f) > 30 March 2021
- Added button (including translations [`0614c76`](https://git.odit.services/lfk/frontend/commit/0614c76e924b18b512bab59933a26fec07cf483d) - Added button (including translations [`0614c76`](https://git.odit.services/lfk/frontend/commit/0614c76e924b18b512bab59933a26fec07cf483d)
- Added button (including translations [`97e338f`](https://git.odit.services/lfk/frontend/commit/97e338f9d4f388596d550990457254c7fa1a3492) - Added button (including translations [`97e338f`](https://git.odit.services/lfk/frontend/commit/97e338f9d4f388596d550990457254c7fa1a3492)
- Sorted translations [`89bb9c2`](https://git.odit.services/lfk/frontend/commit/89bb9c215e356e0940678f5cabd9e38bc203040e) - Sorted translations [`89bb9c2`](https://git.odit.services/lfk/frontend/commit/89bb9c215e356e0940678f5cabd9e38bc203040e)
- Added function for generating cards with pdf [`c8d6390`](https://git.odit.services/lfk/frontend/commit/c8d639024a5f2f72d6e30d2ce990b08bd71a5471) - Added function for generating cards with pdf [`c8d6390`](https://git.odit.services/lfk/frontend/commit/c8d639024a5f2f72d6e30d2ce990b08bd71a5471)
- 🚀RELEASE v0.11.0 [`f8ccf4f`](https://git.odit.services/lfk/frontend/commit/f8ccf4f5d8f68ecee31430029889b8ab1ecec682)
- Fixed button styling [`08cb079`](https://git.odit.services/lfk/frontend/commit/08cb079e9798392e26515d559af2637e74deea97) - Fixed button styling [`08cb079`](https://git.odit.services/lfk/frontend/commit/08cb079e9798392e26515d559af2637e74deea97)
- Now returning cards on creation with pdf [`1d999d4`](https://git.odit.services/lfk/frontend/commit/1d999d4910acb5efa21b3f9922cdb359babff404) - Now returning cards on creation with pdf [`1d999d4`](https://git.odit.services/lfk/frontend/commit/1d999d4910acb5efa21b3f9922cdb359babff404)
- new license file version [CI SKIP] [`8f8b998`](https://git.odit.services/lfk/frontend/commit/8f8b9988ad94ee9f3729a3fe6fdb4c558828d892)
- Merge pull request 'Generate and print bulk blank cards feature/116-download_blanc_cards' (#117) from feature/116-download_blanc_cards into dev [`25d8b86`](https://git.odit.services/lfk/frontend/commit/25d8b86efd89c442d1bf308a8743134820acfd1f)
- Added comment [`636f018`](https://git.odit.services/lfk/frontend/commit/636f018daa33b99468a257bfc33477e1e644d081) - Added comment [`636f018`](https://git.odit.services/lfk/frontend/commit/636f018daa33b99468a257bfc33477e1e644d081)
- Bumped lfk client js version [`2d18686`](https://git.odit.services/lfk/frontend/commit/2d18686ce782a434ca7bd34c07c36a35b9497273) - Bumped lfk client js version [`2d18686`](https://git.odit.services/lfk/frontend/commit/2d18686ce782a434ca7bd34c07c36a35b9497273)
- Bumped lfk-client-js [`7dfaa75`](https://git.odit.services/lfk/frontend/commit/7dfaa7579a22b13194fcdd1c02b4437958261472) - Bumped lfk-client-js [`7dfaa75`](https://git.odit.services/lfk/frontend/commit/7dfaa7579a22b13194fcdd1c02b4437958261472)

View File

@@ -1,14 +1,12 @@
FROM node:15.5.1-alpine3.12 FROM registry.odit.services/hub/library/node:19.5.0-alpine3.16 as build
WORKDIR /app WORKDIR /app
COPY package.json ./ COPY package.json ./
RUN yarn RUN npx pnpm i
COPY package.json *.config.js index.html ./ COPY package.json *.config.js postcss.config.cjs tailwind.config.js vite.config.js index.html ./
COPY src ./src COPY src ./src
COPY public ./public COPY public ./public
RUN yarn build RUN yarn build
# final image # final image
FROM alpine FROM registry.odit.services/library/nginx-brotli:3.15 as final
COPY --from=0 /app/dist /app COPY --from=build /app/dist /usr/share/nginx/html
FROM fholzer/nginx-brotli:v1.19.1
COPY --from=1 /app /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf COPY ./nginx.conf /etc/nginx/nginx.conf

View File

@@ -13,7 +13,7 @@
</head> </head>
<body> <body>
<span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.8.4-RELEASE_INFO</span> <span style="display: none;visibility: hidden;" id="buildinfo">RELEASE_INFO-0.16.1-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

@@ -6,6 +6,11 @@ http {
server { server {
error_page 404 /index.html; error_page 404 /index.html;
root /usr/share/nginx/html; root /usr/share/nginx/html;
location /assets {
expires 1y;
log_not_found off;
access_log off;
}
location = /index.html { location = /index.html {
add_header Cache-Control 'no-store'; add_header Cache-Control 'no-store';
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@odit/lfk-frontend", "name": "@odit/lfk-frontend",
"version": "0.8.4", "version": "0.16.1",
"scripts": { "scripts": {
"i18n-order": "node order.js", "i18n-order": "node order.js",
"dev": "vite", "dev": "vite",
@@ -10,30 +10,30 @@
}, },
"license": "CC-BY-NC-SA-4.0", "license": "CC-BY-NC-SA-4.0",
"devDependencies": { "devDependencies": {
"check-password-strength": "2.0.2", "@odit/lfk-client-js": "0.13.1",
"@odit/lfk-client-js": "0.10.1",
"@odit/license-exporter": "0.0.11", "@odit/license-exporter": "0.0.11",
"@sveltejs/vite-plugin-svelte": "1.0.0-next.5", "@sveltejs/vite-plugin-svelte": "1.0.0-next.6",
"@types/html-minifier": "4.0.0", "@types/html-minifier": "4.0.0",
"auto-changelog": "2.2.1", "auto-changelog": "2.2.1",
"autoprefixer": "10.2.5", "autoprefixer": "10.2.5",
"check-password-strength": "2.0.2",
"csvtojson": "2.0.10", "csvtojson": "2.0.10",
"gridjs": "3.4.0", "gridjs": "3.4.0",
"html-minifier": "4.0.0", "html-minifier": "4.0.0",
"localforage": "1.9.0", "localforage": "1.9.0",
"marked": "2.0.1", "marked": "2.0.3",
"release-it": "14.5.1", "postcss": "8.2.10",
"release-it": "14.6.1",
"svelte": "3.37.0", "svelte": "3.37.0",
"svelte-focus-trap": "1.2.0", "svelte-focus-trap": "1.2.0",
"svelte-i18n": "3.3.9", "svelte-i18n": "3.3.9",
"svelte-preprocess": "4.7.0", "svelte-preprocess": "4.7.0",
"svelte-select": "3.17.0", "svelte-select": "3.17.0",
"tailwindcss": "2.0.4", "tailwindcss": "3.2.4",
"tinro": "0.6.1", "tinro": "0.6.1",
"toastify-js": "1.10.0", "toastify-js": "1.10.0",
"validator": "13.5.2", "validator": "13.5.2",
"vite": "2.1.5", "vite": "2.1.5",
"vite-plugin-windicss": "0.12.2",
"xlsx": "0.16.9" "xlsx": "0.16.9"
}, },
"release-it": { "release-it": {

6
postcss.config.cjs Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
};

View File

@@ -1,5 +1,6 @@
const config = { const config = {
baseurl: 'http://localhost:4010', baseurl: 'http://localhost:4010',
baseurl_documentserver: 'http://localhost:4010/documents',
documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe', documentserver_key: 'NqZSYTy5AFQ7MppbLW5moqpTk7u7YrNUHKYhKYuThnnya2WpCOIU694hIZT1FzYe',
// optional // optional
default_username: 'demo', default_username: 'demo',

File diff suppressed because one or more lines are too long

View File

@@ -72,6 +72,8 @@
import Scans from "./components/scans/Scans.svelte"; import Scans from "./components/scans/Scans.svelte";
import ScanDetail from "./components/scans/ScanDetail.svelte"; import ScanDetail from "./components/scans/ScanDetail.svelte";
import Cards from "./components/cards/Cards.svelte"; import Cards from "./components/cards/Cards.svelte";
import StatsClients from "./components/statsclients/StatsClients.svelte";
import StatsClientDetail from "./components/statsclients/StatsClientDetail.svelte";
store.init(); store.init();
</script> </script>
@@ -206,6 +208,14 @@
<ScanStationDetail {params} /> <ScanStationDetail {params} />
</Route> </Route>
</Route> </Route>
<Route path="/statsclients/*">
<Route path="/">
<StatsClients />
</Route>
<Route path="/:clientid" let:params>
<StatsClientDetail {params} />
</Route>
</Route>
<Route path="/about"> <Route path="/about">
<About /> <About />
</Route> </Route>

View File

@@ -76,7 +76,7 @@
// last login was not processed yet // last login was not processed yet
} else { } else {
Toastify({ Toastify({
text: "chill...", text: $_('please-wait-a-moment-your-login-is-still-being-processed'),
duration: 1500, duration: 1500,
backgroundColor: backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",

View File

@@ -0,0 +1,6 @@
<!--
Temporary tailwind import fixes for classes that wouldn't be directly used otherwise.
Or as others may call it: Real big bullshit time.
Issue: https://git.odit.services/lfk/frontend/issues/136
-->
<div class="opacity-50"></div>

View File

@@ -77,7 +77,7 @@
duration: -1, duration: -1,
}).showToast(); }).showToast();
fetch( fetch(
`${config.baseurl}/documents/cards?&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {

View File

@@ -1,5 +1,5 @@
<script> <script>
import { getLocaleFromNavigator, json, _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { RunnerCardService } from "@odit/lfk-client-js"; import { RunnerCardService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
@@ -11,11 +11,21 @@
export let editable = {}; export let editable = {};
export let original_data = {}; export let original_data = {};
export let current_cards = []; export let current_cards = [];
$: filtered_cards = current_cards.filter(function (c) {
if (
c.code.toLowerCase().includes(searchvalue_lowercase) ||
c.runner?.firstname.toLowerCase().includes(searchvalue_lowercase) ||
c.runner?.middlename.toLowerCase().includes(searchvalue_lowercase) ||
c.runner?.lastname.toLowerCase().includes(searchvalue_lowercase) ||
should_display_based_on_id(c.id)
) {
return true;
}
});
$: searchvalue = ""; $: searchvalue = "";
$: searchvalue_lowercase = searchvalue.toLowerCase();
$: active_deletes = []; $: active_deletes = [];
$: cards_show = current_cards.some( $: cards_show = current_cards.some((r) => r.is_selected === true);
(r) => r.is_selected === true
);
$: generate_cards = current_cards.filter((r) => r.is_selected === true); $: generate_cards = current_cards.filter((r) => r.is_selected === true);
const cards_promise = RunnerCardService.runnerCardControllerGetAll().then( const cards_promise = RunnerCardService.runnerCardControllerGetAll().then(
(val) => { (val) => {
@@ -46,8 +56,38 @@
original_data = Object.assign(original_data, card); original_data = Object.assign(original_data, card);
edit_modal_open = true; edit_modal_open = true;
} }
// -----------------
let scrollTop = 0;
$: rendered = filtered_cards;
let innerHeight = 0;
let ele;
$: updateSlice(scrollTop);
$: innerHeight = `${filtered_cards.length * 25}px`;
$: if (ele) updateSlice();
function updateSlice() {
const height = ele ? parseInt(ele.clientHeight) : 100;
const init = scrollTop / 25;
const end = Math.ceil((scrollTop + height) / 25);
rendered = filtered_cards.slice(init, end + 15);
}
function updateScroll($event) {
scrollTop = $event.target.scrollTop;
}
</script> </script>
<style>
table tbody {
display: block;
overflow-y: scroll;
}
table thead, table tbody tr {
display: table;
width: 100%;
table-layout: fixed;
}
</style>
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:UPDATE')} {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:UPDATE')}
<CardDetailModal <CardDetailModal
bind:current_cards bind:current_cards
@@ -121,107 +161,111 @@
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody class="divide-y divide-gray-200"> <tbody class="divide-y divide-gray-200 virtual-wrapper"
{#each current_cards as card} on:scroll={updateScroll}
{#if card.code style="height: 70vh; width:100%"
.toLowerCase() bind:this={ele}
.includes( >
searchvalue.toLowerCase() {#each filtered_cards as card, index}
) || card.runner?.firstname {#if card.code
.toLowerCase() .toLowerCase()
.includes( .includes(
searchvalue.toLowerCase() searchvalue.toLowerCase()
) || card.runner?.middlename ) || card.runner?.firstname
.toLowerCase() .toLowerCase()
.includes( .includes(
searchvalue.toLowerCase() searchvalue.toLowerCase()
) || card.runner?.lastname ) || card.runner?.middlename
.toLowerCase() .toLowerCase()
.includes( .includes(
searchvalue.toLowerCase() searchvalue.toLowerCase()
) || should_display_based_on_id(card.id)} ) || card.runner?.lastname
<tr data-rowid="card_{card.id}"> .toLowerCase()
<td class="px-6 py-4 whitespace-nowrap"> .includes(
<input searchvalue.toLowerCase()
bind:checked={card.is_selected} ) || should_display_based_on_id(card.id)}
type="checkbox" <tr data-rowid="card_{card.id}">
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" /> <td class="px-6 py-4 whitespace-nowrap">
</td> <input
<td class="px-6 py-4 whitespace-nowrap"> bind:checked={card.is_selected}
<div class="flex items-center">{card.code}</div> type="checkbox"
</td> class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
<td class="px-6 py-4 whitespace-nowrap"> </td>
<div class="flex items-center"> <td class="px-6 py-4 whitespace-nowrap">
{#if card.runner} <div class="flex items-center">{card.code}</div>
<a </td>
href="../runners/{card.runner.id}" <td class="px-6 py-4 whitespace-nowrap">
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{card.runner.firstname} <div class="flex items-center">
{card.runner.middlename || ''} {#if card.runner}
{card.runner.lastname}</a> <a
{:else}{$_('non-blanko')}{/if} href="../runners/{card.runner.id}"
</div> class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{card.runner.firstname}
</td> {card.runner.middlename || ''}
<td class="px-6 py-4 whitespace-nowrap"> {card.runner.lastname}</a>
<div class="flex items-center"> {:else}{$_('non-blanko')}{/if}
{#if card.enabled} </div>
<span </td>
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('enabled')}</span> <td class="px-6 py-4 whitespace-nowrap">
{:else} <div class="flex items-center">
<span {#if card.enabled}
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('disabled')}</span> <span
{/if} class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">{$_('enabled')}</span>
</div> {:else}
</td> <span
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">{$_('disabled')}</span>
{/if}
</div>
</td>
{#if active_deletes[card.id] === true} {#if active_deletes[card.id] === true}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button <button
on:click={() => { on:click={() => {
active_deletes[card.id] = false; active_deletes[card.id] = false;
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button> class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button <button
on:click={() => { on:click={() => {
RunnerCardService.runnerCardControllerRemove(card.id, false).then( RunnerCardService.runnerCardControllerRemove(card.id, false).then(
(resp) => { (resp) => {
current_cards = current_cards.filter( current_cards = current_cards.filter(
(obj) => obj.id !== card.id (obj) => obj.id !== card.id
); );
Toastify({ Toastify({
text: $_('card-deleted'), text: $_('card-deleted'),
duration: 500, duration: 500,
backgroundColor: backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)', 'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast(); }).showToast();
} }
); );
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button> class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
</td> </td>
{:else} {:else}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button <button
on:click={() => { on:click={() => {
open_edit_modal(card); open_edit_modal(card);
}} }}
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</button> class="text-indigo-600 hover:text-indigo-900">{$_('details')}</button>
{#if store.state.jwtinfo.userdetails.permissions.includes('CARD:DELETE')} {#if store.state.jwtinfo.userdetails.permissions.includes('CARD:DELETE')}
<button <button
on:click={() => { on:click={() => {
active_deletes[card.id] = true; active_deletes[card.id] = true;
}} }}
tabindex="0" tabindex="0"
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button> class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button>
{/if} {/if}
</td> </td>
{/if} {/if}
</tr> </tr>
{/if} {/if}
{/each} {/each}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@@ -86,7 +86,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: "Contact is being added...", text: $_('contact-is-being-added'),
duration: -1, duration: -1,
}).showToast(); }).showToast();
let address = {}; let address = {};
@@ -123,7 +123,7 @@
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: "Contact added", text: $_('contact-added'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -12,11 +12,21 @@
} }
</script> </script>
<style>
.collapsed_navigation {
transform: translateX(-100%);
}
@media (min-width: 768px) {
.collapsed_navigation {
transform: translateX(0px);
}
}
</style>
<section class="min-h-screen bg-gray-50"> <section class="min-h-screen bg-gray-50">
<nav <div
class:-translate-x-full={!navOpen} class:collapsed_navigation={!navOpen}
class:translate-x-0={navOpen} class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 bg-gray-50">
class="select-none fixed top-0 left-0 z-20 h-full pb-10 overflow-x-hidden overflow-y-auto transition origin-left transform border-r w-60 md:translate-x-0 bg-gray-50">
<a href="/" class="flex items-center px-4 py-5"> <a href="/" class="flex items-center px-4 py-5">
<img src="/lfk-logo.png" alt="Logo" class="h-10" /> <img src="/lfk-logo.png" alt="Logo" class="h-10" />
<h3 class="text-lg">Lauf für Kaya! Admin</h3> <h3 class="text-lg">Lauf für Kaya! Admin</h3>
@@ -246,6 +256,26 @@
<span>{$_('scanstations')}</span> <span>{$_('scanstations')}</span>
</a> </a>
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:GET')}
<a
class:bg-gray-100={$router.path === '/statsclients/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
href="/statsclients/">
<svg
class="flex-shrink-0 w-5 h-5 mr-2 text-gray-400 transition group-hover:text-gray-600"
fill="currentColor"
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"><path
fill="none"
d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></svg>
<span>{$_('statsclients')}</span>
</a>
{/if}
<a <a
class:bg-gray-100={$router.path === '/settings/'} class:bg-gray-100={$router.path === '/settings/'}
class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900" class="flex items-center px-4 py-3 transition cursor-pointer group hover:bg-gray-100 hover:text-gray-900"
@@ -297,14 +327,15 @@
<span>{$_('logout')}</span> <span>{$_('logout')}</span>
</span> </span>
</nav> </nav>
</nav> </div>
<div class="ml-0 transition md:ml-60"> <div class="ml-0 transition md:ml-60">
<header <header
on:click={() => {
navOpen = true;
}}
class="flex items-center justify-between w-full px-4 bg-white border-b h-14 md:hidden"> class="flex items-center justify-between w-full px-4 bg-white border-b h-14 md:hidden">
<button class="block btn btn-light md:hidden"> <button
on:click={() => {
navOpen = true;
}}
class="block btn btn-light md:hidden">
<span class="sr-only">Menu</span><svg <span class="sr-only">Menu</span><svg
class="w-4 h-4" class="w-4 h-4"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -318,10 +349,13 @@
<NoComponentLoaded /> <NoComponentLoaded />
</slot> </slot>
</div> </div>
<div {#if navOpen === true}
on:click={() => { <div
navOpen = false; on:click={() => {
}} navOpen = false;
class:hidden={!navOpen} console.log({ navOpen });
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" /> }}
class:hidden={!navOpen}
class="fixed inset-0 z-10 w-screen h-screen bg-black bg-opacity-25 md:hidden" />
{/if}
</section> </section>

View File

@@ -70,7 +70,7 @@
<div class="text-xs uppercase font-light text-grey-500"> <div class="text-xs uppercase font-light text-grey-500">
{$_('total-donations')} {$_('total-donations')}
</div> </div>
<div class="text-xl font-bold">{stats.total_donation}</div> <div class="text-xl font-bold">{(stats.total_donation/100).toFixed(2)}</div>
</div><svg </div><svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
height="24" height="24"

View File

@@ -9,6 +9,7 @@
} 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";
export let modal_open; export let modal_open;
export let current_donations; export let current_donations;
const getDonorLabel = (option) => const getDonorLabel = (option) =>
@@ -24,6 +25,7 @@
$: donors = []; $: donors = [];
$: runners = []; $: runners = [];
$: is_fixed = false; $: is_fixed = false;
$: is_paid = false;
DonorService.donorControllerGetAll().then((val) => { DonorService.donorControllerGetAll().then((val) => {
donors = val.map((r) => { donors = val.map((r) => {
return { label: getDonorLabel(r), value: r }; return { label: getDonorLabel(r), value: r };
@@ -57,14 +59,18 @@
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
}; };
if(is_paid){
postdata.paidAmount = amount_cent;
}
DonationService.donationControllerPostFixed(postdata) DonationService.donationControllerPostFixed(postdata)
.then((result) => { .then((result) => {
donor = donors[0].id || 0; donor = donors[0].id || 0;
@@ -73,7 +79,7 @@
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();
@@ -102,7 +108,7 @@
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();
@@ -123,7 +129,7 @@
</script> </script>
<style> <style>
input:before { .toggle:before {
content: ""; content: "";
position: absolute; position: absolute;
width: 1.25rem; width: 1.25rem;
@@ -137,12 +143,12 @@
transition: 0.2s ease-in-out; transition: 0.2s ease-in-out;
} }
input:checked { .toggle:checked {
/* @apply: bg-indigo-400; */ /* @apply: bg-indigo-400; */
background-color: #7f9cf5; background-color: #7f9cf5;
} }
input:checked:before { .toggle:checked:before {
left: 1.25rem; left: 1.25rem;
} }
</style> </style>
@@ -195,7 +201,7 @@
class="ml-2 text-base" class="ml-2 text-base"
class:text-gray-300={is_fixed}>{$_('distance-donation')}</span> class:text-gray-300={is_fixed}>{$_('distance-donation')}</span>
<input <input
class="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" 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" type="checkbox"
bind:checked={is_fixed} /> bind:checked={is_fixed} />
<span <span
@@ -267,6 +273,29 @@
</span> </span>
{/if} {/if}
</div> </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> </div>

View File

@@ -0,0 +1,202 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { DonationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
export let payment_modal_open = false;
export let current_donations = [];
export let editable = {};
export let original_data = {};
export let paid_amount_input = 0;
$:processed_last_submit=true;
function focus(el) {
el.focus();
}
$: createbtnenabled = is_paid_amount_valid && !(paid_amount_input*100 == original_data.paidAmount)
$: is_paid_amount_valid = paid_amount_input > 0;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
payment_modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
const toast = Toastify({
text: $_('updating-donation'),
duration: -1,
}).showToast();
editable.donor = editable.donor.id;
editable.paidAmount = paid_amount_input*100;
if(editable.responseType == "DISTANCEDONATION" || editable.runner){
editable.runner = editable.runner.id;
DonationService.donationControllerPutDistance(original_data.id, editable)
.then((result) => {
let id = original_data.id;
editable = {};
original_data = {};
payment_modal_open = false;
//
Toastify({
text: $_('donation-updated'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_donations[current_donations.findIndex((c) => c.id === id)] = result;
current_donations = current_donations;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
}
else{
DonationService.donationControllerPutFixed(original_data.id, editable)
.then((result) => {
let id = original_data.id;
editable = {};
original_data = {};
payment_modal_open = false;
//
Toastify({
text: $_('donation-updated'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_donations[current_donations.findIndex((c) => c.id === id)] = result;
current_donations = current_donations;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
}
}
}
</script>
{#if payment_modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside
on:click_outside={() => {
payment_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
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>
</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">
{$_('enter-payment')}
</h3>
<div class="mt-2 mb-6">
<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')}
</p>
</div>
<div class="grid grid-cols gap-6">
<div class="w-full">
<label
for="token"
class="block text-sm font-medium text-gray-700">{$_('paid-amount')}</label>
<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"
class:border-red-500={!is_paid_amount_valid}
class:focus:border-red-500={!is_paid_amount_valid}
class:focus:ring-red-500={!is_paid_amount_valid}
bind:value={paid_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 p-2"
placeholder="2.00" />
<button
on:click={
()=>{
paid_amount_input=paid_amount_input = (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>
<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_paid_amount_valid}
<span
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')}
</span>
{/if}
</div>
</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">
{$_('save-changes')}
</button>
<button
on:click={() => {
payment_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

@@ -20,6 +20,8 @@
$: current_runners = []; $: current_runners = [];
$: amount_input = 0; $: amount_input = 0;
$: is_amount_valid = amount_input > 0; $: is_amount_valid = amount_input > 0;
$: paid_amount_input = 0;
$: is_paid_amount_valid = paid_amount_input > 0;
$: is_everything_set = $: is_everything_set =
editable.donor != null && editable.donor != null &&
((original_data.responseType == "DISTANCEDONATION" && ((original_data.responseType == "DISTANCEDONATION" &&
@@ -30,15 +32,17 @@
(original_data.responseType == "DISTANCEDONATION" && (original_data.responseType == "DISTANCEDONATION" &&
!(Math.floor(amount_input * 100) === original_data.amountPerDistance)) || !(Math.floor(amount_input * 100) === original_data.amountPerDistance)) ||
(original_data.responseType !== "DISTANCEDONATION" && (original_data.responseType !== "DISTANCEDONATION" &&
!(Math.floor(amount_input * 100) === original_data.amount)); !(Math.floor(amount_input * 100) === original_data.amount)) ||
!(Math.floor(paid_amount_input * 100) === original_data.paidAmount);
$: save_enabled = changes_performed && is_amount_valid && is_everything_set; $: save_enabled = changes_performed && is_amount_valid && is_everything_set;
const promise = DonationService.donationControllerGetOne( const promise = DonationService.donationControllerGetOne(
params.donationid params.donationid
).then((data) => { ).then((data) => {
data_loaded = true; data_loaded = true;
original_data = Object.assign(original_data, data); original_data = Object.assign({}, data);
editable = Object.assign(editable, original_data); editable = Object.assign({}, original_data);
paid_amount_input = data.paidAmount / 100;
if (data.responseType == "DISTANCEDONATION") { if (data.responseType == "DISTANCEDONATION") {
amount_input = data.amountPerDistance / 100; amount_input = data.amountPerDistance / 100;
RunnerService.runnerControllerGetAll().then((val) => { RunnerService.runnerControllerGetAll().then((val) => {
@@ -66,10 +70,11 @@
function submit() { function submit() {
if (data_loaded === true && save_enabled) { if (data_loaded === true && save_enabled) {
Toastify({ Toastify({
text: "Donation is being updated", text: $_('updating-donation'),
duration: 2500, duration: 2500,
}).showToast(); }).showToast();
let postdata = {}; let postdata = {};
editable.paidAmount = paid_amount_input*100;
if (original_data.responseType === "DISTANCEDONATION") { if (original_data.responseType === "DISTANCEDONATION") {
editable.amountPerDistance = Math.floor(amount_input * 100); editable.amountPerDistance = Math.floor(amount_input * 100);
postdata = Object.assign(postdata, editable); postdata = Object.assign(postdata, editable);
@@ -83,7 +88,7 @@
Object.assign(original_data, editable); Object.assign(original_data, editable);
original_data = original_data; original_data = original_data;
Toastify({ Toastify({
text: "updated donation", text: $_('donation-updated'),
duration: 2500, duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -98,7 +103,7 @@
Object.assign(original_data, editable); Object.assign(original_data, editable);
original_data = original_data; original_data = original_data;
Toastify({ Toastify({
text: "updated donation", text: $_('donation-updated'),
duration: 2500, duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -112,7 +117,7 @@
DonationService.donationControllerRemove(original_data.id, false) DonationService.donationControllerRemove(original_data.id, false)
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Donation delete", text: $_('donation-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -219,7 +224,24 @@
<span>{(editable.amount / 100) <span>{(editable.amount / 100)
.toFixed(2) .toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}</span> .toLocaleString('de-DE', { valute: 'EUR' })}</span>
|
<span
class="font-medium text-gray-700">{$_('paid-amount')}:</span>
<span>{(editable.paidAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}</span>
|
<span
class="font-medium text-gray-700">{$_('status')}:</span>
{#if editable.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}
</div> </div>
<br>
<div class=" w-full"> <div class=" w-full">
<label <label
for="donor" for="donor"
@@ -232,7 +254,7 @@
placeholder={$_('search-for-donor-name-or-id')} placeholder={$_('search-for-donor-name-or-id')}
noOptionsMessage={$_('no-donors-found')} noOptionsMessage={$_('no-donors-found')}
bind:selectedValue={donor} bind:selectedValue={donor}
on:select={(selectedValue) => (editable.donor = selectedValue.detail.value)} on:select={(selectedValue) => {editable.donor = selectedValue.detail.value; editable.donor.donationAmount=original_data.donor.donationAmount; editable.donor.paidDonationAmount =original_data.donor.paidDonationAmount}}
on:clear={() => (editable.donor = null)} /> on:clear={() => (editable.donor = null)} />
</div> </div>
{#if original_data.responseType == 'DISTANCEDONATION'} {#if original_data.responseType == 'DISTANCEDONATION'}
@@ -280,6 +302,39 @@
</span> </span>
{/if} {/if}
</div> </div>
<div class="w-full">
<label
for="token"
class="block text-sm font-medium text-gray-700">{$_('paid-amount')}</label>
<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"
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={paid_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 p-2"
placeholder="2.00" />
<button
on:click={
()=>{
paid_amount_input=paid_amount_input = (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>
<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_paid_amount_valid}
<span
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')}
</span>
{/if}
</div>
</section> </section>
{:catch error} {:catch error}
<PromiseError {error} /> <PromiseError {error} />

View File

@@ -4,9 +4,14 @@
import store from "../../store"; import store from "../../store";
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import DonationsEmptyState from "./DonationsEmptyState.svelte"; import DonationsEmptyState from "./DonationsEmptyState.svelte";
import AddDonationPaymentModal from "./AddDonationPaymentModal.svelte";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
export let current_donations = []; export let current_donations = [];
export let payment_modal_open = false;
export let editable = {};
export let original_data = {};
export let paid_amount_input = 0;
const donations_promise = DonationService.donationControllerGetAll().then( const donations_promise = DonationService.donationControllerGetAll().then(
(val) => { (val) => {
current_donations = val; current_donations = val;
@@ -18,8 +23,15 @@
} }
return id.toString() === searchvalue; return id.toString() === searchvalue;
} }
function open_payment_modal(donation) {
editable = Object.assign({}, donation);
original_data = Object.assign({}, donation);
paid_amount_input = (donation.paidAmount/100).toFixed(2);
payment_modal_open = true;
}
</script> </script>
<AddDonationPaymentModal bind:current_donations bind:original_data bind:editable bind:paid_amount_input bind:payment_modal_open />
{#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')} {#if store.state.jwtinfo.userdetails.permissions.includes('DONATION:GET')}
{#await donations_promise} {#await donations_promise}
<div <div
@@ -63,6 +75,16 @@
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('donation-amount')} {$_('donation-amount')}
</th> </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"> <th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span> <span class="sr-only">{$_('action')}</span>
</th> </th>
@@ -132,6 +154,22 @@
.toLocaleString('de-DE', { valute: 'EUR' })} .toLocaleString('de-DE', { valute: 'EUR' })}
</div> </div>
</td> </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} {#if active_deletes[donation.id] === true}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
@@ -149,7 +187,7 @@
(obj) => obj.id !== donation.id (obj) => obj.id !== donation.id
); );
Toastify({ Toastify({
text: 'Donation deleted', text: $_('donation-deleted'),
duration: 500, duration: 500,
backgroundColor: backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)', 'linear-gradient(to right, #00b09b, #96c93d)',
@@ -163,6 +201,9 @@
{:else} {:else}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> 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 <a
href="./{donation.id}" href="./{donation.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a> class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>

View File

@@ -19,7 +19,7 @@
) )
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Donor deleted", text: $_('donor-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -193,6 +193,12 @@
<span>{(editable.donationAmount / 100) <span>{(editable.donationAmount / 100)
.toFixed(2) .toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}</span> .toLocaleString('de-DE', { valute: 'EUR' })}</span>
|
<span
class="font-medium text-gray-700">{$_('total-paid-amount')}:</span>
<span>{(editable.paidDonationAmount / 100)
.toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })}</span>
<br /> <br />
<span class="font-medium text-gray-700">{$_('donations')}:</span> <span class="font-medium text-gray-700">{$_('donations')}:</span>
{#if current_donations.filter((d) => d.donor.id == editable.id).length > 0} {#if current_donations.filter((d) => d.donor.id == editable.id).length > 0}
@@ -201,7 +207,7 @@
<a <a
href="../donations/{d.id}" 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} 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.middlename || ""}
{d.runner.lastname}</a> {d.runner.lastname}</a>
{:else} {:else}
<a <a

View File

@@ -20,6 +20,31 @@
{$_('add-donor')} {$_('add-donor')}
</button> </button>
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')}
<button
on:click={() => {
const data = (current_donors.filter(d=>d.receiptNeeded===true)).map(function (d) {
d.address.address2=d.address.address2===""?"":" "+d.address.address2;
const address=`${d.address.address1}${d.address.address2}, ${d.address.postalcode} ${d.address.city}, ${d.address.country}`;
return [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";
});
let hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
hiddenElement.target = '_blank';
hiddenElement.download = `${$_('filename_sponsoringquittungsliste')}.csv`;
hiddenElement.click();
hiddenElement.remove();
}}
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">
{$_('sponsoring-quittungs-liste_herunterladen')}
</button>
{/if}
</span> </span>
<DonorsOverview bind:current_donors /> <DonorsOverview bind:current_donors />
</section> </section>

View File

@@ -1,5 +1,5 @@
<script> <script>
import { getLocaleFromNavigator, _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { DonationService, DonorService } from "@odit/lfk-client-js"; import { DonationService, DonorService } from "@odit/lfk-client-js";
import store from "../../store"; import store from "../../store";
import DonorsEmptyState from "./DonorsEmptyState.svelte"; import DonorsEmptyState from "./DonorsEmptyState.svelte";
@@ -77,6 +77,11 @@
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('total-donation-amount')} {$_('total-donation-amount')}
</th> </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"> <th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span> <span class="sr-only">{$_('action')}</span>
</th> </th>
@@ -127,7 +132,7 @@
<a <a
href="../donations/{d.id}" 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} 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.middlename || ''}
{d.runner.lastname}</a> {d.runner.lastname}</a>
{:else} {:else}
<a <a
@@ -145,6 +150,11 @@
.toFixed(2) .toFixed(2)
.toLocaleString('de-DE', { valute: 'EUR' })} .toLocaleString('de-DE', { valute: 'EUR' })}
</td> </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} {#if active_deletes[donor.id] === true}
<td <td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">

View File

@@ -32,8 +32,12 @@
target="_blank" target="_blank"
rel="noopener, noreferrer" rel="noopener, noreferrer"
href="https://git.odit.services/lfk/frontend/src/tag/{releaseinfo}">{releaseinfo}</a> href="https://git.odit.services/lfk/frontend/src/tag/{releaseinfo}">{releaseinfo}</a>
- -
<a class="underline" href="https://docs.lauf-fuer-kaya.de" target="_blank">{$_('documentation')}</a> <a
rel="noopener, noreferrer"
class="underline"
href="https://docs.lauf-fuer-kaya.de"
target="_blank">{$_('documentation')}</a>
- -
<a class="underline" href="/privacy">{$_('privacy')}</a> <a class="underline" href="/privacy">{$_('privacy')}</a>
- -

View File

@@ -19,7 +19,7 @@
) )
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Organization deleted", text: $_('organization-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -12,6 +12,7 @@
import Select from "svelte-select"; import Select from "svelte-select";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
import { tick } from "svelte"; import { tick } from "svelte";
$: delete_triggered = false; $: delete_triggered = false;
$: address_valid_or_none = $: address_valid_or_none =
@@ -34,6 +35,7 @@
$: iscityvalid = editable.address?.city?.trim().length !== 0; $: iscityvalid = editable.address?.city?.trim().length !== 0;
$: sponsoring_contracts_show = true; $: sponsoring_contracts_show = true;
$: cards_show = true; $: cards_show = true;
$: certificates_show = true;
$: generate_orgs = [original_object]; $: generate_orgs = [original_object];
$: registrationLink = `${config.baseurl}/selfservice/register/${editable.registrationKey}`; $: registrationLink = `${config.baseurl}/selfservice/register/${editable.registrationKey}`;
const getContactLabel = (option) => const getContactLabel = (option) =>
@@ -176,6 +178,7 @@
bind:sponsoring_contracts_show bind:sponsoring_contracts_show
bind:generate_orgs /> bind:generate_orgs />
<GenerateRunnerCards bind:cards_show bind:generate_orgs /> <GenerateRunnerCards bind:cards_show bind:generate_orgs />
<GenerateRunnerCertificates bind:certificates_show bind:generate_orgs />
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')}
<button <button
on:click={() => { on:click={() => {
@@ -186,7 +189,7 @@
{$_('import-runners')} {$_('import-runners')}
</button> </button>
{/if} {/if}
{#if store.state.jwtinfo.userdetails.permissions.includes('USER:DELETE')} {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:DELETE')}
{#if delete_triggered} {#if delete_triggered}
<button <button
on:click={deleteOrganization} on:click={deleteOrganization}

View File

@@ -9,11 +9,15 @@
import Toastify from "toastify-js"; import Toastify from "toastify-js";
import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte"; import ConfirmOrgDeletion from "./ConfirmOrgDeletion.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: sponsoring_contracts_show = current_organizations.some((r) => r.is_selected === true); $: sponsoring_contracts_show = current_organizations.some((r) => r.is_selected === true);
$: cards_show = current_organizations.some((r) => r.is_selected === true); $: cards_show = current_organizations.some((r) => r.is_selected === true);
$: generate_orgs = current_organizations.filter((r) => r.is_selected === true); $: generate_orgs = current_organizations.filter((r) => r.is_selected === true);
$: certificates_show = current_organizations.some(
(r) => r.is_selected === true
);
export let current_organizations = []; export let current_organizations = [];
const promise = RunnerOrganizationService.runnerOrganizationControllerGetAll().then( const promise = RunnerOrganizationService.runnerOrganizationControllerGetAll().then(
@@ -55,6 +59,9 @@
<GenerateRunnerCards <GenerateRunnerCards
bind:cards_show bind:cards_show
bind:generate_orgs /> bind:generate_orgs />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_orgs />
</div> </div>
<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">

View File

@@ -41,7 +41,7 @@
duration: -1, duration: -1,
}).showToast(); }).showToast();
fetch( fetch(
`${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -67,7 +67,7 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Runnercards.pdf"; a.download = `${$_('runnercards')}-${locale}.pdf`;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -101,7 +101,7 @@
cards.push(card); cards.push(card);
} }
fetch( fetch(
`${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -127,7 +127,12 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Runnercards.pdf"; if(generate_runners.length == 1){
a.download = `${$_('runnercards')}_${generate_runners[0].firstname}_${generate_runners[0].lastname}-${locale}.pdf`;
}
else{
a.download = `Runnercards-${locale}.pdf`;
}
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -164,7 +169,7 @@
cards.push(card); cards.push(card);
} }
fetch( fetch(
`${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -191,7 +196,7 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Sponsorings_" + t.name + ".pdf"; a.download = `${$_('runnercards')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -211,15 +216,16 @@
async function generateOrgCards(locale) { async function generateOrgCards(locale) {
const toast = Toastify({ const toast = Toastify({
text: $_("generating-pdf"), text: $_("generating-pdfs"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
let count = 0;
const current_cards = await RunnerCardService.runnerCardControllerGetAll(); const current_cards = await RunnerCardService.runnerCardControllerGetAll();
let count = 0;
let count_orgs =0;
for (const o of generate_orgs) { for (const o of generate_orgs) {
const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners( count_orgs++;
o.id let count = 0;
); let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
let cards = []; let cards = [];
for (let runner of runners) { for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id); let card = current_cards.find((c) => c.runner?.id == runner.id);
@@ -230,8 +236,8 @@
} }
cards.push(card); cards.push(card);
} }
fetch( await fetch(
`${config.baseurl}/documents/cards?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -240,39 +246,97 @@
body: JSON.stringify(cards), body: JSON.stringify(cards),
} }
) )
.then((response) => { .then((response) => {
if (response.status != "200") { if (response.status != "200") {
toast.hideToast(); toast.hideToast();
Toastify({ Toastify({
text: $_("pdf-generation-failed"), text: $_("pdf-generation-failed"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast(); }).showToast();
} else { } else {
return response.blob(); return response.blob();
} }
}) })
.then((blob) => { .then((blob) => {
count++; const url = window.URL.createObjectURL(blob);
const url = window.URL.createObjectURL(blob); let a = document.createElement("a");
let a = document.createElement("a"); a.href = url;
a.href = url; a.download = `${$_('runnercards')}_${o.name}_direct-${locale}.pdf`;
a.download = "Sponsorings_" + o.name + ".pdf"; document.body.appendChild(a);
document.body.appendChild(a); a.click();
a.click(); a.remove();
a.remove(); if (count === o.teams.length && count_orgs === generate_orgs.length) {
if (count === generate_orgs.length) { toast.hideToast();
toast.hideToast(); console.log("here")
Toastify({ Toastify({
text: $_("pdfs-successfully-generated"), text: $_("pdfs-successfully-generated"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)", "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
} }
}) })
.catch((err) => {}); .catch((err) => {});
for (const t of o.teams) {
count++;
let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
let cards = [];
for (let runner of runners) {
let card = current_cards.find((c) => c.runner?.id == runner.id);
if (!card) {
card = await RunnerCardService.runnerCardControllerPost({
runner: runner.id,
});
}
cards.push(card);
}
await fetch(
`${config.baseurl_documentserver}/cards?locale=${locale}&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(cards),
}
)
.then((response) => {
if (response.status != "200") {
toast.hideToast();
Toastify({
text: $_("pdf-generation-failed"),
duration: 3500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
} else {
return response.blob();
}
})
.then((blob) => {
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = `${$_('runnercards')}_${o.name}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
}
} }
} }
</script> </script>

View File

@@ -37,14 +37,15 @@
text: $_("generating-pdf"), text: $_("generating-pdf"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
const current_donations = await DonationService.donationControllerGetAll(); const current_donations = (await DonationService.donationControllerGetAll()) || [];
let certificateRunners = []; let certificateRunners = [];
for (let runner of generate_runners) { for (let runner of generate_runners) {
runner.distanceDonations = current_donations.find((d) => d.runner?.id == runner.id) || []; runner.distanceDonations = current_donations.filter((d) => d.runner?.id == runner.id) || [];
console.log(runner.distanceDonations)
certificateRunners.push(runner); certificateRunners.push(runner);
} }
fetch( fetch(
`${config.baseurl}/documents/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -70,7 +71,12 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Certificates.pdf"; if(generate_runners.length == 1){
a.download = `${$_('certificates')}_${generate_runners[0].firstname}_${generate_runners[0].lastname}-${locale}.pdf`;
}
else{
a.download = `${$_('certificates')}-${locale}.pdf`;
}
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -91,19 +97,18 @@
duration: -1, duration: -1,
}).showToast(); }).showToast();
let count = 0; let count = 0;
const current_donations = await DonationService.donationControllerGetAll(); const current_donations = (await DonationService.donationControllerGetAll()) || [];
for (const t of generate_teams) { for (const t of generate_teams) {
const runners = await RunnerTeamService.runnerTeamControllerGetRunners( const runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id t.id
); );
let certificateRunners = []; let certificateRunners = [];
for (let runner of runners) { for (let runner of runners) {
runner.distanceDonations = current_donations.find((d) => d.runner?.id == runner.id) || []; runner.distanceDonations = current_donations.filter((d) => d.runner?.id == runner.id) || [];
certificateRunners.push(runner); certificateRunners.push(runner);
} }
console.log(certificateRunners)
fetch( fetch(
`${config.baseurl}/documents/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -130,7 +135,7 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Certificates_" + t.name + ".pdf"; a.download = `${$_('certificates')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -150,22 +155,23 @@
async function generateOrgCertificates(locale) { async function generateOrgCertificates(locale) {
const toast = Toastify({ const toast = Toastify({
text: $_("generating-pdf"), text: $_("generating-pdfs"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
const current_donations = (await DonationService.donationControllerGetAll()) || [];
let count = 0; let count = 0;
const current_donations = await DonationService.donationControllerGetAll(); let count_orgs =0;
for (const o of generate_orgs) { for (const o of generate_orgs) {
const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners( count_orgs++;
o.id let count = 0;
); let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
let certificateRunners = []; let certificateRunners = [];
for (let runner of runners) { for (let runner of runners) {
runner.distanceDonations = current_donations.find((d) => d.runner?.id == runner.id) || []; runner.distanceDonations = current_donations.filter((d) => d.runner?.id == runner.id) || [];
certificateRunners.push(runner); certificateRunners.push(runner);
} }
fetch( await fetch(
`${config.baseurl}/documents/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -174,39 +180,92 @@
body: JSON.stringify(certificateRunners), body: JSON.stringify(certificateRunners),
} }
) )
.then((response) => { .then((response) => {
if (response.status != "200") { if (response.status != "200") {
toast.hideToast(); toast.hideToast();
Toastify({ Toastify({
text: $_("pdf-generation-failed"), text: $_("pdf-generation-failed"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast(); }).showToast();
} else { } else {
return response.blob(); return response.blob();
} }
}) })
.then((blob) => { .then((blob) => {
count++; const url = window.URL.createObjectURL(blob);
const url = window.URL.createObjectURL(blob); let a = document.createElement("a");
let a = document.createElement("a"); a.href = url;
a.href = url; a.download = `${$_('certificates')}_${o.name}_direct-${locale}.pdf`;
a.download = "Certificates_" + o.name + ".pdf"; document.body.appendChild(a);
document.body.appendChild(a); a.click();
a.click(); a.remove();
a.remove(); if (count === o.teams.length && count_orgs === generate_orgs.length) {
if (count === generate_orgs.length) { toast.hideToast();
toast.hideToast(); console.log("here")
Toastify({ Toastify({
text: $_("pdfs-successfully-generated"), text: $_("pdfs-successfully-generated"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)", "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
} }
}) })
.catch((err) => {}); .catch((err) => {});
for (const t of o.teams) {
count++;
let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
let certificateRunners = [];
for (let runner of runners) {
runner.distanceDonations = current_donations.filter((d) => d.runner?.id == runner.id) || [];
certificateRunners.push(runner);
}
await fetch(
`${config.baseurl_documentserver}/certificates?locale=${locale}&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(certificateRunners),
}
)
.then((response) => {
if (response.status != "200") {
toast.hideToast();
Toastify({
text: $_("pdf-generation-failed"),
duration: 3500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
} else {
return response.blob();
}
})
.then((blob) => {
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = `${$_('certificates')}_${o.name}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
}
} }
} }
</script> </script>

View File

@@ -43,7 +43,7 @@
t.id t.id
); );
fetch( fetch(
`${config.baseurl}/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -69,7 +69,7 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Sponsorings_" + t.name + ".pdf"; a.download = `${$_('sponsorings')}_${t.name}-${locale}.pdf`;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
@@ -92,12 +92,13 @@
text: $_("generating-pdf"), text: $_("generating-pdf"),
duration: -1, duration: -1,
}).showToast(); }).showToast();
let count_orgs =0;
for (const o of generate_orgs) { for (const o of generate_orgs) {
const runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners( count_orgs++;
o.id let count = 0;
); let runners = await RunnerOrganizationService.runnerOrganizationControllerGetRunners(o.id, true)
fetch( await fetch(
`${config.baseurl}/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -106,39 +107,87 @@
body: JSON.stringify(runners), body: JSON.stringify(runners),
} }
) )
.then((response) => { .then((response) => {
if (response.status != "200") { if (response.status != "200") {
toast.hideToast(); toast.hideToast();
Toastify({ Toastify({
text: $_("pdf-generation-failed"), text: $_("pdf-generation-failed"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)", "linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast(); }).showToast();
} else { } else {
return response.blob(); return response.blob();
} }
}) })
.then((blob) => { .then((blob) => {
count++; const url = window.URL.createObjectURL(blob);
const url = window.URL.createObjectURL(blob); let a = document.createElement("a");
let a = document.createElement("a"); a.href = url;
a.href = url; a.download = `${$_('sponsorings')}_${o.name}_direct-${locale}.pdf`;
a.download = "Sponsorings_" + o.name + ".pdf"; document.body.appendChild(a);
document.body.appendChild(a); a.click();
a.click(); a.remove();
a.remove(); if (count === o.teams.length && count_orgs === generate_orgs.length) {
if (count === generate_orgs.length) { toast.hideToast();
toast.hideToast(); console.log("here")
Toastify({ Toastify({
text: $_("pdfs-successfully-generated"), text: $_("pdfs-successfully-generated"),
duration: 3500, duration: 3500,
backgroundColor: backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)", "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
} }
}) })
.catch((err) => {}); .catch((err) => {});
for (const t of o.teams) {
count++;
let runners = await RunnerTeamService.runnerTeamControllerGetRunners(
t.id
);
await fetch(
`${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(runners),
}
)
.then((response) => {
if (response.status != "200") {
toast.hideToast();
Toastify({
text: $_("pdf-generation-failed"),
duration: 3500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
} else {
return response.blob();
}
})
.then((blob) => {
const url = window.URL.createObjectURL(blob);
let a = document.createElement("a");
a.href = url;
a.download = `${$_('sponsorings')}_${o.name}_${t.name}-${locale}.pdf`;
document.body.appendChild(a);
a.click();
a.remove();
if (count === o.teams.length && count_orgs === generate_orgs.length) {
toast.hideToast();
Toastify({
text: $_("pdfs-successfully-generated"),
duration: 3500,
backgroundColor:
"linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
}
})
.catch((err) => {});
}
} }
} }
@@ -148,7 +197,7 @@
duration: -1, duration: -1,
}).showToast(); }).showToast();
fetch( fetch(
`${config.baseurl}/documents/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`, `${config.baseurl_documentserver}/contracts?locale=${locale}&download=true&key=${config.documentserver_key}`,
{ {
method: "POST", method: "POST",
headers: { headers: {
@@ -174,7 +223,10 @@
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
let a = document.createElement("a"); let a = document.createElement("a");
a.href = url; a.href = url;
a.download = "Sponsoring.pdf"; if(generate_runners.length == 1){
a.download = `${$_('sponsorings')}_${generate_runners[0].firstname}_${generate_runners[0].lastname}-${locale}.pdf`;
}
a.download = `${$_('sponsorings')}-${locale}.pdf`;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();

View File

@@ -34,7 +34,7 @@
document.onkeydown = (e) => { document.onkeydown = (e) => {
e = e || window.event; e = e || window.event;
if (e.key === "Escape") { if (e.key === "Escape") {
import_modal_open = false; cancelModal();
} }
if (e.keyCode === 13) { if (e.keyCode === 13) {
// //
@@ -202,7 +202,7 @@
toast.hideToast(); toast.hideToast();
recent_processed = true; recent_processed = true;
Toastify({ Toastify({
text: "Import finished", text: $_('import-finished'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -281,6 +281,16 @@
bind:files bind:files
type="file" /> type="file" />
</div> </div>
<div class="overflow-hidden relative mt-4 mb-4">
<button
on:click={() => {
cancelModal();
}}
type="button"
class="w-full 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 md:ml-40 mr-0 sm:ml-0 sm:w-auto sm:text-sm">
{$_('cancel')}
</button>
</div>
{/if} {/if}
{#if json_output.length > 0} {#if json_output.length > 0}
{#if opened_from === 'OrgOverview'} {#if opened_from === 'OrgOverview'}

View File

@@ -294,7 +294,7 @@
<div class="text-sm w-full"> <div class="text-sm w-full">
<span class="font-medium text-gray-700">{$_('distance')}</span> <span class="font-medium text-gray-700">{$_('distance')}</span>
<br /> <br />
<span class="text-gray-700">{original_data.distance} km</span> <span class="text-gray-700">{original_data.distance /1000 } km</span>
</div> </div>
</section> </section>
{:catch error} {:catch error}

View File

@@ -1,5 +1,5 @@
<script> <script>
import { getLocaleFromNavigator, _ } from "svelte-i18n"; import { _ } from "svelte-i18n";
import { import {
RunnerService, RunnerService,
RunnerTeamService, RunnerTeamService,
@@ -11,11 +11,13 @@
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte"; import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
let pageLoaded = false;
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
export let current_runners = []; export let current_runners = [];
const runners_promise = RunnerService.runnerControllerGetAll().then((val) => { const runners_promise = RunnerService.runnerControllerGetAll().then((val) => {
current_runners = val; current_runners = val;
pageLoaded = true;
}); });
$: selectedFilter_teams = null; $: selectedFilter_teams = null;
$: selectedFilter = null; $: selectedFilter = null;
@@ -101,8 +103,10 @@
bind:generate_runners /> bind:generate_runners />
</div> </div>
<div <div
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"> class:hidden={!pageLoaded}
<table class="divide-y divide-gray-200 w-full"> class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
>
<table class="divide-y divide-gray-200 w-full table-fixed">
<thead class="bg-gray-50"> <thead class="bg-gray-50">
<tr> <tr>
<th <th
@@ -197,7 +201,7 @@
{#if runner.group.responseType === 'RUNNERTEAM'} {#if runner.group.responseType === 'RUNNERTEAM'}
<a <a
href="../teams/{runner.group.id}" href="../teams/{runner.group.id}"
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{runner.group.name}</a> class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800">{runner.group.parentGroup.name} &gt; {runner.group.name}</a>
{/if} {/if}
{#if runner.group.responseType === 'RUNNERORGANIZATION'} {#if runner.group.responseType === 'RUNNERORGANIZATION'}
<a <a
@@ -206,7 +210,7 @@
{/if} {/if}
</td> </td>
<td class="px-6 py-4 whitespace-nowrap"> <td class="px-6 py-4 whitespace-nowrap">
{runner.distance} {runner.distance /1000 } km
</td> </td>
{#if active_deletes[runner.id] === true} {#if active_deletes[runner.id] === true}
<td <td

View File

@@ -17,7 +17,7 @@
MeService.meControllerRemove(true) MeService.meControllerRemove(true)
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Profile deleted!", text: $_('profile-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -0,0 +1,151 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { StatsClientService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
export let modal_open;
export let new_client;
export let current_clients;
export let copy_modal_open;
function focus(el) {
el.focus();
}
$: description = "";
$: createbtnenabled = description != "";
$: processed_last_submit = true;
(() => {
document.onkeydown = (e) => {
e = e || window.event;
if (e.key === "Escape") {
modal_open = false;
}
if (e.keyCode === 13) {
if (createbtnenabled === true) {
createbtnenabled = false;
submit();
}
}
};
})();
function submit() {
if (processed_last_submit === true) {
processed_last_submit = false;
const toast = Toastify({
text: $_("statsclient-is-being-added"),
duration: -1,
}).showToast();
StatsClientService.statsClientControllerPost({description})
.then((result) => {
description = "";
modal_open = false;
//
Toastify({
text: $_("scanstation-added"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
current_clients.push(result);
current_clients = current_clients;
new_client = result;
copy_modal_open = true;
})
.catch((err) => {
//
})
.finally(() => {
processed_last_submit = true;
//
toast.hideToast();
});
}
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
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="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></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">
{$_('create-a-new-statsclient')}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_('please-provide-the-required-information-to-create-a-new-statsclient')}
</p>
</div>
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6">
<label
for="description"
class="block text-sm font-medium text-gray-700">{$_('description')}</label>
<input
use:focus
autocomplete="off"
placeholder={$_('description')}
bind:value={description}
type="text"
name="description"
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>
</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

@@ -0,0 +1,92 @@
<script>
import { _ } from "svelte-i18n";
import { clickOutside } from "../base/outsideclick";
import { focusTrap } from "svelte-focus-trap";
import { ScanStationService } from "@odit/lfk-client-js";
import Toastify from "toastify-js";
import { createEventDispatcher } from "svelte";
export let modal_open;
export let delete_station;
const dispatch = createEventDispatcher();
function cancelDelete() {
modal_open = false;
dispatch("cancelDelete", { id: delete_station.id });
}
function deleteClient() {
ScanStationService.donorControllerRemove(
delete_station.id,
true
)
.then((resp) => {
Toastify({
text: $_('statsclient-deleted'),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
location.replace("./");
})
.catch((err) => {});
}
</script>
{#if modal_open}
<div
class="fixed z-10 inset-0 overflow-y-auto"
use:focusTrap
use:clickOutside
on:click_outside={cancelDelete}>
<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 overflow-hidden 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"><path fill="none" d="M0 0h24v24H0z"/><path d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z"/></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">
{$_('attention')}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_(
'do-you-want-to-delete-this-donor-with-all-related-donations'
)}
<br />
{$_('all-associated-scans-will-get-deleted-as-well')}
</p>
</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={deleteClient}
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">
{$_('confirm-delete-statsclient')}
</button>
<button
on:click={cancelDelete}
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-keep-statsclient')}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -0,0 +1,129 @@
<script>
import { _ } from "svelte-i18n";
import { focusTrap } from "svelte-focus-trap";
import Toastify from "toastify-js";
import { tick, createEventDispatcher } from "svelte";
export let copy_modal_open;
export let new_client;
const dispatch = createEventDispatcher();
let valueCopy = null;
let areaDom;
let copied = false;
function close() {
copy_modal_open = false;
}
async function copy() {
valueCopy = new_client.key;
await tick();
areaDom.focus();
areaDom.select();
try {
const successful = document.execCommand("copy");
if (!successful) {
throw new Error();
}
Toastify({
text: $_("copied-token-to-clipboard"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
copied = true;
} catch (err) {
Toastify({
text: $_("error-whyile-copying-to-clipboard"),
duration: 500,
backgroundColor:
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
}).showToast();
}
// we can notifi by event or storage about copy status
valueCopy = null;
}
</script>
{#if copy_modal_open}
{#if valueCopy != null}
<textarea bind:this={areaDom}>{valueCopy}</textarea>
{/if}
<div class="fixed z-10 inset-0 overflow-y-auto" use:focusTrap>
<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 overflow-hidden 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"><path fill="none" d="M0 0h24v24H0z" />
<path
d="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></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">
{$_('token')}
</h3>
<div class="mt-2 mb-6">
<p class="text-sm text-gray-500">
{$_('the-statsclient-api-token-will-only-get-displayed-once-you-wont-be-able-to-change-or-view-it-again')}
<br />
{$_('please-copy-the-token-and-store-it-somewhere-save')}
</p>
</div>
<div class="mt-2 mb-6">
<label
for="token"
class="block text-sm font-medium text-gray-700">{$_('token')}</label>
<div on:click={copy} class="inline-flex">
<p
name="token"
class:bg-green-200={copied}
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 p-2">
{new_client.key}
</p>
<div
class="bg-gray-200 border-gray-300 border-t border-b border-r text-black rounded-r-md sm:text-sm p-2 mt-1 cursor-pointer">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="24"
height="24"><path fill="none" d="M0 0h24v24H0z" />
<path
fill="currentColor"
d="M7 4V2h10v2h3l1 1v16a1 1 0 01-1 1H4a1 1 0 01-1-1V5l1-1h3zm0 2H5v14h14V6h-2v2H7V6zm2-2v2h6V4H9z" /></svg>
</div>
</div>
<p class="text-gray-500 text-xs">
{$_('click-to-copy-token-to-clipboard')}
</p>
</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={close}
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-green-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm">
{$_('yes-i-copied-the-token')}
</button>
</div>
</div>
</div>
</div>
{/if}

View File

@@ -0,0 +1,119 @@
<script>
import { t, _ } from "svelte-i18n";
import store from "../../store";
import Toastify from "toastify-js";
import PromiseError from "../base/PromiseError.svelte";
import ConfirmStatsClientDeletion from "./ConfirmStatsClientDeletion.svelte";
import { StatsClientService } from "@odit/lfk-client-js";
let data_loaded = false;
let modal_open;
let delete_client;
export let params;
$: delete_triggered = false;
$: original_data = {};
const promise = StatsClientService.statsClientControllerGetOne(
params.clientid
).then((data) => {
data_loaded = true;
original_data = Object.assign(original_data, data);
});
function deleteClient() {
StatsClientService.statsClientControllerRemove(original_data.id, false)
.then((resp) => {
Toastify({
text: $_("statsclient-deleted"),
duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast();
location.replace("./");
})
.catch((err) => {
modal_open = true;
delete_client = original_data;
});
}
</script>
<ConfirmStatsClientDeletion bind:modal_open bind:delete_client />
{#await promise}
{$_('loading-statsclient-details')}
{:then}
<section class="container p-5 select-none">
<div class="flex flex-row mb-4">
<div class="w-full">
<nav class="w-full flex">
<ol class="list-none flex flex-row items-center justify-start">
<li class="flex items-center">
<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="M4 5v11h16V5H4zM2 4a1 1 0 011-1h18a1 1 0 011 1v14H2V4zM1 19h22v2H1v-2z" /></svg>
</li>
<li class="flex items-center ml-2">
<a class="mr-2" href="./">{$_('statsclient')}</a><svg
stroke="currentColor"
fill="none"
stroke-width="2"
viewBox="0 0 24 24"
stroke-linecap="round"
stroke-linejoin="round"
class="h-3 w-3 mr-2 stroke-current"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"><line
x1="5"
y1="12"
x2="19"
y2="12" />
<polyline points="12 5 19 12 12 19" /></svg>
</li>
<li class="flex items-center">
<span class="mr-2">#{original_data.id}</span>
</li>
</ol>
</nav>
</div>
</div>
<div class="mb-8 text-3xl font-extrabold leading-tight">
#{original_data.id}
<span data-id="stations_actions_${original_data.id}">
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:DELETE')}
{#if delete_triggered}
<button
on:click={deleteClient}
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">{$_('confirm-deletion')}</button>
<button
on:click={() => {
delete_triggered = !delete_triggered;
}}
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-400 text-base font-medium text-white sm:w-auto sm:text-sm">{$_('cancel')}</button>
{/if}
{#if !delete_triggered}
<button
on:click={() => {
delete_triggered = true;
}}
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">{$_('delete-statsclient')}</button>
{/if}
{/if}
</span>
</div>
<!-- -->
<div class="text-sm w-full">
<label
for="description"
class="font-medium text-gray-700">{$_('description')}</label>
<p
name="description"
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" >
{original_data.description}</p>
</div>
</section>
{:catch error}
<PromiseError {error} />
{/await}

View File

@@ -0,0 +1,33 @@
<script>
import { _ } from "svelte-i18n";
import store from "../../store";
import AddStatsClientModal from "./AddStatsClientModal.svelte";
import CopyStatsClientTokenModal from "./CopyStatsClientTokenModal.svelte";
import StatsClientsOverview from "./StatsClientsOverview.svelte";
export let modal_open = false;
export let copy_modal_open = false;
export let new_client = {};
let current_clients = [];
</script>
<section class="container p-5">
<span class="mb-1 text-3xl font-extrabold leading-tight">
{$_('statsclients')}
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:CREATE')}
<button
on:click={() => {
modal_open = true;
}}
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-a-new-statsclient')}
</button>
{/if}
</span>
<StatsClientsOverview bind:current_clients bind:modal_open bind:new_client bind:copy_modal_open />
</section>
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:CREATE')}
<AddStatsClientModal bind:modal_open bind:current_clients bind:new_client bind:copy_modal_open/>
<CopyStatsClientTokenModal bind:copy_modal_open bind:new_client />
{/if}

View File

@@ -0,0 +1,21 @@
<script>
import { _ } from "svelte-i18n";
import AddStatsClientModal from "./AddStatsClientModal.svelte";
import CopyScanStationTokenModal from "./CopyStatsClientTokenModal.svelte";
import scanstations_empty from "./statsclients_empty.svg";
let modal_open = false;
let copy_modal_open = false;
let new_client = {};
let current_clients = [];
</script>
<div class="text-center items-center justify-center">
<p class="mb-16 text-lg text-gray-500">
<img class="w-full h-44" src={scanstations_empty} alt="" />
<span class="font-bold">{$_('you-dont-have-any-scanclients-yet')}.</span><br />
<span>{$_('add-the-first-statsclient')}</span>
</p>
</div>
<AddStatsClientModal bind:modal_open bind:current_clients bind:new_client bind:copy_modal_open/>
<CopyScanStationTokenModal bind:copy_modal_open bind:new_client />

View File

@@ -0,0 +1,150 @@
<script>
import { _ } from "svelte-i18n";
import Toastify from "toastify-js";
import { StatsClientService } from "@odit/lfk-client-js";
const promise = StatsClientService.statsClientControllerGetAll().then(
(result) => {
current_clients = result;
}
);
import store from "../../store";
import StatsClientsEmptyState from "./StatsClientsEmptyState.svelte";
import ConfirmStatsClientDeletion from "./ConfirmStatsClientDeletion.svelte";
$: searchvalue = "";
$: active_deletes = [];
let delete_client = {};
let modal_open = false;
export let current_clients = [];
</script>
<ConfirmStatsClientDeletion
on:cancelDelete={(event) => {
modal_open = false;
active_deletes[event.detail.id] = false;
}}
bind:modal_open
bind:delete_client />
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:GET')}
{#await promise}
<div
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
role="alert">
<p class="font-bold">{$_('statsclients-are-being-loaded')}</p>
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
</div>
{:then}
{#if current_clients.length === 0}
<StatsClientsEmptyState />
{:else}
<input
type="search"
bind:value={searchvalue}
placeholder={$_('datatable.search')}
aria-label={$_('datatable.search')}
class="gridjs-input gridjs-search-input mb-4" />
<div
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">
<tr>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('description')}
</th>
<th
scope="col"
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
{$_('prefix')}
</th>
<th scope="col" class="relative px-6 py-3">
<span class="sr-only">{$_('action')}</span>
</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-200">
{#each current_clients as c}
{#if Object.values(c)
.toString()
.toLowerCase()
.includes(searchvalue)}
<tr data-rowid="station_{c.id}">
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{c.description}
</div>
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-nowrap">
<div class="flex items-center">
<div class="ml-4">
<div class="text-sm font-medium text-gray-900">
{c.prefix}
</div>
</div>
</div>
</td>
{#if active_deletes[c.id] === true}
<td
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
<button
on:click={() => {
active_deletes[c.id] = false;
}}
tabindex="0"
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
<button
on:click={() => {
StatsClientService.statsClientControllerRemove(c.id, false)
.then((resp) => {
current_clients = current_clients.filter((obj) => obj.id !== c.id);
Toastify({
text: $_('statsclient-deleted'),
duration: 500,
backgroundColor:
'linear-gradient(to right, #00b09b, #96c93d)',
}).showToast();
})
.catch((err) => {
modal_open = true;
delete_client = c;
});
}}
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="/statsclients/{c.id}"
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
{#if store.state.jwtinfo.userdetails.permissions.includes('STATSCLIENT:DELETE')}
<button
on:click={() => {
active_deletes[c.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>
{/await}
{/if}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@@ -43,7 +43,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: "Team is being added...", text: $_('team-is-being-added'),
duration: -1, duration: -1,
}).showToast(); }).showToast();
RunnerTeamService.runnerTeamControllerPost({ RunnerTeamService.runnerTeamControllerPost({
@@ -55,7 +55,7 @@
modal_open = false; modal_open = false;
// //
Toastify({ Toastify({
text: "Team added", text: $_('team-added'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -16,7 +16,7 @@
RunnerTeamService.runnerTeamControllerRemove(delete_team.id, true) RunnerTeamService.runnerTeamControllerRemove(delete_team.id, true)
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Team deleted", text: $_('team-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();

View File

@@ -14,6 +14,7 @@
import Teams from "./Teams.svelte"; import Teams from "./Teams.svelte";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
let [teamdata, original, delete_team, orgs, contacts, modal_open] = [ let [teamdata, original, delete_team, orgs, contacts, modal_open] = [
{}, {},
{}, {},
@@ -25,11 +26,12 @@
export let params; export let params;
export let import_modal_open = false; export let import_modal_open = false;
$: delete_triggered = false; $: delete_triggered = false;
$: save_enabled = !data_changed && teamdata.parentGroup != null; $: save_enabled = data_changed && teamdata.parentGroup != null;
$: data_loaded = false; $: data_loaded = false;
$: data_changed = JSON.stringify(teamdata) === JSON.stringify(original); $: data_changed = !(JSON.stringify(teamdata) === JSON.stringify(original));
$: sponsoring_contracts_show = true; $: sponsoring_contracts_show = true;
$: cards_show = true; $: cards_show = true;
$: certificates_show = true;
$: generate_teams = [original]; $: generate_teams = [original];
$: group = {}; $: group = {};
$: contact = {}; $: contact = {};
@@ -45,6 +47,8 @@
RunnerOrganizationService.runnerOrganizationControllerGetAll().then( RunnerOrganizationService.runnerOrganizationControllerGetAll().then(
(val) => { (val) => {
orgs = val.map((r) => { orgs = val.map((r) => {
delete r.contact;
r.teams = [];
return { label: r.name, value: r }; return { label: r.name, value: r };
}); });
group = orgs.find((g) => g.value.id == teamdata.parentGroup.id); group = orgs.find((g) => g.value.id == teamdata.parentGroup.id);
@@ -65,7 +69,7 @@
RunnerTeamService.runnerTeamControllerRemove(original.id, false) RunnerTeamService.runnerTeamControllerRemove(original.id, false)
.then((resp) => { .then((resp) => {
Toastify({ Toastify({
text: "Organization deleted", text: $_('team-deleted'),
duration: 500, duration: 500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -79,7 +83,7 @@
function submit() { function submit() {
if (data_loaded === true && save_enabled) { if (data_loaded === true && save_enabled) {
Toastify({ Toastify({
text: "updating team", text: $_('updating-team'),
duration: 2500, duration: 2500,
}).showToast(); }).showToast();
let postdata = teamdata; let postdata = teamdata;
@@ -90,7 +94,7 @@
Object.assign(original, teamdata); Object.assign(original, teamdata);
original = original; original = original;
Toastify({ Toastify({
text: "updated team", text: $_('updated-team'),
duration: 2500, duration: 2500,
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
}).showToast(); }).showToast();
@@ -122,6 +126,9 @@
<GenerateRunnerCards <GenerateRunnerCards
bind:cards_show bind:cards_show
bind:generate_teams /> bind:generate_teams />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_teams />
{#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')} {#if store.state.jwtinfo.userdetails.permissions.includes('RUNNER:IMPORT')}
<button <button
on:click={() => { on:click={() => {

View File

@@ -9,6 +9,7 @@
import { clickOutside } from "../base/outsideclick"; import { clickOutside } from "../base/outsideclick";
import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte"; import GenerateSponsoringContracts from "../pdf_generation/GenerateSponsoringContracts.svelte";
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte"; import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
import GenerateRunnerCertificates from "../pdf_generation/GenerateRunnerCertificates.svelte";
$: searchvalue = ""; $: searchvalue = "";
$: active_deletes = []; $: active_deletes = [];
$: sponsoring_contracts_show = current_teams.some( $: sponsoring_contracts_show = current_teams.some(
@@ -17,6 +18,9 @@
$: cards_show = current_teams.some( $: cards_show = current_teams.some(
(r) => r.is_selected === true (r) => r.is_selected === true
); );
$: certificates_show = current_teams.some(
(r) => r.is_selected === true
);
$: generate_teams = current_teams.filter((r) => r.is_selected === true); $: generate_teams = current_teams.filter((r) => r.is_selected === true);
export let current_teams = []; export let current_teams = [];
let modal_open = false; let modal_open = false;
@@ -61,6 +65,9 @@
<GenerateRunnerCards <GenerateRunnerCards
bind:cards_show bind:cards_show
bind:generate_teams /> bind:generate_teams />
<GenerateRunnerCertificates
bind:certificates_show
bind:generate_teams />
</div> </div>
<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">

View File

@@ -34,7 +34,7 @@
`[data-id="triggered_table_actions_${trackid}"]` `[data-id="triggered_table_actions_${trackid}"]`
).parentNode.parentNode.parentNode; ).parentNode.parentNode.parentNode;
Toastify({ Toastify({
text: "Track is being updated...", text: $_('track-is-being-updated'),
duration: 500, duration: 500,
}).showToast(); }).showToast();
TrackService.trackControllerPut(trackid, { TrackService.trackControllerPut(trackid, {
@@ -45,7 +45,7 @@
}) })
.then((r) => { .then((r) => {
Toastify({ Toastify({
text: "Track was updated!", text: $_('track-was-updated'),
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)", backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
duration: 1000, duration: 1000,
}).showToast(); }).showToast();

View File

@@ -27,7 +27,7 @@
}); });
function submit() { function submit() {
Toastify({ Toastify({
text: "updating permissions...", text: $_('updating-permissions'),
duration: 2500, duration: 2500,
}).showToast(); }).showToast();
to_delete.forEach((d) => { to_delete.forEach((d) => {

View File

@@ -1,428 +1,476 @@
{ {
"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-scan": "Scan erstellen", "add-or-update-a-payment": "Zahlung hinzufügen oder bearbeiten",
"add-the-first-scanstation": "Erstelle deine erste Scannerstation.", "add-scan": "Scan erstellen",
"add-user-group": "Neue Gruppe erstellen", "add-the-first-scanstation": "Erstelle deine erste Scannerstation.",
"add-your-first-card": "Erstelle deine erste Läuferkarte", "add-the-first-statsclient": "Erstelle deinen ersten Statsclient.",
"add-your-first-contact": "Erstelle den ersten Kontakt", "add-user-group": "Neue Gruppe erstellen",
"add-your-first-donor": "Erstelle die erste Sponsor:in", "add-your-first-card": "Erstelle deine erste Läuferkarte",
"add-your-first-group": "Erstelle die erste Gruppe", "add-your-first-contact": "Erstelle den ersten Kontakt",
"add-your-first-organization": "Erstelle die erste Organisation", "add-your-first-donor": "Erstelle die erste Sponsor:in",
"add-your-first-runner": "Erstelle die erste Läufer:in", "add-your-first-group": "Erstelle die erste Gruppe",
"add-your-first-team": "Erstelle das erste Team", "add-your-first-organization": "Erstelle die erste Organisation",
"add-your-first-track": "Erstelle den ersten Track (Laufstrecke).", "add-your-first-runner": "Erstelle die erste Läufer:in",
"add-your-first-user": "Erstelle die erste Benutzer:in", "add-your-first-team": "Erstelle das erste Team",
"add-your-fist-donation": "Erstelle dein erstes Sponsoring", "add-your-first-track": "Erstelle den ersten Track (Laufstrecke).",
"add-your-fist-scan": "Füge deinen ersten Scan hinzu", "add-your-first-user": "Erstelle die erste Benutzer:in",
"adding-card": "Karte wird erstellt", "add-your-fist-donation": "Erstelle dein erstes Sponsoring",
"adding-scan": "Scan wird hinzugefügt", "add-your-fist-scan": "Füge deinen ersten Scan hinzu",
"address": "Adresse", "adding-card": "Karte wird erstellt",
"address-is-required": "Du musst eine Adresse angeben", "adding-donation": "Sponsoring wird erstellt...",
"after-deletion-we-cant-restore-your-old-profile": "Nach der Löschung können auch die Admins dein Profil nicht wiederherstellen!", "adding-scan": "Scan wird hinzugefügt",
"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.", "address": "Adresse",
"all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht", "address-is-required": "Du musst eine Adresse angeben",
"all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!", "after-deletion-we-cant-restore-your-old-profile": "Nach der Löschung können auch die Admins dein Profil nicht wiederherstellen!",
"all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!", "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.",
"amount": "Anzahl", "all-associated-donations-will-get-deleted-as-well": "Alle Sponsorings dieser Sponsor:in werden ebenfalls gelöscht",
"amount-per-kilometer": "Betrag pro Kilometer", "all-associated-runners-will-be-deleted-too": "Alle zugehörigen Läufer:innen werden auch gelöscht!",
"apartment-suite-etc": "Apartment, Wohnung, etc.", "all-associated-teams-and-runners-will-be-deleted-too": "Alle assoziierten Teams und Läufer:innen werden auch gelöscht!",
"application_name": "Lauf für Kaya! - Admin", "already-paid": "Bereits bezahlt",
"applying-changes": "Änderungen anwenden", "amount": "Anzahl",
"attention": "Achtung!", "amount-per-kilometer": "Betrag pro Kilometer",
"author": "Autor:in", "apartment-suite-etc": "Apartment, Wohnung, etc.",
"bitte-bestaetige-diese-laeufer-fuer-den-import": "Bitte die Läufer:innen für den Import bestätigen.", "application_name": "Lauf für Kaya! - Admin",
"by": "von", "applying-changes": "Änderungen anwenden",
"cancel": "Abbrechen", "attention": "Achtung!",
"cancel-delete": "Löschen abbrechen", "author": "Autor:in",
"cancel-keep-donor": "Abbrechen, Sponsor:in behalten", "bitte-bestaetige-diese-laeufer-fuer-den-import": "Bitte die Läufer:innen für den Import bestätigen.",
"cancel-keep-my-profile": "Abbrechen, mein Profil behalten", "by": "von",
"cancel-keep-organization": "Abbrechen und Organisation bearbeiten", "cancel": "Abbrechen",
"cancel-keep-team": "Abbrechen, Team behalten", "cancel-delete": "Löschen abbrechen",
"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-donor": "Abbrechen, Sponsor:in behalten",
"card-added": "Karte wurde hinzugefügt", "cancel-keep-my-profile": "Abbrechen, mein Profil behalten",
"card-deleted": "Karte gelöscht", "cancel-keep-organization": "Abbrechen und Organisation bearbeiten",
"card-updated": "Karte aktualisiert", "cancel-keep-statsclient": "Abbrechen und Statsclient behalten",
"cards": "Läuferkarten", "cancel-keep-team": "Abbrechen, Team behalten",
"change-your-password-here": "Hier kannst du dein Passwort ändern", "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.",
"changing-your-password": "Passwort wird geändert", "card-added": "Karte wurde hinzugefügt",
"city": "Stadt", "card-deleted": "Karte gelöscht",
"click-to-copy-the-link-into-your-clipboard": "Klicke auf den Link, um ihn in deine Zwischenablage zu kopieren", "card-updated": "Karte aktualisiert",
"click-to-copy-token-to-clipboard": "Klicke auf den Token, um ihn in deine Zwischenablage zu kopieren", "cards": "Läuferkarten",
"close": "Schließen", "certificates": "Urkunden",
"code": "Code", "change-your-password-here": "Hier kannst du dein Passwort ändern",
"configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit", "changing-your-password": "Passwort wird geändert",
"confirm": "Bestätigen", "city": "Stadt",
"confirm-delete": "Löschung Bestätigen", "click-to-copy-the-link-into-your-clipboard": "Klicke auf den Link, um ihn in deine Zwischenablage zu kopieren",
"confirm-delete-donor-with-all-donations": "Bestätigen, Sponsor:in mit allen Sponsorings löschen", "click-to-copy-token-to-clipboard": "Klicke auf den Token, um ihn in deine Zwischenablage zu kopieren",
"confirm-delete-my-user-profile": "Bestätigung, mein Benutzerprofil löschen", "close": "Schließen",
"confirm-delete-organization-and-associated-teams-runners": "Bestätugung, lösche die Organisation und alle zugehörigen Teams und Läufer:innen.", "code": "Code",
"confirm-delete-team-and-associated-runners": "Bestätigung, lösche das Team mitsamt seinen Läufer:innen.", "configure-the-tracks-and-minimum-lap-times": "Bearbeite die Tracks und ihre minimale Rundenzeit",
"confirm-deletion": "Löschung Bestätigen", "confirm": "Bestätigen",
"confirm-the-new-password": "Neues Passwort bestätigen", "confirm-delete": "Löschung Bestätigen",
"contact": "Kontakt", "confirm-delete-donor-with-all-donations": "Bestätigen, Sponsor:in mit allen Sponsorings löschen",
"contact-deleted": "Kontakt gelöscht", "confirm-delete-my-user-profile": "Bestätigung, mein Benutzerprofil löschen",
"contact-information": "Kontaktinformation", "confirm-delete-organization-and-associated-teams-runners": "Bestätugung, lösche die Organisation und alle zugehörigen Teams und Läufer:innen.",
"contact-is-being-updated": "Kontakt wird aktualisiert ...", "confirm-delete-statsclient": "Bestätigung, Statsclient löschen",
"contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe", "confirm-delete-team-and-associated-runners": "Bestätigung, lösche das Team mitsamt seinen Läufer:innen.",
"contacts": "Kontakte", "confirm-deletion": "Löschung Bestätigen",
"contacts-are-being-loaded": "Kontakte werden geladen ...", "confirm-the-new-password": "Neues Passwort bestätigen",
"copied-link-to-clipboard": "Link wurde in die Zwischenablage kopiert", "contact": "Kontakt",
"copied-token-to-clipboard": "Token wurde in die Zwischenablage kopiert", "contact-added": "Kontakt wurde hinzugefügt",
"count_organizations": "Organisationen (Anzahl)", "contact-deleted": "Kontakt gelöscht",
"count_teams": "Teams (Anzahl)", "contact-information": "Kontaktinformation",
"create": "Erstellen", "contact-is-being-added": "Kontakt wird erstellt...",
"create-a-new": "Erstelle eine neue", "contact-is-being-updated": "Kontakt wird aktualisiert ...",
"create-a-new-card": "Neue Läuferkarte erstellen", "contact-is-not-a-member-in-any-group": "Kontakt gehört zu keiner Gruppe",
"create-a-new-contact": "Kontakt erstellen", "contacts": "Kontakte",
"create-a-new-distance-donation": "Erstelle ein neues Sponsoring", "contacts-are-being-loaded": "Kontakte werden geladen ...",
"create-a-new-donor": "Neue Sponsor:in erstellen", "copied-link-to-clipboard": "Link wurde in die Zwischenablage kopiert",
"create-a-new-fixed-donation": "Erstelle eine neue Festbetragsspende", "copied-token-to-clipboard": "Token wurde in die Zwischenablage kopiert",
"create-a-new-organization": "Neue Organisation anlegen", "count_organizations": "Organisationen (Anzahl)",
"create-a-new-runner": "Neue Läufer:in erstellen", "count_teams": "Teams (Anzahl)",
"create-a-new-scan-fixed-only": "Neuen Scan erstellen (nur mit Festdistanz)", "create": "Erstellen",
"create-a-new-scanstation": "Neue Station erstellen", "create-a-new": "Erstelle eine neue",
"create-a-new-team": "Erstelle ein neues Team", "create-a-new-card": "Neue Läuferkarte erstellen",
"create-a-new-track": "Neuen Track erstellen", "create-a-new-contact": "Kontakt erstellen",
"create-a-new-user": "Neue Benutzer:in anlegen", "create-a-new-distance-donation": "Erstelle ein neues Sponsoring",
"create-a-new-user-group": "Erstelle eine neue Gruppe", "create-a-new-donor": "Neue Sponsor:in erstellen",
"create-and-generate-pdf": "Erstellen und PDF herunterladen", "create-a-new-fixed-donation": "Erstelle eine neue Festbetragsspende",
"create-bulk-blanco-cards": "Blankokarten erstellen", "create-a-new-organization": "Neue Organisation anlegen",
"create-bulk-cards": "Blankokarten erstellen", "create-a-new-runner": "Neue Läufer:in erstellen",
"create-organization": "Organisation erstellen", "create-a-new-scan-fixed-only": "Neuen Scan erstellen (nur mit Festdistanz)",
"create-team": "Team erstellen", "create-a-new-scanstation": "Neue Station erstellen",
"create-track": "Track erstellen", "create-a-new-statsclient": "Neuen Statsclient erstellen",
"create-user": "Benutzer anlegen", "create-a-new-team": "Erstelle ein neues Team",
"create-without-pdf": "Ohne PDF erstellen", "create-a-new-track": "Neuen Track erstellen",
"created-blanco-cards": "Blankokarten wurden erstellt", "create-a-new-user": "Neue Benutzer:in anlegen",
"creating-blanco-cards": "Erstelle Blankokarten", "create-a-new-user-group": "Erstelle eine neue Gruppe",
"credits": "Credits", "create-and-generate-pdf": "Erstellen und PDF herunterladen",
"csv_import__class": "Klasse", "create-bulk-blanco-cards": "Blankokarten erstellen",
"csv_import__firstname": "Vorname", "create-bulk-cards": "Blankokarten erstellen",
"csv_import__lastname": "Nachname", "create-organization": "Organisation erstellen",
"csv_import__middlename": "Mittelname", "create-team": "Team erstellen",
"csv_import__team": "Team", "create-track": "Track erstellen",
"danger-zone": "Gefahrenzone", "create-user": "Benutzer anlegen",
"dashboard-greeting": "Hallo", "create-without-pdf": "Ohne PDF erstellen",
"dashboard-title": "Dashboard", "created-blanco-cards": "Blankokarten wurden erstellt",
"datatable": { "creating-blanco-cards": "Erstelle Blankokarten",
"search": "🔍 Suche ...", "credits": "Credits",
"an_error_happened_while_fetching_the_data": "Beim Abrufen der Daten ist ein Fehler aufgetreten", "csv_import__class": "Klasse",
"loading": "Wird geladen...", "csv_import__firstname": "Vorname",
"next": "Nächste", "csv_import__lastname": "Nachname",
"of": "von", "csv_import__middlename": "Mittelname",
"previous": "Vorherige", "csv_import__team": "Team",
"to": "bis", "danger-zone": "Gefahrenzone",
"showing": "Zeige", "dashboard-greeting": "Hallo",
"no_matching_records_found": "Keine passenden Einträge gefunden", "dashboard-title": "Dashboard",
"page": "Seite", "datatable": {
"records": "Einträge", "search": "🔍 Suche ...",
"sort_column_ascending": "Spalte aufsteigend sortieren", "an_error_happened_while_fetching_the_data": "Beim Abrufen der Daten ist ein Fehler aufgetreten",
"sort_column_descending": "Spalte absteigend sortieren" "loading": "Wird geladen...",
}, "next": "Nächste",
"delete": "Löschen", "of": "von",
"delete-contact": "Kontakt löschen", "previous": "Vorherige",
"delete-donation": "Sponsporing löschen", "to": "bis",
"delete-donor": "Sponsor:in löschen", "showing": "Zeige",
"delete-group": "Gruppe löschen", "no_matching_records_found": "Keine passenden Einträge gefunden",
"delete-organization": "Organisation löschen", "page": "Seite",
"delete-profile": "Profil löschen", "records": "Einträge",
"delete-runner": "Läufer:in löschen", "sort_column_ascending": "Spalte aufsteigend sortieren",
"delete-scan": "Scan löschen", "sort_column_descending": "Spalte absteigend sortieren"
"delete-station": "Station löschen", },
"delete-team": "Team Löschen", "delete": "Löschen",
"delete-user": "Benutzer:in löschen", "delete-contact": "Kontakt löschen",
"deleted-scan": "Scan wurde gelöscht", "delete-donation": "Sponsoring löschen",
"dependency_name": "Name", "delete-donor": "Sponsor:in löschen",
"description": "Beschreibung", "delete-group": "Gruppe löschen",
"description-optional": "Beschreibung (optional)", "delete-organization": "Organisation löschen",
"deselect-all": "Alle abwählen", "delete-profile": "Profil löschen",
"details": "Details", "delete-runner": "Läufer:in löschen",
"disabled": "deaktiviert", "delete-scan": "Scan löschen",
"distance": "Distanz", "delete-station": "Station löschen",
"distance-donation": "Sponsoring", "delete-statsclient": "Statsclient löschen",
"distance-in-km": "Distanz (in KM)", "delete-team": "Team Löschen",
"distance-track": "Distanz (+Track)", "delete-user": "Benutzer:in löschen",
"do-you-really-want-to-delete-your-profile": "Möchtest du dein Profil wirklich löschen?", "deleted-scan": "Scan wurde gelöscht",
"do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?", "dependency_name": "Name",
"do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?", "description": "Beschreibung",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?", "description-optional": "Beschreibung (optional)",
"documentation": "Dokumentation", "deselect-all": "Alle abwählen",
"donation-amount": "Sponsoringbetrag", "details": "Details",
"donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.", "disabled": "deaktiviert",
"donations": "Sponsorings", "distance": "Distanz",
"donor": "Sponsor:in", "distance-donation": "Sponsoring",
"donor-added": "Sponsor:in hinzugefügt", "distance-in-km": "Distanz (in KM)",
"donor-deleted": "Sponsor:in gelöscht", "distance-track": "Distanz (+Track)",
"donor-has-no-associated-donations": "Zur Sponsor:in gibt es noch keine Sponsorings", "do-you-really-want-to-delete-your-profile": "Möchtest du dein Profil wirklich löschen?",
"donor-is-being-added": "Sponsor:in wird hinzugefügt...", "do-you-want-to-delete-the-organization-delete_org-name": "Möchtest du die Organisation {orgname} löschen?",
"donor-is-being-updated": "Sponsor:in wird aktualisiert", "do-you-want-to-delete-the-team-delete_team-name": "Möchtest du das Team {teamname} löschen?",
"donors": "Sponsor:innen", "do-you-want-to-delete-this-donor-with-all-related-donations": "Möchtest du diese Sponsor:in mit all ihren Sponsorings löschen?",
"donors-are-being-loaded": "Sponsor:innen werden geladen", "documentation": "Dokumentation",
"dont-have-your-email-connected": "Deine E-Mail ist nicht verknüpft?", "donation-amount": "Sponsoringbetrag",
"dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌", "donation-amount-must-be-greater-that-0-00eur": "Der Sponsoringbetrag muss größer als 0.00€ sein.",
"e-mail-adress": "E-Mail-Adresse", "donation-deleted": "Sponsoring gelöscht",
"edit": "Bearbeiten", "donation-updated": "Sponsoring wurde aktualisiert",
"edit-a-card": "Läuferkarte bearbeiten", "donation_added": "Sponsoring hinzugefügt",
"edit-permissions": "Berechtigungen bearbeiten", "donations": "Sponsorings",
"email_address_or_username": "E-Mail-Adresse/ Benutzername", "donor": "Sponsor:in",
"enabled": "aktiviert", "donor-added": "Sponsor:in hinzugefügt",
"enabled_large": "Aktiviert", "donor-deleted": "Sponsor:in gelöscht",
"english": "Englisch", "donor-has-no-associated-donations": "Zur Sponsor:in gibt es noch keine Sponsorings",
"error-during-import": "Fehler beim Importieren", "donor-is-being-added": "Sponsor:in wird hinzugefügt...",
"error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage", "donor-is-being-updated": "Sponsor:in wird aktualisiert",
"error_on_login": "😢Fehler beim Login", "donors": "Sponsor:innen",
"erteilte": "Direkt erteilte", "donors-are-being-loaded": "Sponsor:innen werden geladen",
"everything-concerning-your-profile": "Alles zu deinem Profil", "dont-have-your-email-connected": "Deine E-Mail ist nicht verknüpft?",
"everything-is-more-fun-together": "Im Team macht's mehr Spaß 🏃‍♂️🏃‍♀️🏃‍♂️", "dont-panic-were-resetting-it": "Keine Panik, wir setzen es zurück ✌",
"faq": "FAQ", "e-mail-adress": "E-Mail-Adresse",
"filter-by-organization-team": "Filtern nach Organisation / Team", "edit": "Bearbeiten",
"first-name": "Vorname", "edit-a-card": "Läuferkarte bearbeiten",
"first-name-is-required": "Vorname muss angegeben werden", "edit-permissions": "Berechtigungen bearbeiten",
"first-scan-of-the-day": "Erster Scan des Tages", "email_address_or_username": "E-Mail-Adresse/ Benutzername",
"fixed-donation": "Festbetragsspende", "enabled": "aktiviert",
"forgot_password": "Passwort vergessen?", "enabled_large": "Aktiviert",
"geerbte": "geerbte", "english": "Englisch",
"general-stats": "Allgemeine Statistiken", "enter-payment": "Zahlung eingeben",
"general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten", "error-during-import": "Fehler beim Importieren",
"generate-runnercards": "Läuferkarten generieren", "error-whyile-copying-to-clipboard": "Fehler beim Kopieren in die Zwischenablage",
"generate-sponsoring-contract": "Sponsoringvertrag generieren", "error_on_login": "😢Fehler beim Login",
"generate-sponsoring-contracts": "Sponsoringverträge generieren", "erteilte": "Direkt erteilte",
"generating-pdf": "Pdf wird generiert...", "everything-concerning-your-profile": "Alles zu deinem Profil",
"generating-pdfs": "PDFs werden generiert...", "everything-is-more-fun-together": "Im Team macht's mehr Spaß 🏃‍♂️🏃‍♀️🏃‍♂️",
"generic-ui-logic-error": "Etwas ist in der Benutzeroberfläche schiefgelaufen.", "faq": "FAQ",
"german": "Deutsch", "filename_sponsoringquittungsliste": "SponsoringQuittungsListe",
"go-to-login": "Zum Login", "filter-by-organization-team": "Filtern nach Organisation / Team",
"goback": "Zur Startseite", "first-name": "Vorname",
"granted": "Gewährt", "first-name-is-required": "Vorname muss angegeben werden",
"group": "Gruppe", "first-scan-of-the-day": "Erster Scan des Tages",
"group-added": "Gruppe hinzugefügt", "fixed-donation": "Festbetragsspende",
"group-is-being-added": "Gruppe wird erstellt", "forgot_password": "Passwort vergessen?",
"group-name-is-required": "Der Gruppenname muss angegeben werden.", "geerbte": "geerbte",
"group-updated": "Gruppe aktualisiert", "general-stats": "Allgemeine Statistiken",
"groups": "Gruppen", "general_promise_error": "😢 Ein unbekannter Fehler ist aufgetreten",
"groups-are-being-loaded": "Gruppen werden geladen", "generate-runner-certificate": "Urkunde generieren",
"home": "Start", "generate-runner-certificates": "Urkunden generieren",
"icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:", "generate-runnercards": "Läuferkarten generieren",
"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.", "generate-sponsoring-contract": "Sponsoringvertrag generieren",
"import-finished": "Import abgeschlossen", "generate-sponsoring-contracts": "Sponsoringverträge generieren",
"import-runners": "Läufer:innen importieren", "generating-pdf": "PDF wird generiert...",
"import__target-organization": "Ziel Organisation", "generating-pdfs": "PDFs werden generiert...",
"imprint": "Impressum ", "generic-ui-logic-error": "Etwas ist in der Benutzeroberfläche schiefgelaufen.",
"imprint-loading": "Impressum lädt...", "german": "Deutsch",
"inactive": "Inaktiv", "go-to-login": "Zum Login",
"installed-version": "Installierte Version", "goback": "Zur Startseite",
"internal-error": "Interner Fehler", "granted": "Gewährt",
"invalid": "Ungültig", "group": "Gruppe",
"invalid-mail-reset": "Das ist keine gültige E-Mail", "group-added": "Gruppe hinzugefügt",
"just-enter-how-many-you-want-and-the-system-will-create-them": "Gebe einfach ein, wie viele Blankokarten das System erstellen soll.", "group-is-being-added": "Gruppe wird erstellt",
"laeufer-hinzufuegen": "Läufer:in hinzufügen", "group-name-is-required": "Der Gruppenname muss angegeben werden.",
"laeufer-importieren": "Läufer:innen importieren", "group-updated": "Gruppe aktualisiert",
"laptime": "Rundenzeit", "groups": "Gruppen",
"last-name": "Nachname", "groups-are-being-loaded": "Gruppen werden geladen",
"last-name-is-required": "Nachname muss angegeben werden", "home": "Start",
"lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.", "icon-image-credits": "Wir möchten uns außerdem für die verwendeten Icons und Bilder bedanken bei:",
"license": "Lizenz", "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.",
"licenses-are-being-loaded": "Lizenzen werden geladen...", "import-finished": "Import abgeschlossen",
"loading-cards": "Läuferkarten werden geladen", "import-runners": "Läufer:innen importieren",
"loading-contact-details": "Kontaktdaten werden geladen ...", "import__target-organization": "Ziel Organisation",
"loading-donation-details": "Lade Sponsoringdetails", "imprint": "Impressum ",
"loading-donor-details": "Lade Details", "imprint-loading": "Impressum lädt...",
"loading-group-detail": "Lade Gruppendetails...", "inactive": "Inaktiv",
"loading-profile-data": "Lade Profildaten", "installed-version": "Installierte Version",
"loading-runners": "Läufer:innen werden geladen...", "internal-error": "Interner Fehler",
"loading-station-details": "Lade Scanstation-Details ...", "invalid": "Ungültig",
"log_in": "Anmelden", "invalid-mail-reset": "Das ist keine gültige E-Mail",
"log_in_to_your_account": "Bitte melde dich an", "just-enter-how-many-you-want-and-the-system-will-create-them": "Gebe einfach ein, wie viele Blankokarten das System erstellen soll.",
"login_is_checked": "Login wird überprüft", "key": "Schlüssel",
"logout": "Abmelden", "laeufer-hinzufuegen": "Läufer:in hinzufügen",
"mail-validation-in-progress": "E-Mail Verifizierung läuft... ", "laeufer-importieren": "Läufer:innen importieren",
"manage-admin-users": "Nutzer verwalten", "laptime": "Rundenzeit",
"middle-name": "Mittelname", "last-name": "Nachname",
"minimum-lap-time-in-s": "Minimale Rundenzeit (in Sekunden)", "last-name-is-required": "Nachname muss angegeben werden",
"minimum-lap-time-must-be-a-positive-number-or-0": "Die minimale Rundenzeit muss eine positive Zahl oder 0 sein", "lfk-is-os": "Das \"Lauf für Kaya!\" Frontend ist (wie alle anderen Projekte für den \"LfK!\" auch) ein OpenSource Projekt.",
"must-be-at-least-10-characters-long": "Passwort muss mindestens 10 Zeichen lang sein!", "license": "Lizenz",
"must-contain-a-lowercase-letter": "Passwort muss einen Großbuchstaben enthalten!", "licenses-are-being-loaded": "Lizenzen werden geladen...",
"must-contain-a-number": "Passwort muss eine Zahl enthalten!", "loading-cards": "Läuferkarten werden geladen",
"must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!", "loading-contact-details": "Kontaktdaten werden geladen ...",
"name": "Name", "loading-donation-details": "Lade Sponsoringdetails",
"name-is-required": "Der Gruppenname muss angegeben werden", "loading-donor-details": "Lade Details",
"new-password": "Neues Passwort", "loading-group-detail": "Lade Gruppendetails...",
"no-contact-found": "Keine Kontakte gefunden", "loading-profile-data": "Lade Profildaten",
"no-contact-selected": "Kein Kontakt ausgewählt", "loading-runners": "Läufer:innen werden geladen...",
"no-contact-specified": "Kein Kontakt angegeben", "loading-station-details": "Lade Scanstation-Details ...",
"no-donors-found": "Keine Spender:innen gefunden", "log_in": "Anmelden",
"no-license-text-could-be-found": "Kein Lizenz-Text gefunden 😢", "log_in_to_your_account": "Bitte melde dich an",
"no-organization-or-team-found": "Keine Organisationen oder Teams gefunden", "login_is_checked": "Login wird überprüft",
"no-organization-specified": "Keine Organisation angegeben", "logout": "Abmelden",
"no-organizations-found": "Keine Organisationen gefunden", "mail-validation-in-progress": "E-Mail Verifizierung läuft... ",
"no-runners-found": "Keine Läufer:innen gefunden", "manage-admin-users": "Nutzer verwalten",
"no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.", "middle-name": "Mittelname",
"non-blanko": "Keine/Blankokarte", "minimum-lap-time-in-s": "Minimale Rundenzeit (in Sekunden)",
"organization": "Organisation", "minimum-lap-time-must-be-a-positive-number-or-0": "Die minimale Rundenzeit muss eine positive Zahl oder 0 sein",
"organization-added": "Organisation hinzugefügt", "must-be-at-least-10-characters-long": "Passwort muss mindestens 10 Zeichen lang sein!",
"organization-deleted": "Organisation gelöscht", "must-contain-a-lowercase-letter": "Passwort muss einen Großbuchstaben enthalten!",
"organization-detail-is-being-loaded": "Organisationsdetails werden geladen ...", "must-contain-a-number": "Passwort muss eine Zahl enthalten!",
"organization-is-being-added": "Organisation wird hinzugefügt ...", "must-contain-a-uppercase-letter": "Passwort muss einen Kleinbuchstaben enthalten!",
"organization-name-is-required": "Der Name muss angegeben werden", "name": "Name",
"organizations": "Organisationen", "name-is-required": "Der Gruppenname muss angegeben werden",
"organizations-are-being-loaded": "Organisationen werden geladen ...", "new-password": "Neues Passwort",
"orgs": "Organisationen", "no-contact-found": "Keine Kontakte gefunden",
"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!", "no-contact-selected": "Kein Kontakt ausgewählt",
"password": "Passwort", "no-contact-specified": "Kein Kontakt angegeben",
"password-changed": "Passwort wurde aktualisiert!", "no-donors-found": "Keine Spender:innen gefunden",
"password-is-required": "Passwort muss angegeben werden", "no-license-text-could-be-found": "Kein Lizenz-Text gefunden 😢",
"password-reset-failed": "Passwort zurücksetzen ist fehlgeschlagen!", "no-organization-or-team-found": "Keine Organisationen oder Teams gefunden",
"password-reset-in-progress": "Passwort wird zurückgesetzt...", "no-organization-specified": "Keine Organisation angegeben",
"password-reset-mail-sent": "Passwort-Reset Mail wurde an \"{usersEmail}\" geschickt.", "no-organizations-found": "Keine Organisationen gefunden",
"password-reset-successful": "Passwort erfolgreich zurückgesetzt!", "no-runners-found": "Keine Läufer:innen gefunden",
"passwords-dont-match": "Die Passwörter stimmen nicht überein!", "no-tracks-added-yet": "Es wurden noch keine Tracks erstellt.",
"pdf-generation-failed": "PDF Generierung fehlgeschlagen!", "non-blanko": "Keine/Blankokarte",
"pdf-successfully-generated": "PDF wurde erfolgreich generiert!", "open": "OFFEN",
"pdfs-successfully-generated": "Alle PDFs wurden generiert!", "organization": "Organisation",
"per-kilometer": "pro Kilometer", "organization-added": "Organisation hinzugefügt",
"permissions": "Berechtigungen", "organization-deleted": "Organisation gelöscht",
"permissions-updated": "Berechtigungen aktualisiert!", "organization-detail-is-being-loaded": "Organisationsdetails werden geladen ...",
"phone": "Telefon", "organization-is-being-added": "Organisation wird hinzugefügt ...",
"please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.", "organization-name-is-required": "Der Name muss angegeben werden",
"please-provide-a-password": "Bitte gebe ein Passwort an...", "organizations": "Organisationen",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen", "organizations-are-being-loaded": "Organisationen werden geladen ...",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.", "orgs": "Organisationen",
"please-provide-the-nessecary-information-to-create-a-new-scan": "Bitte gebe alle notwendigen Informationen an, um einen neuen Scan zu erstellen.", "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!",
"please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.", "paid": "BEZAHLT",
"please-provide-the-required-information-for-creating-a-new-user-group": "Bitte gebe alle für eine neue Gruppe notwendigen Informationen an.", "paid-amount": "Gezahlter Betrag",
"please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.", "password": "Passwort",
"please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.", "password-changed": "Passwort wurde aktualisiert!",
"please-provide-the-required-information-to-add-a-new-runner": "Bitte die benötigten Informationen angeben.", "password-is-required": "Passwort muss angegeben werden",
"please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.", "password-reset-failed": "Passwort zurücksetzen ist fehlgeschlagen!",
"please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.", "password-reset-in-progress": "Passwort wird zurückgesetzt...",
"please-provide-the-required-information-to-add-a-new-user": "Bitte gebe alle nötigen Informationen an, im die neue Benutzer:in zu erstellen.", "password-reset-mail-sent": "Passwort-Reset Mail wurde an \"{usersEmail}\" geschickt.",
"please-provide-the-required-information-to-create-a-new-scanstation": "Bitte gebe alle für eine Scannerstation notwendigen Informationen an", "password-reset-successful": "Passwort erfolgreich zurückgesetzt!",
"please-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...", "passwords-dont-match": "Die Passwörter stimmen nicht überein!",
"privacy": "Datenschutz", "payment-amount-must-be-greater-than-0-00eur": "Der Zahlungsbetrag muss größer als 0.00€ sein!",
"privacy-loading": "Datenschutzerklärung lädt...", "pdf-generation-failed": "PDF Generierung fehlgeschlagen!",
"profile": "Profil", "pdf-successfully-generated": "PDF wurde erfolgreich generiert!",
"profile-picture": "Profilbild", "pdfs-successfully-generated": "Alle PDFs wurden generiert!",
"profile-updated": "Profil wurde aktualisiert!", "per-kilometer": "pro Kilometer",
"read-license": "Lizenz-Text lesen", "permissions": "Berechtigungen",
"receipt-needed": "Spendenquittung benötigt", "permissions-updated": "Berechtigungen aktualisiert!",
"repo_link": "Link", "phone": "Telefon",
"request-a-new-reset-mail": "Neue Reset-Mail anfordern", "please-copy-the-token-and-store-it-somewhere-save": "Bitte kopiere dir den Token und bewahre ihn gut auf.",
"reset-my-password": "Passwort zurücksetzen", "please-provide-a-password": "Bitte gebe ein Passwort an...",
"reset-password": "Passwort zurücksetzen", "please-provide-the-nessecary-information-to-add-a-new-donor": "Bitte mach die Notwendigen Angaben, um eine neue Sponsor:in zu erstellen",
"runner": "Läufer:in", "please-provide-the-nessecary-information-to-create-a-new-donation": "Bitte gebe alle für das Sponsoring notwendigen Daten an.",
"runner-added": "Läufer:in hinzugefügt", "please-provide-the-nessecary-information-to-create-a-new-scan": "Bitte gebe alle notwendigen Informationen an, um einen neuen Scan zu erstellen.",
"runner-import": "Läufer:innen Import", "please-provide-the-required-csv-xlsx-file": "Bitte eine CSV oder XLSX Datei hochladen.",
"runner-is-being-added": "Läufer:in wird hinzugefügt...", "please-provide-the-required-information-for-creating-a-new-user-group": "Bitte gebe alle für eine neue Gruppe notwendigen Informationen an.",
"runner-updated": "Läufer:in aktualisiert!", "please-provide-the-required-information-to-add-a-new-contact": "Bitte gebe alle nötigen Informationen an, im den neuen Kontakt zu erstellen.",
"runnerimport_verify_runners_org": "Bitte die Läufer:innen für den Import in die Organisation \"{org_name}\" bestätigen", "please-provide-the-required-information-to-add-a-new-organization": "Bitte gebe alle nötigen Informationen an, im die neue Organisation zu erstellen.",
"runners": "Läufer", "please-provide-the-required-information-to-add-a-new-runner": "Bitte die benötigten Informationen angeben.",
"runners-are-being-imported": "Läufer:innen werden importiert ...", "please-provide-the-required-information-to-add-a-new-team": "Bitte gebe alle nötigen Informationen an, im das neue Team zu erstellen.",
"runners-are-being-loaded": "Läufer:innen werden geladen ...", "please-provide-the-required-information-to-add-a-new-track": "Bitte die benötigten Informationen angeben.",
"save": "Speichern", "please-provide-the-required-information-to-add-a-new-user": "Bitte gebe alle nötigen Informationen an, im die neue Benutzer:in zu erstellen.",
"save-changes": "Änderungen speichern", "please-provide-the-required-information-to-create-a-new-scanstation": "Bitte gebe alle für eine Scannerstation notwendigen Informationen an",
"scan-added": "Scan hinzugefügt", "please-provide-the-required-information-to-create-a-new-statsclient": "Bitte gebe alle für einen Statsclient notwendigen Informationen an",
"scan-is-being-updated": "Scan wird aktualisiert", "please-request-a-new-reset-mail": "Bitte eine neue Passwortreset-Mail anfordern...",
"scan-with-fixed-distance": "Scan mit Festdistanz", "please-wait-a-moment-your-login-is-still-being-processed": "Bitte warte einen Moment, deine Anmeldung wird verarbeitet",
"scans": "Scans", "prefix": "Prefix",
"scans-are-being-loaded": "Scans werden geladen", "privacy": "Datenschutz",
"scanstation": "Scanner Station", "privacy-loading": "Datenschutzerklärung lädt...",
"scanstation-added": "Station wurde erstellt", "profile": "Profil",
"scanstation-is-being-added": "Scannerstation wird angelegt...", "profile-deleted": "Profil gelöscht!",
"scanstations": "Scanner Stationen", "profile-picture": "Profilbild",
"scanstations-are-being-loaded": "Scannerstationen werden geladen...", "profile-updated": "Profil wurde aktualisiert!",
"search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)", "read-license": "Lizenz-Text lesen",
"search-for-an-organization-or-team-by-name-or-id": "Suche eine Organisation oder ein Team (via Name oder Id)", "receipt-needed": "Spendenquittung benötigt",
"search-for-donor-name-or-id": "Suche eine Spender:in (via Name oder Id)", "repo_link": "Link",
"search-for-permission": "Berechtigungen durchsuchen", "request-a-new-reset-mail": "Neue Reset-Mail anfordern",
"search-for-runner-by-name-or-id": "Suche eine Läufer:in (via Name oder Id)", "reset-my-password": "Passwort zurücksetzen",
"select-all": "Alle auswählen", "reset-password": "Passwort zurücksetzen",
"select-language": "Sprache auswählen", "runner": "Läufer:in",
"selfservice-registration": "Selfservice Registrierung", "runner-added": "Läufer:in hinzugefügt",
"send-a-mail-to-lfk-odit-services": "Sende eine Mail an lfk@odit.services", "runner-import": "Läufer:innen Import",
"set-the-user-active-inactive": "Den Benutzer auf (in)aktiv setzen", "runner-is-being-added": "Läufer:in wird hinzugefügt...",
"settings": "Einstellungen", "runner-updated": "Läufer:in aktualisiert!",
"settings-for-your-profile": "Die Einstellungen deines Accounts", "runnercards": "Laeuferkarten",
"something-about-the-group": "Infos zur Gruppe", "runnerimport_verify_runners_org": "Bitte die Läufer:innen für den Import in die Organisation \"{org_name}\" bestätigen",
"stats-are-being-loaded": "Die Statistiken werden geladen...", "runners": "Läufer",
"status": "Status", "runners-are-being-imported": "Läufer:innen werden importiert ...",
"stuff-that-could-harm-your-profile": "Einstellungen, die deinem Profil nachhaltig schaden können", "runners-are-being-loaded": "Läufer:innen werden geladen ...",
"successful-password-reset": "Passwort erfolgreich zurückgesetzt!", "save": "Speichern",
"team": "Team", "save-changes": "Änderungen speichern",
"team-detail-is-being-loaded": "Team wird geladen...", "scan-added": "Scan hinzugefügt",
"team-name": "Teamname", "scan-is-being-updated": "Scan wird aktualisiert",
"team-name-is-required": "Teamname ist erforderlich", "scan-with-fixed-distance": "Scan mit Festdistanz",
"teams": "Teams", "scans": "Scans",
"teams-are-being-loaded": "Teams werden geladen ...", "scans-are-being-loaded": "Scans werden geladen",
"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...", "scanstation": "Scanner Station",
"the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.", "scanstation-added": "Station wurde erstellt",
"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!", "scanstation-is-being-added": "Scannerstation wird angelegt...",
"there-are-no-cards-yet": "Es gibt noch keine Läuferkarten.", "scanstations": "Scanner Stationen",
"there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.", "scanstations-are-being-loaded": "Scannerstationen werden geladen...",
"there-are-no-donations-yet": "Es gibt noch keine Sponsorings", "search-for-an-organization-by-name-or-id": "Suche eine Organisation (via Name oder Id)",
"there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen", "search-for-an-organization-or-team-by-name-or-id": "Suche eine Organisation oder ein Team (via Name oder Id)",
"there-are-no-groups-yet": "Es gibt noch keine Gruppen", "search-for-donor-name-or-id": "Suche eine Spender:in (via Name oder Id)",
"there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.", "search-for-permission": "Berechtigungen durchsuchen",
"there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.", "search-for-runner-by-name-or-id": "Suche eine Läufer:in (via Name oder Id)",
"there-are-no-scans-yet": "Es gibt noch keine Scans", "select-all": "Alle auswählen",
"there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.", "select-language": "Sprache auswählen",
"there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.", "selfservice-registration": "Selfservice Registrierung",
"this-card-is": "Diese Karte ist", "send-a-mail-to-lfk-odit-services": "Sende eine Mail an lfk@odit.services",
"this-might-take-a-moment": "Das könnte einen kleinen Moment dauern", "set-the-user-active-inactive": "Den Benutzer auf (in)aktiv setzen",
"this-scanstation-is": "Diese Station ist", "settings": "Einstellungen",
"token": "Token", "settings-for-your-profile": "Die Einstellungen deines Accounts",
"total-distance": "gelaufene Strecke", "something-about-the-group": "Infos zur Gruppe",
"total-donation-amount": "Gesamtbetrag", "sponsoring-quittungs-liste_herunterladen": "Sponsoring-Quittungs-Liste herunterladen",
"total-donations": "Spendensumme", "sponsorings": "Sponsoringerklaerungen",
"total-scans": "gesamte Scans", "stats-are-being-loaded": "Die Statistiken werden geladen...",
"track": "Track", "statsclient-deleted": "Statsclient wurde gelöscht",
"track-added": "Track hinzugefügt", "statsclient-is-being-added": "Statsclient wird angelegt...",
"track-data-is-being-loaded": "Trackdaten werden geladen", "statsclients": "Statsclient (aka Beamershow)",
"track-is-being-added": "Track wird hinzugefügt...", "statsclients-are-being-loaded": "Statsclients werden geladen",
"track-length-in-m": "Tracklänge (in Metern)", "status": "Status",
"track-length-must-be-greater-than-0": "Die Länge muss größer als 0 (Meter) sein", "stuff-that-could-harm-your-profile": "Einstellungen, die deinem Profil nachhaltig schaden können",
"track-name": "Trackname", "successful-password-reset": "Passwort erfolgreich zurückgesetzt!",
"track-name-must-not-be-empty": "Der Name muss angegeben werden", "team": "Team",
"tracks": "Tracks", "team-added": "Team wurde hinzugefügt",
"update-password": "Passwort ändern", "team-deleted": "Team gelöscht",
"updated-contact": "Kontakt aktualisiert!", "team-detail-is-being-loaded": "Team wird geladen...",
"updated-donor": "Sponsor:in wurde aktualisiert", "team-is-being-added": "Team wird erstellt...",
"updated-organization": "Organisation wurde aktualisiert", "team-name": "Teamname",
"updated-scan": "Scan wurde aktualisiert", "team-name-is-required": "Teamname ist erforderlich",
"updateing-group": "Gruppe wird aktualisiert...", "teams": "Teams",
"updating-card": "Karte wird aktualisiert", "teams-are-being-loaded": "Teams werden geladen ...",
"updating-organization": "Organisation wird aktualisiert", "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...",
"updating-permissions": "Berechtigungen werden aktualisiert...", "the-scans-distance-must-be-greater-than-0m": "Die Distanz muss größer als 0m sein.",
"updating-runner": "Läufer:in wird aktualisiert.", "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!",
"updating-user": "Benutzer:in wird aktualisiert...", "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!",
"updating-your-profile": "Profil wird aktualisiert...", "there-are-no-cards-yet": "Es gibt noch keine Läuferkarten.",
"user-added": "Benutzer hinzugefügt", "there-are-no-contacts-added-yet": "Es wurden noch keine Kontakte hinzugefügt.",
"user-groups": "Benutzergruppen", "there-are-no-donations-yet": "Es gibt noch keine Sponsorings",
"user-is-being-added": "Benutzer wird hinzugefügt ...", "there-are-no-donors-yet": "Es gibt noch keine Sponsor:innen",
"user-updated": "Benutzer:in wurde aktualisiert", "there-are-no-groups-yet": "Es gibt noch keine Gruppen",
"username": "Benutzername", "there-are-no-organizations-added-yet": "Es wurden noch keine Organisationen hinzugefügt.",
"users": "Benutzer", "there-are-no-runners-added-yet": "Es wurden noch keine Läufer:innen hinzugefügt.",
"valid": "Gültig", "there-are-no-scans-yet": "Es gibt noch keine Scans",
"valid-city-is-required": "Du musst eine Stadt angeben", "there-are-no-teams-added-yet": "Es wurden noch keine Teams hinzugefügt.",
"valid-email-is-required": "Es wird eine valide E-Mail Adresse benötigt", "there-are-no-users-added-yet": "Es wurden noch keine Benutzer hinzugefügt.",
"valid-international-phone-number-is-required": "Du musst eine Telefonnummer im internationalen Format angeben...", "this-card-is": "Diese Karte ist",
"valid-zipcode-postal-code-is-required": "Du musst eine valide Postleitzahl angeben", "this-might-take-a-moment": "Das könnte einen kleinen Moment dauern",
"verfuegbare": "Verfügbar", "this-scanstation-is": "Diese Station ist",
"welcome_wavinghand": "Willkommen 👋", "token": "Token",
"yes-i-copied-the-token": "Ja, ich habe den Token kopiert", "total-distance": "gelaufene Strecke",
"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!", "total-donation-amount": "Gesamtbetrag",
"you-can-now-use-your-new-password-to-log-in-to-your-account": "Du kannst dich jetzt mit deinem neuen Passwort anmelden! 🎉", "total-donations": "Spendensumme",
"you-can-provide-a-runner-but-you-dont-have-to": "Du kannst eine Läufer:in angeben, musst aber nicht.", "total-paid-amount": "Gezahlter Gesamtbetrag",
"you-dont-have-any-scanstations-yet": "Es gibt noch keine Scannerstationen", "total-scans": "gesamte Scans",
"you-have-to-provide-an-organization": "Du musst eine Organisation angeben", "total_donation_amount_in_eur": "Gesamtbetrag in €",
"you-have-to-save-your-changes-to-generate-a-link": "Du musst deine Änderungen speichern, um einen Link zu generieren.", "track": "Track",
"you-must-create-at-least-one-card-or-cancel": "Du musst mindestens eine Blankokarte erstellen (oder abbrechen).", "track-added": "Track hinzugefügt",
"zip-postal-code": "Postleitzahl", "track-data-is-being-loaded": "Trackdaten werden geladen",
"generate-runner-certificates": "Urkunden generieren" "track-is-being-added": "Track wird hinzugefügt...",
"track-is-being-updated": "Track wird aktualisiert...",
"track-length-in-m": "Tracklänge (in Metern)",
"track-length-must-be-greater-than-0": "Die Länge muss größer als 0 (Meter) sein",
"track-name": "Trackname",
"track-name-must-not-be-empty": "Der Name muss angegeben werden",
"track-was-updated": "Track wurde aktualisiert",
"tracks": "Tracks",
"unpaid": "Offen",
"update-card": "Karte aktualisieren",
"update-password": "Passwort ändern",
"updated-contact": "Kontakt aktualisiert!",
"updated-donor": "Sponsor:in wurde aktualisiert",
"updated-organization": "Organisation wurde aktualisiert",
"updated-scan": "Scan wurde aktualisiert",
"updated-team": "Team wurde aktualisiert",
"updateing-group": "Gruppe wird aktualisiert...",
"updating-card": "Karte wird aktualisiert",
"updating-donation": "Sponsoring wird aktualisiert",
"updating-organization": "Organisation wird aktualisiert",
"updating-permissions": "Berechtigungen werden aktualisiert...",
"updating-runner": "Läufer:in wird aktualisiert.",
"updating-team": "Team wird aktualisiert",
"updating-user": "Benutzer:in wird aktualisiert...",
"updating-your-profile": "Profil wird aktualisiert...",
"user-added": "Benutzer hinzugefügt",
"user-groups": "Benutzergruppen",
"user-is-being-added": "Benutzer wird hinzugefügt ...",
"user-updated": "Benutzer:in wurde aktualisiert",
"username": "Benutzername",
"users": "Benutzer",
"valid": "Gültig",
"valid-city-is-required": "Du musst eine Stadt angeben",
"valid-email-is-required": "Es wird eine valide E-Mail Adresse benötigt",
"valid-international-phone-number-is-required": "Du musst eine Telefonnummer im internationalen Format angeben...",
"valid-zipcode-postal-code-is-required": "Du musst eine valide Postleitzahl angeben",
"verfuegbare": "Verfügbar",
"welcome_wavinghand": "Willkommen 👋",
"yes-i-copied-the-token": "Ja, ich habe den Token kopiert",
"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!",
"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",
"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,429 +1,476 @@
{ {
"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-scan": "Add scan", "add-or-update-a-payment": "Add or update a payment",
"add-the-first-scanstation": "Add your first scanstation.", "add-scan": "Add scan",
"add-user-group": "Add User Group", "add-the-first-scanstation": "Add your first scanstation.",
"add-your-first-card": "Add your first card", "add-the-first-statsclient": "Add your first statsclient.",
"add-your-first-contact": "Add your first contact", "add-user-group": "Add User Group",
"add-your-first-donor": "add your first donor", "add-your-first-card": "Add your first card",
"add-your-first-group": "Add your first group", "add-your-first-contact": "Add your first contact",
"add-your-first-organization": "Add your first organization", "add-your-first-donor": "add your first donor",
"add-your-first-runner": "Add your first runner", "add-your-first-group": "Add your first group",
"add-your-first-team": "Add your first team", "add-your-first-organization": "Add your first organization",
"add-your-first-track": "Add your first track.", "add-your-first-runner": "Add your first runner",
"add-your-first-user": "Add your first user", "add-your-first-team": "Add your first team",
"add-your-fist-donation": "Add your fist donation", "add-your-first-track": "Add your first track.",
"add-your-fist-scan": "Add your fist scan", "add-your-first-user": "Add your first user",
"adding-card": "Adding Card", "add-your-fist-donation": "Add your fist donation",
"adding-scan": "Adding Scan", "add-your-fist-scan": "Add your fist scan",
"address": "Address", "adding-card": "Adding Card",
"address-is-required": "Address is required", "adding-donation": "Adding donation...",
"after-deletion-we-cant-restore-your-old-profile": "After deletion we can't restore your old profile!", "adding-scan": "Adding Scan",
"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.", "address": "Address",
"all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well", "address-is-required": "Address is required",
"all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!", "after-deletion-we-cant-restore-your-old-profile": "After deletion we can't restore your old profile!",
"all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!", "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.",
"amount": "Amount", "all-associated-donations-will-get-deleted-as-well": "All associated donations will get deleted as well",
"amount-per-kilometer": "Amount per kilometer", "all-associated-runners-will-be-deleted-too": "All associated runners will be deleted too!",
"apartment-suite-etc": "Apartment, suite, etc.", "all-associated-teams-and-runners-will-be-deleted-too": "All associated teams and runners will be deleted too!",
"application_name": "Lauf für Kaya! - Admin", "already-paid": "Already paid",
"applying-changes": "Applying Changes", "amount": "Amount",
"attention": "Attention!", "amount-per-kilometer": "Amount per kilometer",
"author": "Author", "apartment-suite-etc": "Apartment, suite, etc.",
"bitte-bestaetige-diese-laeufer-fuer-den-import": "Please confirm these runners for import.", "application_name": "Lauf für Kaya! - Admin",
"by": "by", "applying-changes": "Applying Changes",
"cancel": "Cancel", "attention": "Attention!",
"cancel-delete": "Cancel Delete", "author": "Author",
"cancel-keep-donor": "Cancel, keep donor", "bitte-bestaetige-diese-laeufer-fuer-den-import": "Please confirm these runners for import.",
"cancel-keep-my-profile": "Cancel, keep my profile", "by": "by",
"cancel-keep-organization": "Cancel, keep organization", "cancel": "Cancel",
"cancel-keep-team": "Cancel, keep team", "cancel-delete": "Cancel Delete",
"cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity", "cancel-keep-donor": "Cancel, keep donor",
"card-added": "Card added", "cancel-keep-my-profile": "Cancel, keep my profile",
"card-deleted": "Card deleted", "cancel-keep-organization": "Cancel, keep organization",
"card-updated": "Card updated", "cancel-keep-statsclient": "Cancel and keep statsclient",
"cards": "Cards", "cancel-keep-team": "Cancel, keep team",
"change-your-password-here": "Change your password here", "cannot-reset-your-password-directly": "Bummer. We unfortunately cannot reset your password directly. Please send us a mail and confirm your identity",
"changing-your-password": "Changing your password", "card-added": "Card added",
"city": "City", "card-deleted": "Card deleted",
"click-to-copy-the-link-into-your-clipboard": "Click to copy the link into your clipboard", "card-updated": "Card updated",
"click-to-copy-token-to-clipboard": "Click to copy the token to your clipboard", "cards": "Cards",
"close": "Close", "certificates": "Certificates",
"code": "Code", "change-your-password-here": "Change your password here",
"configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times", "changing-your-password": "Changing your password",
"confirm": "Confirm", "city": "City",
"confirm-delete": "Confirm Delete", "click-to-copy-the-link-into-your-clipboard": "Click to copy the link into your clipboard",
"confirm-delete-donor-with-all-donations": "Confirm, delete donor with all donations", "click-to-copy-token-to-clipboard": "Click to copy the token to your clipboard",
"confirm-delete-my-user-profile": "Confirm, delete my user profile", "close": "Close",
"confirm-delete-organization-and-associated-teams-runners": "Confirm, delete organization and associated teams+runners.", "code": "Code",
"confirm-delete-team-and-associated-runners": "Confirm, delete team and associated runners.", "configure-the-tracks-and-minimum-lap-times": "configure the tracks & minimum lap times",
"confirm-deletion": "Confirm Deletion", "confirm": "Confirm",
"confirm-the-new-password": "Confirm the new password", "confirm-delete": "Confirm Delete",
"contact": "Contact", "confirm-delete-donor-with-all-donations": "Confirm, delete donor with all donations",
"contact-deleted": "Contact deleted", "confirm-delete-my-user-profile": "Confirm, delete my user profile",
"contact-information": "Contact Information", "confirm-delete-organization-and-associated-teams-runners": "Confirm, delete organization and associated teams+runners.",
"contact-is-being-updated": "Contact is being updated...", "confirm-delete-statsclient": "Confirm, delete statsclient",
"contact-is-not-a-member-in-any-group": "Contact is not a member in any group", "confirm-delete-team-and-associated-runners": "Confirm, delete team and associated runners.",
"contacts": "Contacts", "confirm-deletion": "Confirm Deletion",
"contacts-are-being-loaded": "contacts are being loaded...", "confirm-the-new-password": "Confirm the new password",
"copied-link-to-clipboard": "Copied link to clipboard", "contact": "Contact",
"copied-token-to-clipboard": "Copied token to clipboard", "contact-added": "Contact added",
"count_organizations": "# Organizations", "contact-deleted": "Contact deleted",
"count_teams": "# Teams", "contact-information": "Contact Information",
"create": "Create", "contact-is-being-added": "Contact is being added...",
"create-a-new": "Create a new", "contact-is-being-updated": "Contact is being updated...",
"create-a-new-card": "Create a new card", "contact-is-not-a-member-in-any-group": "Contact is not a member in any group",
"create-a-new-contact": "Create a new contact", "contacts": "Contacts",
"create-a-new-distance-donation": "Create a new distance donation", "contacts-are-being-loaded": "contacts are being loaded...",
"create-a-new-donor": "Create a new donor", "copied-link-to-clipboard": "Copied link to clipboard",
"create-a-new-fixed-donation": "Create a new fixed donation", "copied-token-to-clipboard": "Copied token to clipboard",
"create-a-new-organization": "Create a new Organization", "count_organizations": "# Organizations",
"create-a-new-runner": "Create a new Runner", "count_teams": "# Teams",
"create-a-new-scan-fixed-only": "Create a new scan (fixed only)", "create": "Create",
"create-a-new-scanstation": "Create a new station", "create-a-new": "Create a new",
"create-a-new-team": "Create a new team", "create-a-new-card": "Create a new card",
"create-a-new-track": "Create a new Track", "create-a-new-contact": "Create a new contact",
"create-a-new-user": "Create a new User", "create-a-new-distance-donation": "Create a new distance donation",
"create-a-new-user-group": "Create a new user group", "create-a-new-donor": "Create a new donor",
"create-and-generate-pdf": "Create and generate PDF", "create-a-new-fixed-donation": "Create a new fixed donation",
"create-bulk-blanco-cards": "Create bulk blanco cards", "create-a-new-organization": "Create a new Organization",
"create-bulk-cards": "Add blanco cards", "create-a-new-runner": "Create a new Runner",
"create-organization": "Create Organization", "create-a-new-scan-fixed-only": "Create a new scan (fixed only)",
"create-team": "Create Team", "create-a-new-scanstation": "Create a new station",
"create-track": "Create Track", "create-a-new-statsclient": "Create a new statsclient",
"create-user": "Create User", "create-a-new-team": "Create a new team",
"create-without-pdf": "Create without PDF", "create-a-new-track": "Create a new Track",
"created-blanco-cards": "Created blanco cards", "create-a-new-user": "Create a new User",
"creating-blanco-cards": "Creating blanco cards", "create-a-new-user-group": "Create a new user group",
"credits": "Credits", "create-and-generate-pdf": "Create and generate PDF",
"csv_import__class": "Class", "create-bulk-blanco-cards": "Create bulk blanco cards",
"csv_import__firstname": "Firstname", "create-bulk-cards": "Add blanco cards",
"csv_import__lastname": "Lastname", "create-organization": "Create Organization",
"csv_import__middlename": "Middlename", "create-team": "Create Team",
"csv_import__team": "Team", "create-track": "Create Track",
"danger-zone": "Danger zone", "create-user": "Create User",
"dashboard-greeting": "Hello", "create-without-pdf": "Create without PDF",
"dashboard-title": "Dashboard", "created-blanco-cards": "Created blanco cards",
"datatable": { "creating-blanco-cards": "Creating blanco cards",
"search": "🔍 Search...", "credits": "Credits",
"sort_column_ascending": "Sort column ascending", "csv_import__class": "Class",
"sort_column_descending": "Sort column descending", "csv_import__firstname": "Firstname",
"previous": "Previous", "csv_import__lastname": "Lastname",
"next": "Next", "csv_import__middlename": "Middlename",
"page": "Page", "csv_import__team": "Team",
"showing": "Showing", "danger-zone": "Danger zone",
"records": "Records", "dashboard-greeting": "Hello",
"of": "of", "dashboard-title": "Dashboard",
"to": "to", "datatable": {
"loading": "Loading...", "search": "🔍 Search...",
"no_matching_records_found": "No matching records found", "sort_column_ascending": "Sort column ascending",
"an_error_happened_while_fetching_the_data": "An error happened while fetching the data" "sort_column_descending": "Sort column descending",
}, "previous": "Previous",
"delete": "Delete", "next": "Next",
"delete-contact": "Delete Contact", "page": "Page",
"delete-donation": "Delete Donation", "showing": "Showing",
"delete-donor": "Delete donor", "records": "Records",
"delete-group": "Delete Group", "of": "of",
"delete-organization": "Delete Organization", "to": "to",
"delete-profile": "Delete Profile", "loading": "Loading...",
"delete-runner": "Delete Runner", "no_matching_records_found": "No matching records found",
"delete-scan": "Delete scan", "an_error_happened_while_fetching_the_data": "An error happened while fetching the data"
"delete-station": "Delete station", },
"delete-team": "Delete Team", "delete": "Delete",
"delete-user": "Delete User", "delete-contact": "Delete Contact",
"deleted-scan": "Deleted scan", "delete-donation": "Delete Donation",
"dependency_name": "Name", "delete-donor": "Delete donor",
"description": "description", "delete-group": "Delete Group",
"description-optional": "Description (optional)", "delete-organization": "Delete Organization",
"deselect-all": "deselect all", "delete-profile": "Delete Profile",
"details": "Details", "delete-runner": "Delete Runner",
"disabled": "disabled", "delete-scan": "Delete scan",
"distance": "Distance", "delete-station": "Delete station",
"distance-donation": "distance donation", "delete-statsclient": "Delete statsclient",
"distance-in-km": "Distance in km", "delete-team": "Delete Team",
"distance-track": "Distance (+Track)", "delete-user": "Delete User",
"do-you-really-want-to-delete-your-profile": "Do you really want to delete your profile?", "deleted-scan": "Deleted scan",
"do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?", "dependency_name": "Name",
"do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?", "description": "description",
"do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations", "description-optional": "Description (optional)",
"documentation": "Documentation", "deselect-all": "deselect all",
"donation-amount": "Donation amount", "details": "Details",
"donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€", "disabled": "disabled",
"donations": "Donations", "distance": "Distance",
"donor": "Donor", "distance-donation": "distance donation",
"donor-added": "Donor added", "distance-in-km": "Distance in km",
"donor-deleted": "donor deleted", "distance-track": "Distance (+Track)",
"donor-has-no-associated-donations": "Donor has no associated donations.", "do-you-really-want-to-delete-your-profile": "Do you really want to delete your profile?",
"donor-is-being-added": "Donor is being added...", "do-you-want-to-delete-the-organization-delete_org-name": "Do you want to delete the organization {orgname}?",
"donor-is-being-updated": "Donor is being updated", "do-you-want-to-delete-the-team-delete_team-name": "Do you want to delete the team {teamname}?",
"donors": "Donors", "do-you-want-to-delete-this-donor-with-all-related-donations": "Do you want to delete this donor with all related donations",
"donors-are-being-loaded": "donors are being loaded", "documentation": "Documentation",
"dont-have-your-email-connected": "Don't have your email connected?", "donation-amount": "Donation amount",
"dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌", "donation-amount-must-be-greater-that-0-00eur": "Donation amount must be greater that 0.00€",
"e-mail-adress": "E-Mail Adress", "donation-deleted": "Donation deleted",
"edit": "Edit", "donation-updated": "Donation updated",
"edit-a-card": "Edit a card", "donation_added": "Donation_added",
"edit-permissions": "edit permissions", "donations": "Donations",
"email_address_or_username": "Email / username", "donor": "Donor",
"enabled": "enabled", "donor-added": "Donor added",
"enabled_large": "Enabled", "donor-deleted": "donor deleted",
"english": "English", "donor-has-no-associated-donations": "Donor has no associated donations.",
"error-during-import": "Error during import", "donor-is-being-added": "Donor is being added...",
"error-whyile-copying-to-clipboard": "Error while copying to clipboard", "donor-is-being-updated": "Donor is being updated",
"error_on_login": "Error on login", "donors": "Donors",
"erteilte": "Directly granted", "donors-are-being-loaded": "donors are being loaded",
"everything-concerning-your-profile": "Everything concerning your profile", "dont-have-your-email-connected": "Don't have your email connected?",
"everything-is-more-fun-together": "everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️", "dont-panic-were-resetting-it": "Don't panic, we're resetting it ✌",
"faq": "FAQ", "e-mail-adress": "E-Mail Adress",
"filter-by-organization-team": "Filter by Organization/ Team", "edit": "Edit",
"first-name": "First name", "edit-a-card": "Edit a card",
"first-name-is-required": "First Name is required", "edit-permissions": "edit permissions",
"first-scan-of-the-day": "First scan of the day.", "email_address_or_username": "Email / username",
"fixed-donation": "fixed donation", "enabled": "enabled",
"forgot_password": "Forgot your password?", "enabled_large": "Enabled",
"geerbte": "inherited", "english": "English",
"general-stats": "General Stats", "enter-payment": "Enter payment",
"general_promise_error": "😢 Error", "error-during-import": "Error during import",
"generate-runnercards": "Generate Runnercards", "error-whyile-copying-to-clipboard": "Error while copying to clipboard",
"generate-sponsoring-contract": "generate sponsoring contract", "error_on_login": "Error on login",
"generate-sponsoring-contracts": "generate sponsoring contracts", "erteilte": "Directly granted",
"generating-pdf": "generating PDF...", "everything-concerning-your-profile": "Everything concerning your profile",
"generating-pdfs": "generating PDFs...", "everything-is-more-fun-together": "everything is more fun together 🏃‍♂️🏃‍♀️🏃‍♂️",
"generic-ui-logic-error": "Something went wrong in the UI logic", "faq": "FAQ",
"german": "German", "filename_sponsoringquittungsliste": "DonorReceiptList",
"go-to-login": "Go To Login", "filter-by-organization-team": "Filter by Organization/ Team",
"goback": "Go Home", "first-name": "First name",
"granted": "granted", "first-name-is-required": "First Name is required",
"group": "Group", "first-scan-of-the-day": "First scan of the day.",
"group-added": "Group added", "fixed-donation": "fixed donation",
"group-is-being-added": "Group is being added...", "forgot_password": "Forgot your password?",
"group-name-is-required": "Group name is required", "geerbte": "inherited",
"group-updated": "group updated", "general-stats": "General Stats",
"groups": "Groups", "general_promise_error": "😢 Error",
"groups-are-being-loaded": "Groups are being loaded", "generate-runner-certificate": "Generate runner certificate",
"home": "Home", "generate-runner-certificates": "Generate runner certificates",
"icon-image-credits": "We also want to thank these projects for illustrations and icons:", "generate-runnercards": "Generate Runnercards",
"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.", "generate-sponsoring-contract": "generate sponsoring contract",
"import-finished": "Import finished", "generate-sponsoring-contracts": "generate sponsoring contracts",
"import-runners": "Import runners", "generating-pdf": "generating PDF...",
"import__target-organization": "Target Organization", "generating-pdfs": "generating PDFs...",
"imprint": "Imprint", "generic-ui-logic-error": "Something went wrong in the UI logic",
"imprint-loading": "Imprint loading...", "german": "German",
"inactive": "Inactive", "go-to-login": "Go To Login",
"installed-version": "Installed version", "goback": "Go Home",
"internal-error": "Internal Error", "granted": "granted",
"invalid": "Invalid", "group": "Group",
"invalid-mail-reset": "the provided email is invalid", "group-added": "Group added",
"just-enter-how-many-you-want-and-the-system-will-create-them": "Just enter how many you want and the system will create them", "group-is-being-added": "Group is being added...",
"laeufer-hinzufuegen": "Add runner", "group-name-is-required": "Group name is required",
"laeufer-importieren": "Läufer importieren", "group-updated": "group updated",
"laptime": "Laptime", "groups": "Groups",
"last-name": "Last name", "groups-are-being-loaded": "Groups are being loaded",
"last-name-is-required": "Last Name is required", "home": "Home",
"lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.", "icon-image-credits": "We also want to thank these projects for illustrations and icons:",
"license": "License", "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.",
"licenses-are-being-loaded": "Licenses are being loaded...", "import-finished": "Import finished",
"loading-cards": "Loading cards", "import-runners": "Import runners",
"loading-contact-details": "Loading contact details...", "import__target-organization": "Target Organization",
"loading-donation-details": "Loading donation details", "imprint": "Imprint",
"loading-donor-details": "Loading donor details", "imprint-loading": "Imprint loading...",
"loading-group-detail": "Loading group detail...", "inactive": "Inactive",
"loading-profile-data": "Loading profile data", "installed-version": "Installed version",
"loading-runners": "loading runners...", "internal-error": "Internal Error",
"loading-station-details": "Loading station details", "invalid": "Invalid",
"log_in": "Log in", "invalid-mail-reset": "the provided email is invalid",
"log_in_to_your_account": "Log in to your account", "just-enter-how-many-you-want-and-the-system-will-create-them": "Just enter how many you want and the system will create them",
"login_is_checked": "Login is being checked...", "key": "Key",
"logout": "Logout", "laeufer-hinzufuegen": "Add runner",
"mail-validation-in-progress": "mail validation in progress...", "laeufer-importieren": "Läufer importieren",
"manage-admin-users": "manage admin users", "laptime": "Laptime",
"middle-name": "Middle name", "last-name": "Last name",
"minimum-lap-time-in-s": "minimum lap time in s", "last-name-is-required": "Last Name is required",
"minimum-lap-time-must-be-a-positive-number-or-0": "minimum lap time must be a positive number or 0", "lfk-is-os": "The \"Lauf für Kaya!\" Frontend is (like all other projects for the \"LfK!\" Also) an open source project.",
"must-be-at-least-10-characters-long": "Must be at least 10 characters long!", "license": "License",
"must-contain-a-lowercase-letter": "Must contain a lowercase letter!", "licenses-are-being-loaded": "Licenses are being loaded...",
"must-contain-a-number": "Must contain a number!", "loading-cards": "Loading cards",
"must-contain-a-uppercase-letter": "Must contain a uppercase letter!", "loading-contact-details": "Loading contact details...",
"name": "Name", "loading-donation-details": "Loading donation details",
"name-is-required": "Name is required", "loading-donor-details": "Loading donor details",
"new-password": "New password", "loading-group-detail": "Loading group detail...",
"no-contact-found": "No contacts found", "loading-profile-data": "Loading profile data",
"no-contact-selected": "No contact selected", "loading-runners": "loading runners...",
"no-contact-specified": "no contact specified", "loading-station-details": "Loading station details",
"no-donors-found": "No donors found", "log_in": "Log in",
"no-license-text-could-be-found": "No license text could be found 😢", "log_in_to_your_account": "Log in to your account",
"no-organization-or-team-found": "No organization or team found", "login_is_checked": "Login is being checked...",
"no-organization-specified": "no organization specified", "logout": "Logout",
"no-organizations-found": "No organizations found", "mail-validation-in-progress": "mail validation in progress...",
"no-runners-found": "No runners found", "manage-admin-users": "manage admin users",
"no-tracks-added-yet": "there are no tracks added yet.", "middle-name": "Middle name",
"non-blanko": "Non/Blanko", "minimum-lap-time-in-s": "minimum lap time in s",
"organization": "Organization", "minimum-lap-time-must-be-a-positive-number-or-0": "minimum lap time must be a positive number or 0",
"organization-added": "Organization added", "must-be-at-least-10-characters-long": "Must be at least 10 characters long!",
"organization-deleted": "Organization deleted", "must-contain-a-lowercase-letter": "Must contain a lowercase letter!",
"organization-detail-is-being-loaded": "organization detail is being loaded...", "must-contain-a-number": "Must contain a number!",
"organization-is-being-added": "Organization is being added...", "must-contain-a-uppercase-letter": "Must contain a uppercase letter!",
"organization-name-is-required": "Organization name is required", "name": "Name",
"organizations": "Organizations", "name-is-required": "Name is required",
"organizations-are-being-loaded": "organizations are being loaded...", "new-password": "New password",
"orgs": "Organizations", "no-contact-found": "No contacts found",
"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!", "no-contact-selected": "No contact selected",
"password": "Password", "no-contact-specified": "no contact specified",
"password-changed": "Password changed!", "no-donors-found": "No donors found",
"password-is-required": "Password is required", "no-license-text-could-be-found": "No license text could be found 😢",
"password-reset-failed": "Password reset failed!", "no-organization-or-team-found": "No organization or team found",
"password-reset-in-progress": "Password Reset in Progress...", "no-organization-specified": "no organization specified",
"password-reset-mail-sent": "Password reset mail was sent to \"{usersEmail}\".", "no-organizations-found": "No organizations found",
"password-reset-successful": "Password Reset successful!", "no-runners-found": "No runners found",
"passwords-dont-match": "Passwords don't match!", "no-tracks-added-yet": "there are no tracks added yet.",
"pdf-generation-failed": "PDF generation failed!", "non-blanko": "Non/Blanko",
"pdf-successfully-generated": "PDF successfully generated!", "open": "OPEN",
"pdfs-successfully-generated": "PDFs successfully generated!", "organization": "Organization",
"per-kilometer": "per Kilometer", "organization-added": "Organization added",
"permissions": "Permissions", "organization-deleted": "Organization deleted",
"permissions-updated": "Permissions updated!", "organization-detail-is-being-loaded": "organization detail is being loaded...",
"phone": "Phone", "organization-is-being-added": "Organization is being added...",
"please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.", "organization-name-is-required": "Organization name is required",
"please-provide-a-password": "Please provide a password...", "organizations": "Organizations",
"please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor", "organizations-are-being-loaded": "organizations are being loaded...",
"please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation", "orgs": "Organizations",
"please-provide-the-nessecary-information-to-create-a-new-scan": "Please provide the nessecary information to create a new scan.", "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!",
"please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file", "paid": "PAID",
"please-provide-the-required-information-for-creating-a-new-user-group": "Please provide the required information for creating a new user group.", "paid-amount": "Paid amount",
"please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.", "password": "Password",
"please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.", "password-changed": "Password changed!",
"please-provide-the-required-information-to-add-a-new-runner": "Please provide the required information to add a new runner.", "password-is-required": "Password is required",
"please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.", "password-reset-failed": "Password reset failed!",
"please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.", "password-reset-in-progress": "Password Reset in Progress...",
"please-provide-the-required-information-to-add-a-new-user": "Please provide the required information to add a new user.", "password-reset-mail-sent": "Password reset mail was sent to \"{usersEmail}\".",
"please-provide-the-required-information-to-create-a-new-scanstation": "Please provide the required information to create a new scanstation", "password-reset-successful": "Password Reset successful!",
"please-request-a-new-reset-mail": "Please request a new reset mail...", "passwords-dont-match": "Passwords don't match!",
"privacy": "Privacy", "payment-amount-must-be-greater-than-0-00eur": "Payment amount must be greater than 0.00€!",
"privacy-loading": "Privacy loading...", "pdf-generation-failed": "PDF generation failed!",
"profile": "Profile", "pdf-successfully-generated": "PDF successfully generated!",
"profile-picture": "Profile Picture", "pdfs-successfully-generated": "PDFs successfully generated!",
"profile-updated": "Profile updated!", "per-kilometer": "per Kilometer",
"read-license": "Read License", "permissions": "Permissions",
"receipt-needed": "Receipt needed", "permissions-updated": "Permissions updated!",
"repo_link": "Link", "phone": "Phone",
"request-a-new-reset-mail": "Request a new reset mail", "please-copy-the-token-and-store-it-somewhere-save": "Please copy the token and store it somewhere safe.",
"reset-my-password": "Reset my password", "please-provide-a-password": "Please provide a password...",
"reset-password": "Reset your password", "please-provide-the-nessecary-information-to-add-a-new-donor": "Please provide the nessecary information to add a new donor",
"runner": "Runner", "please-provide-the-nessecary-information-to-create-a-new-donation": "Please provide the nessecary information to create a new donation",
"runner-added": "Runner added", "please-provide-the-nessecary-information-to-create-a-new-scan": "Please provide the nessecary information to create a new scan.",
"runner-import": "Runner Import", "please-provide-the-required-csv-xlsx-file": "Please provide the required csv/ xlsx file",
"runner-is-being-added": "Runner is being added...", "please-provide-the-required-information-for-creating-a-new-user-group": "Please provide the required information for creating a new user group.",
"runner-updated": "Runner updated!", "please-provide-the-required-information-to-add-a-new-contact": "Please provide the required information to add a new contact.",
"runnerimport_verify_runners_org": "Please confirm these runners for import into the organization \"{org_name}\"", "please-provide-the-required-information-to-add-a-new-organization": "Please provide the required information to add a new organization.",
"runners": "Runners", "please-provide-the-required-information-to-add-a-new-runner": "Please provide the required information to add a new runner.",
"runners-are-being-imported": "Runners are being imported...", "please-provide-the-required-information-to-add-a-new-team": "Please provide the required information to add a new team.",
"runners-are-being-loaded": "runners are being loaded...", "please-provide-the-required-information-to-add-a-new-track": "Please provide the required information to add a new track.",
"save": "Save", "please-provide-the-required-information-to-add-a-new-user": "Please provide the required information to add a new user.",
"save-changes": "Save Changes", "please-provide-the-required-information-to-create-a-new-scanstation": "Please provide the required information to create a new scanstation",
"scan-added": "Scan added", "please-provide-the-required-information-to-create-a-new-statsclient": "Please provide the required information to create a new statsclient",
"scan-is-being-updated": "Scan is being updated", "please-request-a-new-reset-mail": "Please request a new reset mail...",
"scan-with-fixed-distance": "Scan with fixed distance", "please-wait-a-moment-your-login-is-still-being-processed": "Please wait a moment, your login is still being processed",
"scans": "Scans", "prefix": "Prefix",
"scans-are-being-loaded": "Scans are being loaded", "privacy": "Privacy",
"scanstation": "Scanstation", "privacy-loading": "Privacy loading...",
"scanstation-added": "Scanstation added", "profile": "Profile",
"scanstation-is-being-added": "Adding scanstation...", "profile-deleted": "Profile deleted!",
"scanstations": "Scanstations", "profile-picture": "Profile Picture",
"scanstations-are-being-loaded": "Loading scanstations...", "profile-updated": "Profile updated!",
"search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)", "read-license": "Read License",
"search-for-an-organization-or-team-by-name-or-id": "Search for an organization or team (by name or id)", "receipt-needed": "Receipt needed",
"search-for-donor-name-or-id": "Search for donor (by name or id)", "repo_link": "Link",
"search-for-permission": "Search for permission", "request-a-new-reset-mail": "Request a new reset mail",
"search-for-runner-by-name-or-id": "Search for runner (by name or id)", "reset-my-password": "Reset my password",
"select-all": "select all", "reset-password": "Reset your password",
"select-language": "Select language", "runner": "Runner",
"selfservice-registration": "Selfservice registration", "runner-added": "Runner added",
"send-a-mail-to-lfk-odit-services": "send a mail to lfk@odit.services", "runner-import": "Runner Import",
"set-the-user-active-inactive": "set the user active/ inactive", "runner-is-being-added": "Runner is being added...",
"settings": "Settings", "runner-updated": "Runner updated!",
"settings-for-your-profile": "Settings for your profile", "runnercards": "Runnercards",
"something-about-the-group": "Something about the group...", "runnerimport_verify_runners_org": "Please confirm these runners for import into the organization \"{org_name}\"",
"stats-are-being-loaded": "stats are being loaded...", "runners": "Runners",
"status": "Status", "runners-are-being-imported": "Runners are being imported...",
"stuff-that-could-harm-your-profile": "Stuff that could harm your profile", "runners-are-being-loaded": "runners are being loaded...",
"successful-password-reset": "Successful password reset!", "save": "Save",
"team": "Team", "save-changes": "Save Changes",
"team-detail-is-being-loaded": "team detail is being loaded...", "scan-added": "Scan added",
"team-name": "Team name", "scan-is-being-updated": "Scan is being updated",
"team-name-is-required": "team name is required", "scan-with-fixed-distance": "Scan with fixed distance",
"teams": "Teams", "scans": "Scans",
"teams-are-being-loaded": "teams are being loaded...", "scans-are-being-loaded": "Scans are being loaded",
"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...", "scanstation": "Scanstation",
"the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m", "scanstation-added": "Scanstation added",
"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!", "scanstation-is-being-added": "Adding scanstation...",
"there-are-no-cards-yet": "There are no cards yet.", "scanstations": "Scanstations",
"there-are-no-contacts-added-yet": "There are no contacts added yet.", "scanstations-are-being-loaded": "Loading scanstations...",
"there-are-no-donations-yet": "There are no donations yet", "search-for-an-organization-by-name-or-id": "Search for an organization (by name or id)",
"there-are-no-donors-yet": "There are no donors yet", "search-for-an-organization-or-team-by-name-or-id": "Search for an organization or team (by name or id)",
"there-are-no-groups-yet": "There are no groups yet", "search-for-donor-name-or-id": "Search for donor (by name or id)",
"there-are-no-organizations-added-yet": "There are no organizations added yet.", "search-for-permission": "Search for permission",
"there-are-no-runners-added-yet": "There are no runners added yet.", "search-for-runner-by-name-or-id": "Search for runner (by name or id)",
"there-are-no-scans-yet": "There are no scans yet", "select-all": "select all",
"there-are-no-teams-added-yet": "There are no teams added yet.", "select-language": "Select language",
"there-are-no-users-added-yet": "There are no users added yet.", "selfservice-registration": "Selfservice registration",
"this-card-is": "This card is", "send-a-mail-to-lfk-odit-services": "send a mail to lfk@odit.services",
"this-might-take-a-moment": "This might take a moment 👀", "set-the-user-active-inactive": "set the user active/ inactive",
"this-scanstation-is": "This scanstation is", "settings": "Settings",
"token": "Token", "settings-for-your-profile": "Settings for your profile",
"total-distance": "total distance", "something-about-the-group": "Something about the group...",
"total-donation-amount": "total donation amount", "sponsoring-quittungs-liste_herunterladen": "Download donor receipt list",
"total-donations": "total donations", "sponsorings": "Sponsorings",
"total-scans": "total scans", "stats-are-being-loaded": "stats are being loaded...",
"track": "Track", "statsclient-deleted": "Deleted statsclient",
"track-added": "Track added", "statsclient-is-being-added": "Statsclient is being added...",
"track-data-is-being-loaded": "Track data is being loaded", "statsclients": "Statsclients (aka Beamershow)",
"track-is-being-added": "Track is being added...", "statsclients-are-being-loaded": "Loading statsclients",
"track-length-in-m": "Track Length in m", "status": "Status",
"track-length-must-be-greater-than-0": "Track length must be greater than 0", "stuff-that-could-harm-your-profile": "Stuff that could harm your profile",
"track-name": "Track name", "successful-password-reset": "Successful password reset!",
"track-name-must-not-be-empty": "Track name must not be empty", "team": "Team",
"tracks": "Tracks", "team-added": "Team added",
"update-card": "Update Card", "team-deleted": "Team deleted",
"update-password": "Update password", "team-detail-is-being-loaded": "team detail is being loaded...",
"updated-contact": "Updated contact!", "team-is-being-added": "Team is being added...",
"updated-donor": "updated donor", "team-name": "Team name",
"updated-organization": "updated organization", "team-name-is-required": "team name is required",
"updated-scan": "updated scan", "teams": "Teams",
"updateing-group": "updateing group...", "teams-are-being-loaded": "teams are being loaded...",
"updating-card": "Updating card", "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...",
"updating-organization": "updating organization", "the-scans-distance-must-be-greater-than-0m": "The scan's distance must be greater than 0m",
"updating-permissions": "updating permissions...", "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!",
"updating-runner": "Updating runner...", "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!",
"updating-user": "updating user...", "there-are-no-cards-yet": "There are no cards yet.",
"updating-your-profile": "Updating your profile...", "there-are-no-contacts-added-yet": "There are no contacts added yet.",
"user-added": "User added", "there-are-no-donations-yet": "There are no donations yet",
"user-groups": "User Groups", "there-are-no-donors-yet": "There are no donors yet",
"user-is-being-added": "User is being added...", "there-are-no-groups-yet": "There are no groups yet",
"user-updated": "User updated", "there-are-no-organizations-added-yet": "There are no organizations added yet.",
"username": "Username", "there-are-no-runners-added-yet": "There are no runners added yet.",
"users": "Users", "there-are-no-scans-yet": "There are no scans yet",
"valid": "Valid", "there-are-no-teams-added-yet": "There are no teams added yet.",
"valid-city-is-required": "Valid city is required", "there-are-no-users-added-yet": "There are no users added yet.",
"valid-email-is-required": "valid email is required", "this-card-is": "This card is",
"valid-international-phone-number-is-required": "valid international phone number is required...", "this-might-take-a-moment": "This might take a moment 👀",
"valid-zipcode-postal-code-is-required": "Valid zipcode/ postal code is required", "this-scanstation-is": "This scanstation is",
"verfuegbare": "availdable", "token": "Token",
"welcome_wavinghand": "Welcome 👋", "total-distance": "total distance",
"yes-i-copied-the-token": "Yes, I copied the token", "total-donation-amount": "total donation amount",
"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!", "total-donations": "total donations",
"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! 🎉", "total-paid-amount": "Total paid amount",
"you-can-provide-a-runner-but-you-dont-have-to": "You can provide a runner, but you don't have to.", "total-scans": "total scans",
"you-dont-have-any-scanstations-yet": "You don't have any scanstations yet", "total_donation_amount_in_eur": "Total donation amount in €",
"you-have-to-provide-an-organization": "You have to provide an organization", "track": "Track",
"you-have-to-save-your-changes-to-generate-a-link": "You have to save your changes to generate a link.", "track-added": "Track added",
"you-must-create-at-least-one-card-or-cancel": "You must create at least one card (or cancel).", "track-data-is-being-loaded": "Track data is being loaded",
"zip-postal-code": "ZIP/ postal code", "track-is-being-added": "Track is being added...",
"generate-runner-certificates": "Generate runner certificates" "track-is-being-updated": "Track is being updated...",
"track-length-in-m": "Track Length in m",
"track-length-must-be-greater-than-0": "Track length must be greater than 0",
"track-name": "Track name",
"track-name-must-not-be-empty": "Track name must not be empty",
"track-was-updated": "Track was updated!",
"tracks": "Tracks",
"unpaid": "Unpaid",
"update-card": "Update Card",
"update-password": "Update password",
"updated-contact": "Updated contact!",
"updated-donor": "updated donor",
"updated-organization": "updated organization",
"updated-scan": "updated scan",
"updated-team": "Updated team",
"updateing-group": "updateing group...",
"updating-card": "Updating card",
"updating-donation": "Updating donation",
"updating-organization": "updating organization",
"updating-permissions": "updating permissions...",
"updating-runner": "Updating runner...",
"updating-team": "Updating team",
"updating-user": "updating user...",
"updating-your-profile": "Updating your profile...",
"user-added": "User added",
"user-groups": "User Groups",
"user-is-being-added": "User is being added...",
"user-updated": "User updated",
"username": "Username",
"users": "Users",
"valid": "Valid",
"valid-city-is-required": "Valid city is required",
"valid-email-is-required": "valid email is required",
"valid-international-phone-number-is-required": "valid international phone number is required...",
"valid-zipcode-postal-code-is-required": "Valid zipcode/ postal code is required",
"verfuegbare": "availdable",
"welcome_wavinghand": "Welcome 👋",
"yes-i-copied-the-token": "Yes, I copied the token",
"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!",
"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.",
"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"
} }

View File

@@ -1,4 +1,4 @@
import 'windi.css'; import './style.css';
import "toastify-js/src/toastify.css"; import "toastify-js/src/toastify.css";
import "gridjs/dist/theme/mermaid.css"; import "gridjs/dist/theme/mermaid.css";
import App from './App.svelte'; import App from './App.svelte';

3
src/style.css Normal file
View File

@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,4 +1,6 @@
module.exports = { module.exports = {
mode: 'jit',
purge: [ './src/**/*.svelte' ],
theme: { theme: {
extend: { extend: {
colors: { colors: {

View File

@@ -1,5 +1,4 @@
import svelte from '@sveltejs/vite-plugin-svelte'; import svelte from '@sveltejs/vite-plugin-svelte';
import windiCSS from 'vite-plugin-windicss';
import { minify } from 'html-minifier'; import { minify } from 'html-minifier';
import { defineConfig } from 'vite'; import { defineConfig } from 'vite';
// //
@@ -24,17 +23,6 @@ export default defineConfig(({ command, mode }) => {
minify: isProduction minify: isProduction
}, },
plugins: [ plugins: [
windiCSS({
//@ts-ignore
verbose: true,
silent: false,
debug: true,
config: 'tailwind.config.js', // tailwind config file path (optional)
compile: false, // false: interpretation mode; true: compilation mode
prefix: 'windi-', // set compilation mode style prefix
globalPreflight: true, // set preflight style is global or scoped
globalUtility: true // set utility style is global or scoped
}),
svelte({ svelte({
//@ts-ignore //@ts-ignore
hot: !isProduction, hot: !isProduction,